Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
70 #include <algorithm>
71 #include <fstream>
72 #include <iostream>
73 #include <iterator>
74 #include <vector>
75 #include <stdexcept>
76 #include <numeric>
77 
78 namespace Tpetra {
108  namespace MatrixMarket {
164  template<class SparseMatrixType>
165  class Reader {
166  public:
168  typedef SparseMatrixType sparse_matrix_type;
169  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
170 
173  typedef typename SparseMatrixType::scalar_type scalar_type;
176  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
184  typedef typename SparseMatrixType::global_ordinal_type
187  typedef typename SparseMatrixType::node_type node_type;
188 
193 
195  typedef MultiVector<scalar_type,
199 
201  typedef Vector<scalar_type,
205 
206  typedef Teuchos::Comm<int> comm_type;
208 
209 
210  private:
216  typedef Teuchos::ArrayRCP<int>::size_type size_type;
217 
228  static Teuchos::RCP<const map_type>
229  makeRangeMap (const Teuchos::RCP<const comm_type>& pComm,
230  const global_ordinal_type numRows)
231  {
232  // Return a conventional, uniformly partitioned, contiguous map.
233  return rcp (new map_type (static_cast<global_size_t> (numRows),
234  static_cast<global_ordinal_type> (0),
235  pComm, GloballyDistributed));
236  }
237 
265  static Teuchos::RCP<const map_type>
266  makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
267  const Teuchos::RCP<const comm_type>& pComm,
268  const global_ordinal_type numRows)
269  {
270  // If the caller didn't provide a map, return a conventional,
271  // uniformly partitioned, contiguous map.
272  if (pRowMap.is_null ()) {
273  return rcp (new map_type (static_cast<global_size_t> (numRows),
274  static_cast<global_ordinal_type> (0),
275  pComm, GloballyDistributed));
276  }
277  else {
278  TEUCHOS_TEST_FOR_EXCEPTION
279  (! pRowMap->isDistributed () && pComm->getSize () > 1,
280  std::invalid_argument, "The specified row map is not distributed, "
281  "but the given communicator includes more than one process (in "
282  "fact, there are " << pComm->getSize () << " processes).");
283  TEUCHOS_TEST_FOR_EXCEPTION
284  (pRowMap->getComm () != pComm, std::invalid_argument,
285  "The specified row Map's communicator (pRowMap->getComm()) "
286  "differs from the given separately supplied communicator pComm.");
287  return pRowMap;
288  }
289  }
290 
305  static Teuchos::RCP<const map_type>
306  makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
307  const global_ordinal_type numRows,
308  const global_ordinal_type numCols)
309  {
310  // Abbreviations so that the map creation call isn't too long.
311  typedef local_ordinal_type LO;
312  typedef global_ordinal_type GO;
313  typedef node_type NT;
314 
315  if (numRows == numCols) {
316  return pRangeMap;
317  } else {
318  return createUniformContigMapWithNode<LO,GO,NT> (numCols,
319  pRangeMap->getComm ());
320  }
321  }
322 
395  static void
396  distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
397  Teuchos::ArrayRCP<size_t>& myRowPtr,
398  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
399  Teuchos::ArrayRCP<scalar_type>& myValues,
400  const Teuchos::RCP<const map_type>& pRowMap,
401  Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
402  Teuchos::ArrayRCP<size_t>& rowPtr,
403  Teuchos::ArrayRCP<global_ordinal_type>& colInd,
404  Teuchos::ArrayRCP<scalar_type>& values,
405  const bool debug=false)
406  {
407  using Teuchos::arcp;
408  using Teuchos::ArrayRCP;
409  using Teuchos::ArrayView;
410  using Teuchos::as;
411  using Teuchos::Comm;
412  using Teuchos::CommRequest;
413  using Teuchos::null;
414  using Teuchos::RCP;
415  using Teuchos::receive;
416  using Teuchos::send;
417  using std::cerr;
418  using std::endl;
419 
420  const bool extraDebug = false;
421  RCP<const comm_type> pComm = pRowMap->getComm ();
422  const int numProcs = pComm->getSize ();
423  const int myRank = pComm->getRank ();
424  const int rootRank = 0;
425 
426  // Type abbreviations to make the code more concise.
427  typedef global_ordinal_type GO;
428 
429  // List of the global indices of my rows. They may or may
430  // not be contiguous, and the row map need not be one-to-one.
431  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
432  const size_type myNumRows = myRows.size();
433  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
434  pRowMap->getNodeNumElements(),
435  std::logic_error,
436  "pRowMap->getNodeElementList().size() = "
437  << myNumRows
438  << " != pRowMap->getNodeNumElements() = "
439  << pRowMap->getNodeNumElements() << ". "
440  "Please report this bug to the Tpetra developers.");
441  TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
442  std::logic_error,
443  "On Proc 0: numEntriesPerRow.size() = "
444  << numEntriesPerRow.size()
445  << " != pRowMap->getNodeElementList().size() = "
446  << myNumRows << ". Please report this bug to the "
447  "Tpetra developers.");
448 
449  // Space for my proc's number of entries per row. Will be
450  // filled in below.
451  myNumEntriesPerRow = arcp<size_t> (myNumRows);
452 
453  if (myRank != rootRank) {
454  // Tell the root how many rows we have. If we're sending
455  // none, then we don't have anything else to send, nor does
456  // the root have to receive anything else.
457  send (*pComm, myNumRows, rootRank);
458  if (myNumRows != 0) {
459  // Now send my rows' global indices. Hopefully the cast
460  // to int doesn't overflow. This is unlikely, since it
461  // should fit in a LO, even though it is a GO.
462  send (*pComm, static_cast<int> (myNumRows),
463  myRows.getRawPtr(), rootRank);
464 
465  // I (this proc) don't care if my global row indices are
466  // contiguous, though the root proc does (since otherwise
467  // it needs to pack noncontiguous data into contiguous
468  // storage before sending). That's why we don't check
469  // for contiguousness here.
470 
471  // Ask the root process for my part of the array of the
472  // number of entries per row.
473  receive (*pComm, rootRank,
474  static_cast<int> (myNumRows),
475  myNumEntriesPerRow.getRawPtr());
476 
477  // Use the resulting array to figure out how many column
478  // indices and values I should ask from the root process.
479  const local_ordinal_type myNumEntries =
480  std::accumulate (myNumEntriesPerRow.begin(),
481  myNumEntriesPerRow.end(), 0);
482 
483  // Make space for my entries of the sparse matrix. Note
484  // that they don't have to be sorted by row index.
485  // Iterating through all my rows requires computing a
486  // running sum over myNumEntriesPerRow.
487  myColInd = arcp<GO> (myNumEntries);
488  myValues = arcp<scalar_type> (myNumEntries);
489  if (myNumEntries > 0) {
490  // Ask for that many column indices and values, if
491  // there are any.
492  receive (*pComm, rootRank,
493  static_cast<int> (myNumEntries),
494  myColInd.getRawPtr());
495  receive (*pComm, rootRank,
496  static_cast<int> (myNumEntries),
497  myValues.getRawPtr());
498  }
499  } // If I own at least one row
500  } // If I am not the root processor
501  else { // I _am_ the root processor
502  if (debug) {
503  cerr << "-- Proc 0: Copying my data from global arrays" << endl;
504  }
505  // Proc 0 still needs to (allocate, if not done already)
506  // and fill its part of the matrix (my*).
507  for (size_type k = 0; k < myNumRows; ++k) {
508  const GO myCurRow = myRows[k];
509  const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
510  myNumEntriesPerRow[k] = numEntriesInThisRow;
511  }
512  if (extraDebug && debug) {
513  cerr << "Proc " << pRowMap->getComm ()->getRank ()
514  << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
515  for (size_type k = 0; k < myNumRows; ++k) {
516  cerr << myNumEntriesPerRow[k];
517  if (k < myNumRows-1) {
518  cerr << " ";
519  }
520  }
521  cerr << "]" << endl;
522  }
523  // The total number of matrix entries that my proc owns.
524  const local_ordinal_type myNumEntries =
525  std::accumulate (myNumEntriesPerRow.begin(),
526  myNumEntriesPerRow.end(), 0);
527  if (debug) {
528  cerr << "-- Proc 0: I own " << myNumRows << " rows and "
529  << myNumEntries << " entries" << endl;
530  }
531  myColInd = arcp<GO> (myNumEntries);
532  myValues = arcp<scalar_type> (myNumEntries);
533 
534  // Copy Proc 0's part of the matrix into the my* arrays.
535  // It's important that myCurPos be updated _before_ k,
536  // otherwise myCurPos will get the wrong number of entries
537  // per row (it should be for the row in the just-completed
538  // iteration, not for the next iteration's row).
539  local_ordinal_type myCurPos = 0;
540  for (size_type k = 0; k < myNumRows;
541  myCurPos += myNumEntriesPerRow[k], ++k) {
542  const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
543  const GO myRow = myRows[k];
544  const size_t curPos = rowPtr[myRow];
545  // Only copy if there are entries to copy, in order not
546  // to construct empty ranges for the ArrayRCP views.
547  if (curNumEntries > 0) {
548  ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
549  ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
550  std::copy (colIndView.begin(), colIndView.end(),
551  myColIndView.begin());
552 
553  ArrayView<scalar_type> valuesView =
554  values (curPos, curNumEntries);
555  ArrayView<scalar_type> myValuesView =
556  myValues (myCurPos, curNumEntries);
557  std::copy (valuesView.begin(), valuesView.end(),
558  myValuesView.begin());
559  }
560  }
561 
562  // Proc 0 processes each other proc p in turn.
563  for (int p = 1; p < numProcs; ++p) {
564  if (debug) {
565  cerr << "-- Proc 0: Processing proc " << p << endl;
566  }
567 
568  size_type theirNumRows = 0;
569  // Ask Proc p how many rows it has. If it doesn't
570  // have any, we can move on to the next proc. This
571  // has to be a standard receive so that we can avoid
572  // the degenerate case of sending zero data.
573  receive (*pComm, p, &theirNumRows);
574  if (debug) {
575  cerr << "-- Proc 0: Proc " << p << " owns "
576  << theirNumRows << " rows" << endl;
577  }
578  if (theirNumRows != 0) {
579  // Ask Proc p which rows it owns. The resulting global
580  // row indices are not guaranteed to be contiguous or
581  // sorted. Global row indices are themselves indices
582  // into the numEntriesPerRow array.
583  ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
584  receive (*pComm, p, as<int> (theirNumRows),
585  theirRows.getRawPtr ());
586  // Extra test to make sure that the rows we received
587  // are all sensible. This is a good idea since we are
588  // going to use the global row indices we've received
589  // to index into the numEntriesPerRow array. Better to
590  // catch any bugs here and print a sensible error
591  // message, rather than segfault and print a cryptic
592  // error message.
593  {
594  const global_size_t numRows = pRowMap->getGlobalNumElements ();
595  const GO indexBase = pRowMap->getIndexBase ();
596  bool theirRowsValid = true;
597  for (size_type k = 0; k < theirNumRows; ++k) {
598  if (theirRows[k] < indexBase ||
599  as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
600  theirRowsValid = false;
601  }
602  }
603  if (! theirRowsValid) {
604  TEUCHOS_TEST_FOR_EXCEPTION(
605  ! theirRowsValid, std::logic_error,
606  "Proc " << p << " has at least one invalid row index. "
607  "Here are all of them: " <<
608  Teuchos::toString (theirRows ()) << ". Valid row index "
609  "range (zero-based): [0, " << (numRows - 1) << "].");
610  }
611  }
612 
613  // Perhaps we could save a little work if we check
614  // whether Proc p's row indices are contiguous. That
615  // would make lookups in the global data arrays
616  // faster. For now, we just implement the general
617  // case and don't prematurely optimize. (Remember
618  // that you're making Proc 0 read the whole file, so
619  // you've already lost scalability.)
620 
621  // Compute the number of entries in each of Proc p's
622  // rows. (Proc p will compute its row pointer array
623  // on its own, after it gets the data from Proc 0.)
624  ArrayRCP<size_t> theirNumEntriesPerRow;
625  theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
626  for (size_type k = 0; k < theirNumRows; ++k) {
627  theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
628  }
629 
630  // Tell Proc p the number of entries in each of its
631  // rows. Hopefully the cast to int doesn't overflow.
632  // This is unlikely, since it should fit in a LO,
633  // even though it is a GO.
634  send (*pComm, static_cast<int> (theirNumRows),
635  theirNumEntriesPerRow.getRawPtr(), p);
636 
637  // Figure out how many entries Proc p owns.
638  const local_ordinal_type theirNumEntries =
639  std::accumulate (theirNumEntriesPerRow.begin(),
640  theirNumEntriesPerRow.end(), 0);
641 
642  if (debug) {
643  cerr << "-- Proc 0: Proc " << p << " owns "
644  << theirNumEntries << " entries" << endl;
645  }
646 
647  // If there are no entries to send, then we're done
648  // with Proc p.
649  if (theirNumEntries == 0) {
650  continue;
651  }
652 
653  // Construct (views of) proc p's column indices and
654  // values. Later, we might like to optimize for the
655  // (common) contiguous case, for which we don't need to
656  // copy data into separate "their*" arrays (we can just
657  // use contiguous views of the global arrays).
658  ArrayRCP<GO> theirColInd (theirNumEntries);
659  ArrayRCP<scalar_type> theirValues (theirNumEntries);
660  // Copy Proc p's part of the matrix into the their*
661  // arrays. It's important that theirCurPos be updated
662  // _before_ k, otherwise theirCurPos will get the wrong
663  // number of entries per row (it should be for the row
664  // in the just-completed iteration, not for the next
665  // iteration's row).
666  local_ordinal_type theirCurPos = 0;
667  for (size_type k = 0; k < theirNumRows;
668  theirCurPos += theirNumEntriesPerRow[k], k++) {
669  const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
670  const GO theirRow = theirRows[k];
671  const local_ordinal_type curPos = rowPtr[theirRow];
672 
673  // Only copy if there are entries to copy, in order
674  // not to construct empty ranges for the ArrayRCP
675  // views.
676  if (curNumEntries > 0) {
677  ArrayView<GO> colIndView =
678  colInd (curPos, curNumEntries);
679  ArrayView<GO> theirColIndView =
680  theirColInd (theirCurPos, curNumEntries);
681  std::copy (colIndView.begin(), colIndView.end(),
682  theirColIndView.begin());
683 
684  ArrayView<scalar_type> valuesView =
685  values (curPos, curNumEntries);
686  ArrayView<scalar_type> theirValuesView =
687  theirValues (theirCurPos, curNumEntries);
688  std::copy (valuesView.begin(), valuesView.end(),
689  theirValuesView.begin());
690  }
691  }
692  // Send Proc p its column indices and values.
693  // Hopefully the cast to int doesn't overflow. This
694  // is unlikely, since it should fit in a LO, even
695  // though it is a GO.
696  send (*pComm, static_cast<int> (theirNumEntries),
697  theirColInd.getRawPtr(), p);
698  send (*pComm, static_cast<int> (theirNumEntries),
699  theirValues.getRawPtr(), p);
700 
701  if (debug) {
702  cerr << "-- Proc 0: Finished with proc " << p << endl;
703  }
704  } // If proc p owns at least one row
705  } // For each proc p not the root proc 0
706  } // If I'm (not) the root proc 0
707 
708  // Invalidate the input data to save space, since we don't
709  // need it anymore.
710  numEntriesPerRow = null;
711  rowPtr = null;
712  colInd = null;
713  values = null;
714 
715  if (debug && myRank == 0) {
716  cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
717  }
718 
719  // Allocate and fill in myRowPtr (the row pointer array for
720  // my rank's rows). We delay this until the end because we
721  // don't need it to compute anything else in distribute().
722  // Each proc can do this work for itself, since it only needs
723  // myNumEntriesPerRow to do so.
724  myRowPtr = arcp<size_t> (myNumRows+1);
725  myRowPtr[0] = 0;
726  for (size_type k = 1; k < myNumRows+1; ++k) {
727  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
728  }
729  if (extraDebug && debug) {
730  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
731  << ": myRowPtr[0.." << myNumRows << "] = [";
732  for (size_type k = 0; k < myNumRows+1; ++k) {
733  cerr << myRowPtr[k];
734  if (k < myNumRows) {
735  cerr << " ";
736  }
737  }
738  cerr << "]" << endl << endl;
739  }
740 
741  if (debug && myRank == 0) {
742  cerr << "-- Proc 0: Done with distribute" << endl;
743  }
744  }
745 
759  static Teuchos::RCP<sparse_matrix_type>
760  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
761  Teuchos::ArrayRCP<size_t>& myRowPtr,
762  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
763  Teuchos::ArrayRCP<scalar_type>& myValues,
764  const Teuchos::RCP<const map_type>& pRowMap,
765  const Teuchos::RCP<const map_type>& pRangeMap,
766  const Teuchos::RCP<const map_type>& pDomainMap,
767  const bool callFillComplete = true)
768  {
769  using Teuchos::ArrayView;
770  using Teuchos::null;
771  using Teuchos::RCP;
772  using Teuchos::rcp;
773  using std::cerr;
774  using std::endl;
775  // Typedef to make certain type declarations shorter.
776  typedef global_ordinal_type GO;
777 
778  // The row pointer array always has at least one entry, even
779  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
780  // and myValues would all be empty arrays in that degenerate
781  // case, but the row and domain maps would still be nonnull
782  // (though they would be trivial maps).
783  TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
784  "makeMatrix: myRowPtr array is null. "
785  "Please report this bug to the Tpetra developers.");
786  TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
787  "makeMatrix: domain map is null. "
788  "Please report this bug to the Tpetra developers.");
789  TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
790  "makeMatrix: range map is null. "
791  "Please report this bug to the Tpetra developers.");
792  TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
793  "makeMatrix: row map is null. "
794  "Please report this bug to the Tpetra developers.");
795 
796  // Construct the CrsMatrix, using the row map, with the
797  // constructor specifying the number of nonzeros for each row.
798  RCP<sparse_matrix_type> A =
799  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow (),
800  StaticProfile));
801 
802  // List of the global indices of my rows.
803  // They may or may not be contiguous.
804  ArrayView<const GO> myRows = pRowMap->getNodeElementList ();
805  const size_type myNumRows = myRows.size ();
806 
807  // Add this processor's matrix entries to the CrsMatrix.
808  const GO indexBase = pRowMap->getIndexBase ();
809  for (size_type i = 0; i < myNumRows; ++i) {
810  const size_type myCurPos = myRowPtr[i];
811  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
812  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
813  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
814 
815  // Modify the column indices in place to have the right index base.
816  for (size_type k = 0; k < curNumEntries; ++k) {
817  curColInd[k] += indexBase;
818  }
819  // Avoid constructing empty views of ArrayRCP objects.
820  if (curNumEntries > 0) {
821  A->insertGlobalValues (myRows[i], curColInd, curValues);
822  }
823  }
824  // We've entered in all our matrix entries, so we can delete
825  // the original data. This will save memory when we call
826  // fillComplete(), so that we never keep more than two copies
827  // of the matrix's data in memory at once.
828  myNumEntriesPerRow = null;
829  myRowPtr = null;
830  myColInd = null;
831  myValues = null;
832 
833  if (callFillComplete) {
834  A->fillComplete (pDomainMap, pRangeMap);
835  }
836  return A;
837  }
838 
844  static Teuchos::RCP<sparse_matrix_type>
845  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
846  Teuchos::ArrayRCP<size_t>& myRowPtr,
847  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
848  Teuchos::ArrayRCP<scalar_type>& myValues,
849  const Teuchos::RCP<const map_type>& pRowMap,
850  const Teuchos::RCP<const map_type>& pRangeMap,
851  const Teuchos::RCP<const map_type>& pDomainMap,
852  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
853  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
854  {
855  using Teuchos::ArrayView;
856  using Teuchos::null;
857  using Teuchos::RCP;
858  using Teuchos::rcp;
859  using std::cerr;
860  using std::endl;
861  // Typedef to make certain type declarations shorter.
862  typedef global_ordinal_type GO;
863 
864  // The row pointer array always has at least one entry, even
865  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
866  // and myValues would all be empty arrays in that degenerate
867  // case, but the row and domain maps would still be nonnull
868  // (though they would be trivial maps).
869  TEUCHOS_TEST_FOR_EXCEPTION(
870  myRowPtr.is_null(), std::logic_error,
871  "makeMatrix: myRowPtr array is null. "
872  "Please report this bug to the Tpetra developers.");
873  TEUCHOS_TEST_FOR_EXCEPTION(
874  pDomainMap.is_null(), std::logic_error,
875  "makeMatrix: domain map is null. "
876  "Please report this bug to the Tpetra developers.");
877  TEUCHOS_TEST_FOR_EXCEPTION(
878  pRangeMap.is_null(), std::logic_error,
879  "makeMatrix: range map is null. "
880  "Please report this bug to the Tpetra developers.");
881  TEUCHOS_TEST_FOR_EXCEPTION(
882  pRowMap.is_null(), std::logic_error,
883  "makeMatrix: row map is null. "
884  "Please report this bug to the Tpetra developers.");
885 
886  // Construct the CrsMatrix, using the row map, with the
887  // constructor specifying the number of nonzeros for each row.
888  RCP<sparse_matrix_type> A =
889  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
890  StaticProfile, constructorParams));
891 
892  // List of the global indices of my rows.
893  // They may or may not be contiguous.
894  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
895  const size_type myNumRows = myRows.size();
896 
897  // Add this processor's matrix entries to the CrsMatrix.
898  const GO indexBase = pRowMap->getIndexBase ();
899  for (size_type i = 0; i < myNumRows; ++i) {
900  const size_type myCurPos = myRowPtr[i];
901  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
902  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
903  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
904 
905  // Modify the column indices in place to have the right index base.
906  for (size_type k = 0; k < curNumEntries; ++k) {
907  curColInd[k] += indexBase;
908  }
909  if (curNumEntries > 0) {
910  A->insertGlobalValues (myRows[i], curColInd, curValues);
911  }
912  }
913  // We've entered in all our matrix entries, so we can delete
914  // the original data. This will save memory when we call
915  // fillComplete(), so that we never keep more than two copies
916  // of the matrix's data in memory at once.
917  myNumEntriesPerRow = null;
918  myRowPtr = null;
919  myColInd = null;
920  myValues = null;
921 
922  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
923  return A;
924  }
925 
930  static Teuchos::RCP<sparse_matrix_type>
931  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
932  Teuchos::ArrayRCP<size_t>& myRowPtr,
933  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
934  Teuchos::ArrayRCP<scalar_type>& myValues,
935  const Teuchos::RCP<const map_type>& rowMap,
936  Teuchos::RCP<const map_type>& colMap,
937  const Teuchos::RCP<const map_type>& domainMap,
938  const Teuchos::RCP<const map_type>& rangeMap,
939  const bool callFillComplete = true)
940  {
941  using Teuchos::ArrayView;
942  using Teuchos::as;
943  using Teuchos::null;
944  using Teuchos::RCP;
945  using Teuchos::rcp;
946  typedef global_ordinal_type GO;
947 
948  // Construct the CrsMatrix.
949 
950  RCP<sparse_matrix_type> A; // the matrix to return.
951  if (colMap.is_null ()) { // the user didn't provide a column Map
952  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow, StaticProfile));
953  } else { // the user provided a column Map
954  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow, StaticProfile));
955  }
956 
957  // List of the global indices of my rows.
958  // They may or may not be contiguous.
959  ArrayView<const GO> myRows = rowMap->getNodeElementList ();
960  const size_type myNumRows = myRows.size ();
961 
962  // Add this process' matrix entries to the CrsMatrix.
963  const GO indexBase = rowMap->getIndexBase ();
964  for (size_type i = 0; i < myNumRows; ++i) {
965  const size_type myCurPos = myRowPtr[i];
966  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
967  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
968  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
969 
970  // Modify the column indices in place to have the right index base.
971  for (size_type k = 0; k < curNumEntries; ++k) {
972  curColInd[k] += indexBase;
973  }
974  if (curNumEntries > 0) {
975  A->insertGlobalValues (myRows[i], curColInd, curValues);
976  }
977  }
978  // We've entered in all our matrix entries, so we can delete
979  // the original data. This will save memory when we call
980  // fillComplete(), so that we never keep more than two copies
981  // of the matrix's data in memory at once.
982  myNumEntriesPerRow = null;
983  myRowPtr = null;
984  myColInd = null;
985  myValues = null;
986 
987  if (callFillComplete) {
988  A->fillComplete (domainMap, rangeMap);
989  if (colMap.is_null ()) {
990  colMap = A->getColMap ();
991  }
992  }
993  return A;
994  }
995 
996  private:
997 
1014  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1015  readBanner (std::istream& in,
1016  size_t& lineNumber,
1017  const bool tolerant=false,
1018  const bool /* debug */=false,
1019  const bool isGraph=false)
1020  {
1021  using Teuchos::MatrixMarket::Banner;
1022  using Teuchos::RCP;
1023  using Teuchos::rcp;
1024  using std::cerr;
1025  using std::endl;
1026  typedef Teuchos::ScalarTraits<scalar_type> STS;
1027 
1028  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1029  std::string line; // If read from stream successful: the Banner line
1030 
1031  // Try to read a line from the input stream.
1032  const bool readFailed = ! getline(in, line);
1033  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1034  "Failed to get Matrix Market banner line from input.");
1035 
1036  // We read a line from the input stream.
1037  lineNumber++;
1038 
1039  // Assume that the line we found is the Banner line.
1040  try {
1041  pBanner = rcp (new Banner (line, tolerant));
1042  } catch (std::exception& e) {
1043  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1044  "Matrix Market banner line contains syntax error(s): "
1045  << e.what());
1046  }
1047  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1048  std::invalid_argument, "The Matrix Market file does not contain "
1049  "matrix data. Its Banner (first) line says that its object type is \""
1050  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1051 
1052  // Validate the data type of the matrix, with respect to the
1053  // Scalar type of the CrsMatrix entries.
1054  TEUCHOS_TEST_FOR_EXCEPTION(
1055  ! STS::isComplex && pBanner->dataType() == "complex",
1056  std::invalid_argument,
1057  "The Matrix Market file contains complex-valued data, but you are "
1058  "trying to read it into a matrix containing entries of the real-"
1059  "valued Scalar type \""
1060  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1061  TEUCHOS_TEST_FOR_EXCEPTION(
1062  !isGraph &&
1063  pBanner->dataType() != "real" &&
1064  pBanner->dataType() != "complex" &&
1065  pBanner->dataType() != "integer",
1066  std::invalid_argument,
1067  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1068  "Matrix Market file may not contain a \"pattern\" matrix. A "
1069  "pattern matrix is really just a graph with no weights. It "
1070  "should be stored in a CrsGraph, not a CrsMatrix.");
1071 
1072  TEUCHOS_TEST_FOR_EXCEPTION(
1073  isGraph &&
1074  pBanner->dataType() != "pattern",
1075  std::invalid_argument,
1076  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1077  "Matrix Market file must contain a \"pattern\" matrix.");
1078 
1079  return pBanner;
1080  }
1081 
1104  static Teuchos::Tuple<global_ordinal_type, 3>
1105  readCoordDims (std::istream& in,
1106  size_t& lineNumber,
1107  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1108  const Teuchos::RCP<const comm_type>& pComm,
1109  const bool tolerant = false,
1110  const bool /* debug */ = false)
1111  {
1112  using Teuchos::MatrixMarket::readCoordinateDimensions;
1113  using Teuchos::Tuple;
1114 
1115  // Packed coordinate matrix dimensions (numRows, numCols,
1116  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1117  // ranks.
1118  Tuple<global_ordinal_type, 3> dims;
1119 
1120  // Read in the coordinate matrix dimensions from the input
1121  // stream. "success" tells us whether reading in the
1122  // coordinate matrix dimensions succeeded ("Guilty unless
1123  // proven innocent").
1124  bool success = false;
1125  if (pComm->getRank() == 0) {
1126  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1127  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1128  "only accepts \"coordinate\" (sparse) matrix data.");
1129  // Unpacked coordinate matrix dimensions
1130  global_ordinal_type numRows, numCols, numNonzeros;
1131  // Only MPI Rank 0 reads from the input stream
1132  success = readCoordinateDimensions (in, numRows, numCols,
1133  numNonzeros, lineNumber,
1134  tolerant);
1135  // Pack up the data into a Tuple so we can send them with
1136  // one broadcast instead of three.
1137  dims[0] = numRows;
1138  dims[1] = numCols;
1139  dims[2] = numNonzeros;
1140  }
1141  // Only Rank 0 did the reading, so it decides success.
1142  //
1143  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1144  // to send bools. For now, we convert to/from int instead,
1145  // using the usual "true is 1, false is 0" encoding.
1146  {
1147  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1148  Teuchos::broadcast (*pComm, 0, &the_success);
1149  success = (the_success == 1);
1150  }
1151  if (success) {
1152  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1153  // to all the other MPI ranks.
1154  Teuchos::broadcast (*pComm, 0, dims);
1155  }
1156  else {
1157  // Perhaps in tolerant mode, we could set all the
1158  // dimensions to zero for now, and deduce correct
1159  // dimensions by reading all of the file's entries and
1160  // computing the max(row index) and max(column index).
1161  // However, for now we just error out in that case.
1162  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1163  "Error reading Matrix Market sparse matrix: failed to read "
1164  "coordinate matrix dimensions.");
1165  }
1166  return dims;
1167  }
1168 
1179  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1180 
1181  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1182 
1208  static Teuchos::RCP<adder_type>
1209  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1210  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1211  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1212  const bool tolerant=false,
1213  const bool debug=false)
1214  {
1215  if (pComm->getRank () == 0) {
1216  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1218  raw_adder_type;
1219  Teuchos::RCP<raw_adder_type> pRaw =
1220  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1221  tolerant, debug));
1222  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1223  }
1224  else {
1225  return Teuchos::null;
1226  }
1227  }
1228 
1254  static Teuchos::RCP<graph_adder_type>
1255  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1256  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1257  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1258  const bool tolerant=false,
1259  const bool debug=false)
1260  {
1261  if (pComm->getRank () == 0) {
1262  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1263  Teuchos::RCP<raw_adder_type> pRaw =
1264  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1265  tolerant, debug));
1266  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1267  }
1268  else {
1269  return Teuchos::null;
1270  }
1271  }
1272 
1274  static Teuchos::RCP<sparse_graph_type>
1275  readSparseGraphHelper (std::istream& in,
1276  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1277  const Teuchos::RCP<const map_type>& rowMap,
1278  Teuchos::RCP<const map_type>& colMap,
1279  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1280  const bool tolerant,
1281  const bool debug)
1282  {
1283  using Teuchos::MatrixMarket::Banner;
1284  using Teuchos::RCP;
1285  using Teuchos::ptr;
1286  using Teuchos::Tuple;
1287  using std::cerr;
1288  using std::endl;
1289 
1290  const int myRank = pComm->getRank ();
1291  const int rootRank = 0;
1292 
1293  // Current line number in the input stream. Various calls
1294  // will modify this depending on the number of lines that are
1295  // read from the input stream. Only Rank 0 modifies this.
1296  size_t lineNumber = 1;
1297 
1298  if (debug && myRank == rootRank) {
1299  cerr << "Matrix Market reader: readGraph:" << endl
1300  << "-- Reading banner line" << endl;
1301  }
1302 
1303  // The "Banner" tells you whether the input stream represents
1304  // a sparse matrix, the symmetry type of the matrix, and the
1305  // type of the data it contains.
1306  //
1307  // pBanner will only be nonnull on MPI Rank 0. It will be
1308  // null on all other MPI processes.
1309  RCP<const Banner> pBanner;
1310  {
1311  // We read and validate the Banner on Proc 0, but broadcast
1312  // the validation result to all processes.
1313  // Teuchos::broadcast doesn't currently work with bool, so
1314  // we use int (true -> 1, false -> 0).
1315  int bannerIsCorrect = 1;
1316  std::ostringstream errMsg;
1317 
1318  if (myRank == rootRank) {
1319  // Read the Banner line from the input stream.
1320  try {
1321  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1322  }
1323  catch (std::exception& e) {
1324  errMsg << "Attempt to read the Matrix Market file's Banner line "
1325  "threw an exception: " << e.what();
1326  bannerIsCorrect = 0;
1327  }
1328 
1329  if (bannerIsCorrect) {
1330  // Validate the Banner for the case of a sparse graph.
1331  // We validate on Proc 0, since it reads the Banner.
1332 
1333  // In intolerant mode, the matrix type must be "coordinate".
1334  if (! tolerant && pBanner->matrixType() != "coordinate") {
1335  bannerIsCorrect = 0;
1336  errMsg << "The Matrix Market input file must contain a "
1337  "\"coordinate\"-format sparse graph in order to create a "
1338  "Tpetra::CrsGraph object from it, but the file's matrix "
1339  "type is \"" << pBanner->matrixType() << "\" instead.";
1340  }
1341  // In tolerant mode, we allow the matrix type to be
1342  // anything other than "array" (which would mean that
1343  // the file contains a dense matrix).
1344  if (tolerant && pBanner->matrixType() == "array") {
1345  bannerIsCorrect = 0;
1346  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1347  "format sparse graph in order to create a Tpetra::CrsGraph "
1348  "object from it, but the file's matrix type is \"array\" "
1349  "instead. That probably means the file contains dense matrix "
1350  "data.";
1351  }
1352  }
1353  } // Proc 0: Done reading the Banner, hopefully successfully.
1354 
1355  // Broadcast from Proc 0 whether the Banner was read correctly.
1356  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1357 
1358  // If the Banner is invalid, all processes throw an
1359  // exception. Only Proc 0 gets the exception message, but
1360  // that's OK, since the main point is to "stop the world"
1361  // (rather than throw an exception on one process and leave
1362  // the others hanging).
1363  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1364  std::invalid_argument, errMsg.str ());
1365  } // Done reading the Banner line and broadcasting success.
1366  if (debug && myRank == rootRank) {
1367  cerr << "-- Reading dimensions line" << endl;
1368  }
1369 
1370  // Read the graph dimensions from the Matrix Market metadata.
1371  // dims = (numRows, numCols, numEntries). Proc 0 does the
1372  // reading, but it broadcasts the results to all MPI
1373  // processes. Thus, readCoordDims() is a collective
1374  // operation. It does a collective check for correctness too.
1375  Tuple<global_ordinal_type, 3> dims =
1376  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1377 
1378  if (debug && myRank == rootRank) {
1379  cerr << "-- Making Adder for collecting graph data" << endl;
1380  }
1381 
1382  // "Adder" object for collecting all the sparse graph entries
1383  // from the input stream. This is only nonnull on Proc 0.
1384  // The Adder internally converts the one-based indices (native
1385  // Matrix Market format) into zero-based indices.
1386  RCP<graph_adder_type> pAdder =
1387  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1388 
1389  if (debug && myRank == rootRank) {
1390  cerr << "-- Reading graph data" << endl;
1391  }
1392  //
1393  // Read the graph entries from the input stream on Proc 0.
1394  //
1395  {
1396  // We use readSuccess to broadcast the results of the read
1397  // (succeeded or not) to all MPI processes. Since
1398  // Teuchos::broadcast doesn't currently know how to send
1399  // bools, we convert to int (true -> 1, false -> 0).
1400  int readSuccess = 1;
1401  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1402  if (myRank == rootRank) {
1403  try {
1404  // Reader for "coordinate" format sparse graph data.
1405  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1406  global_ordinal_type> reader_type;
1407  reader_type reader (pAdder);
1408 
1409  // Read the sparse graph entries.
1410  std::pair<bool, std::vector<size_t> > results =
1411  reader.read (in, lineNumber, tolerant, debug);
1412  readSuccess = results.first ? 1 : 0;
1413  }
1414  catch (std::exception& e) {
1415  readSuccess = 0;
1416  errMsg << e.what();
1417  }
1418  }
1419  broadcast (*pComm, rootRank, ptr (&readSuccess));
1420 
1421  // It would be nice to add a "verbose" flag, so that in
1422  // tolerant mode, we could log any bad line number(s) on
1423  // Proc 0. For now, we just throw if the read fails to
1424  // succeed.
1425  //
1426  // Question: If we're in tolerant mode, and if the read did
1427  // not succeed, should we attempt to call fillComplete()?
1428  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1429  "Failed to read the Matrix Market sparse graph file: "
1430  << errMsg.str());
1431  } // Done reading the graph entries (stored on Proc 0 for now)
1432 
1433  if (debug && myRank == rootRank) {
1434  cerr << "-- Successfully read the Matrix Market data" << endl;
1435  }
1436 
1437  // In tolerant mode, we need to rebroadcast the graph
1438  // dimensions, since they may be different after reading the
1439  // actual graph data. We only need to broadcast the number
1440  // of rows and columns. Only Rank 0 needs to know the actual
1441  // global number of entries, since (a) we need to merge
1442  // duplicates on Rank 0 first anyway, and (b) when we
1443  // distribute the entries, each rank other than Rank 0 will
1444  // only need to know how many entries it owns, not the total
1445  // number of entries.
1446  if (tolerant) {
1447  if (debug && myRank == rootRank) {
1448  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1449  << endl
1450  << "----- Dimensions before: "
1451  << dims[0] << " x " << dims[1]
1452  << endl;
1453  }
1454  // Packed coordinate graph dimensions (numRows, numCols).
1455  Tuple<global_ordinal_type, 2> updatedDims;
1456  if (myRank == rootRank) {
1457  // If one or more bottom rows of the graph contain no
1458  // entries, then the Adder will report that the number
1459  // of rows is less than that specified in the
1460  // metadata. We allow this case, and favor the
1461  // metadata so that the zero row(s) will be included.
1462  updatedDims[0] =
1463  std::max (dims[0], pAdder->getAdder()->numRows());
1464  updatedDims[1] = pAdder->getAdder()->numCols();
1465  }
1466  broadcast (*pComm, rootRank, updatedDims);
1467  dims[0] = updatedDims[0];
1468  dims[1] = updatedDims[1];
1469  if (debug && myRank == rootRank) {
1470  cerr << "----- Dimensions after: " << dims[0] << " x "
1471  << dims[1] << endl;
1472  }
1473  }
1474  else {
1475  // In strict mode, we require that the graph's metadata and
1476  // its actual data agree, at least somewhat. In particular,
1477  // the number of rows must agree, since otherwise we cannot
1478  // distribute the graph correctly.
1479 
1480  // Teuchos::broadcast() doesn't know how to broadcast bools,
1481  // so we use an int with the standard 1 == true, 0 == false
1482  // encoding.
1483  int dimsMatch = 1;
1484  if (myRank == rootRank) {
1485  // If one or more bottom rows of the graph contain no
1486  // entries, then the Adder will report that the number of
1487  // rows is less than that specified in the metadata. We
1488  // allow this case, and favor the metadata, but do not
1489  // allow the Adder to think there are more rows in the
1490  // graph than the metadata says.
1491  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1492  dimsMatch = 0;
1493  }
1494  }
1495  broadcast (*pComm, 0, ptr (&dimsMatch));
1496  if (dimsMatch == 0) {
1497  // We're in an error state anyway, so we might as well
1498  // work a little harder to print an informative error
1499  // message.
1500  //
1501  // Broadcast the Adder's idea of the graph dimensions
1502  // from Proc 0 to all processes.
1503  Tuple<global_ordinal_type, 2> addersDims;
1504  if (myRank == rootRank) {
1505  addersDims[0] = pAdder->getAdder()->numRows();
1506  addersDims[1] = pAdder->getAdder()->numCols();
1507  }
1508  broadcast (*pComm, 0, addersDims);
1509  TEUCHOS_TEST_FOR_EXCEPTION(
1510  dimsMatch == 0, std::runtime_error,
1511  "The graph metadata says that the graph is " << dims[0] << " x "
1512  << dims[1] << ", but the actual data says that the graph is "
1513  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1514  "data includes more rows than reported in the metadata. This "
1515  "is not allowed when parsing in strict mode. Parse the graph in "
1516  "tolerant mode to ignore the metadata when it disagrees with the "
1517  "data.");
1518  }
1519  } // Matrix dimensions (# rows, # cols, # entries) agree.
1520 
1521  // Create a map describing a distribution where the root owns EVERYTHING
1522  RCP<map_type> proc0Map;
1523  global_ordinal_type indexBase;
1524  if(Teuchos::is_null(rowMap)) {
1525  indexBase = 0;
1526  }
1527  else {
1528  indexBase = rowMap->getIndexBase();
1529  }
1530  if(myRank == rootRank) {
1531  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1532  }
1533  else {
1534  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1535  }
1536 
1537  // Create the graph where the root owns EVERYTHING
1538  std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1539  if (myRank == rootRank) {
1540  const auto& entries = pAdder()->getAdder()->getEntries();
1541  // This will count duplicates, but it's better than dense.
1542  // An even better approach would use a classic algorithm,
1543  // likely in Saad's old textbook, for converting COO (entries)
1544  // to CSR (the local part of the sparse matrix data structure).
1545  for (const auto& entry : entries) {
1546  const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1547  ++numEntriesPerRow_map[gblRow];
1548  }
1549  }
1550 
1551  Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getNodeNumElements ());
1552  for (const auto& ent : numEntriesPerRow_map) {
1553  const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1554  numEntriesPerRow[lclRow] = ent.second;
1555  }
1556  // Free anything we don't need before allocating the graph.
1557  // Swapping with an empty data structure is the standard idiom
1558  // for freeing memory used by Standard Library containers.
1559  // (Just resizing to 0 doesn't promise to free memory.)
1560  {
1561  std::map<global_ordinal_type, size_t> empty_map;
1562  std::swap (numEntriesPerRow_map, empty_map);
1563  }
1564 
1565  RCP<sparse_graph_type> proc0Graph =
1566  rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1567  StaticProfile,constructorParams));
1568  if(myRank == rootRank) {
1569  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1570 
1571  // Get the entries
1572  const std::vector<element_type>& entries =
1573  pAdder->getAdder()->getEntries();
1574 
1575  // Insert them one at a time
1576  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1577  const element_type& curEntry = entries[curPos];
1578  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1579  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1580  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1581  proc0Graph->insertGlobalIndices(curRow,colView);
1582  }
1583  }
1584  proc0Graph->fillComplete();
1585 
1586  RCP<sparse_graph_type> distGraph;
1587  if(Teuchos::is_null(rowMap))
1588  {
1589  // Create a map describing the distribution we actually want
1590  RCP<map_type> distMap =
1591  rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1592 
1593  // Create the graph with that distribution too
1594  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,StaticProfile,constructorParams));
1595 
1596  // Create an importer/exporter/vandelay to redistribute the graph
1597  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1598  import_type importer (proc0Map, distMap);
1599 
1600  // Import the data
1601  distGraph->doImport(*proc0Graph,importer,INSERT);
1602  }
1603  else {
1604  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,StaticProfile,constructorParams));
1605 
1606  // Create an importer/exporter/vandelay to redistribute the graph
1607  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1608  import_type importer (proc0Map, rowMap);
1609 
1610  // Import the data
1611  distGraph->doImport(*proc0Graph,importer,INSERT);
1612  }
1613 
1614  return distGraph;
1615  }
1616 
1617  public:
1641  static Teuchos::RCP<sparse_graph_type>
1642  readSparseGraphFile (const std::string& filename,
1643  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1644  const bool callFillComplete=true,
1645  const bool tolerant=false,
1646  const bool debug=false)
1647  {
1648  using Teuchos::broadcast;
1649  using Teuchos::outArg;
1650 
1651  // Only open the file on Process 0. Test carefully to make
1652  // sure that the file opened successfully (and broadcast that
1653  // result to all processes to prevent a hang on exception
1654  // throw), since it's a common mistake to misspell a filename.
1655  std::ifstream in;
1656  int opened = 0;
1657  if (comm->getRank () == 0) {
1658  try {
1659  in.open (filename.c_str ());
1660  opened = 1;
1661  }
1662  catch (...) {
1663  opened = 0;
1664  }
1665  }
1666  broadcast<int, int> (*comm, 0, outArg (opened));
1667  TEUCHOS_TEST_FOR_EXCEPTION
1668  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1669  "Failed to open file \"" << filename << "\" on Process 0.");
1670  return readSparseGraph (in, comm,
1671  callFillComplete,
1672  tolerant, debug);
1673  // We can rely on the destructor of the input stream to close
1674  // the file on scope exit, even if readSparseGraph() throws an
1675  // exception.
1676  }
1677 
1678 
1707  static Teuchos::RCP<sparse_graph_type>
1708  readSparseGraphFile (const std::string& filename,
1709  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1710  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1711  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1712  const bool tolerant=false,
1713  const bool debug=false)
1714  {
1715  using Teuchos::broadcast;
1716  using Teuchos::outArg;
1717 
1718  // Only open the file on Process 0. Test carefully to make
1719  // sure that the file opened successfully (and broadcast that
1720  // result to all processes to prevent a hang on exception
1721  // throw), since it's a common mistake to misspell a filename.
1722  std::ifstream in;
1723  int opened = 0;
1724  if (pComm->getRank () == 0) {
1725  try {
1726  in.open (filename.c_str ());
1727  opened = 1;
1728  }
1729  catch (...) {
1730  opened = 0;
1731  }
1732  }
1733  broadcast<int, int> (*pComm, 0, outArg (opened));
1734  TEUCHOS_TEST_FOR_EXCEPTION
1735  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1736  "Failed to open file \"" << filename << "\" on Process 0.");
1737  if (pComm->getRank () == 0) { // only open the input file on Process 0
1738  in.open (filename.c_str ());
1739  }
1740  return readSparseGraph (in, pComm,
1741  constructorParams,
1742  fillCompleteParams, tolerant, debug);
1743  // We can rely on the destructor of the input stream to close
1744  // the file on scope exit, even if readSparseGraph() throws an
1745  // exception.
1746  }
1747 
1748 
1786  static Teuchos::RCP<sparse_graph_type>
1787  readSparseGraphFile (const std::string& filename,
1788  const Teuchos::RCP<const map_type>& rowMap,
1789  Teuchos::RCP<const map_type>& colMap,
1790  const Teuchos::RCP<const map_type>& domainMap,
1791  const Teuchos::RCP<const map_type>& rangeMap,
1792  const bool callFillComplete=true,
1793  const bool tolerant=false,
1794  const bool debug=false)
1795  {
1796  using Teuchos::broadcast;
1797  using Teuchos::Comm;
1798  using Teuchos::outArg;
1799  using Teuchos::RCP;
1800 
1801  TEUCHOS_TEST_FOR_EXCEPTION
1802  (rowMap.is_null (), std::invalid_argument,
1803  "Input rowMap must be nonnull.");
1804  RCP<const Comm<int> > comm = rowMap->getComm ();
1805  if (comm.is_null ()) {
1806  // If the input communicator is null on some process, then
1807  // that process does not participate in the collective.
1808  return Teuchos::null;
1809  }
1810 
1811  // Only open the file on Process 0. Test carefully to make
1812  // sure that the file opened successfully (and broadcast that
1813  // result to all processes to prevent a hang on exception
1814  // throw), since it's a common mistake to misspell a filename.
1815  std::ifstream in;
1816  int opened = 0;
1817  if (comm->getRank () == 0) {
1818  try {
1819  in.open (filename.c_str ());
1820  opened = 1;
1821  }
1822  catch (...) {
1823  opened = 0;
1824  }
1825  }
1826  broadcast<int, int> (*comm, 0, outArg (opened));
1827  TEUCHOS_TEST_FOR_EXCEPTION
1828  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1829  "Failed to open file \"" << filename << "\" on Process 0.");
1830  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1831  callFillComplete, tolerant, debug);
1832  }
1833 
1859  static Teuchos::RCP<sparse_graph_type>
1860  readSparseGraph (std::istream& in,
1861  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1862  const bool callFillComplete=true,
1863  const bool tolerant=false,
1864  const bool debug=false)
1865  {
1866  Teuchos::RCP<const map_type> fakeRowMap;
1867  Teuchos::RCP<const map_type> fakeColMap;
1868  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1869 
1870  Teuchos::RCP<sparse_graph_type> graph =
1871  readSparseGraphHelper (in, pComm,
1872  fakeRowMap, fakeColMap,
1873  fakeCtorParams, tolerant, debug);
1874  if (callFillComplete) {
1875  graph->fillComplete ();
1876  }
1877  return graph;
1878  }
1879 
1880 
1910  static Teuchos::RCP<sparse_graph_type>
1911  readSparseGraph (std::istream& in,
1912  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1913  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1914  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1915  const bool tolerant=false,
1916  const bool debug=false)
1917  {
1918  Teuchos::RCP<const map_type> fakeRowMap;
1919  Teuchos::RCP<const map_type> fakeColMap;
1920  Teuchos::RCP<sparse_graph_type> graph =
1921  readSparseGraphHelper (in, pComm,
1922  fakeRowMap, fakeColMap,
1923  constructorParams, tolerant, debug);
1924  graph->fillComplete (fillCompleteParams);
1925  return graph;
1926  }
1927 
1928 
1969  static Teuchos::RCP<sparse_graph_type>
1970  readSparseGraph (std::istream& in,
1971  const Teuchos::RCP<const map_type>& rowMap,
1972  Teuchos::RCP<const map_type>& colMap,
1973  const Teuchos::RCP<const map_type>& domainMap,
1974  const Teuchos::RCP<const map_type>& rangeMap,
1975  const bool callFillComplete=true,
1976  const bool tolerant=false,
1977  const bool debug=false)
1978  {
1979  Teuchos::RCP<sparse_graph_type> graph =
1980  readSparseGraphHelper (in, rowMap->getComm (),
1981  rowMap, colMap, Teuchos::null, tolerant,
1982  debug);
1983  if (callFillComplete) {
1984  graph->fillComplete (domainMap, rangeMap);
1985  }
1986  return graph;
1987  }
1988 
2012  static Teuchos::RCP<sparse_matrix_type>
2013  readSparseFile (const std::string& filename,
2014  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2015  const bool callFillComplete=true,
2016  const bool tolerant=false,
2017  const bool debug=false)
2018  {
2019  const int myRank = pComm->getRank ();
2020  std::ifstream in;
2021 
2022  // Only open the file on Rank 0.
2023  if (myRank == 0) {
2024  in.open (filename.c_str ());
2025  }
2026  // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2027  // opening the file succeeded, before continuing. That will
2028  // avoid hangs if the read doesn't work. On the other hand,
2029  // readSparse could do that too, by checking the status of the
2030  // std::ostream.
2031 
2032  return readSparse (in, pComm, callFillComplete, tolerant, debug);
2033  // We can rely on the destructor of the input stream to close
2034  // the file on scope exit, even if readSparse() throws an
2035  // exception.
2036  }
2037 
2038 
2067  static Teuchos::RCP<sparse_matrix_type>
2068  readSparseFile (const std::string& filename,
2069  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2070  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2071  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2072  const bool tolerant=false,
2073  const bool debug=false)
2074  {
2075  std::ifstream in;
2076  if (pComm->getRank () == 0) { // only open on Process 0
2077  in.open (filename.c_str ());
2078  }
2079  return readSparse (in, pComm, constructorParams,
2080  fillCompleteParams, tolerant, debug);
2081  }
2082 
2083 
2121  static Teuchos::RCP<sparse_matrix_type>
2122  readSparseFile (const std::string& filename,
2123  const Teuchos::RCP<const map_type>& rowMap,
2124  Teuchos::RCP<const map_type>& colMap,
2125  const Teuchos::RCP<const map_type>& domainMap,
2126  const Teuchos::RCP<const map_type>& rangeMap,
2127  const bool callFillComplete=true,
2128  const bool tolerant=false,
2129  const bool debug=false)
2130  {
2131  using Teuchos::broadcast;
2132  using Teuchos::Comm;
2133  using Teuchos::outArg;
2134  using Teuchos::RCP;
2135 
2136  TEUCHOS_TEST_FOR_EXCEPTION(
2137  rowMap.is_null (), std::invalid_argument,
2138  "Row Map must be nonnull.");
2139 
2140  RCP<const Comm<int> > comm = rowMap->getComm ();
2141  const int myRank = comm->getRank ();
2142 
2143  // Only open the file on Process 0. Test carefully to make
2144  // sure that the file opened successfully (and broadcast that
2145  // result to all processes to prevent a hang on exception
2146  // throw), since it's a common mistake to misspell a filename.
2147  std::ifstream in;
2148  int opened = 0;
2149  if (myRank == 0) {
2150  try {
2151  in.open (filename.c_str ());
2152  opened = 1;
2153  }
2154  catch (...) {
2155  opened = 0;
2156  }
2157  }
2158  broadcast<int, int> (*comm, 0, outArg (opened));
2159  TEUCHOS_TEST_FOR_EXCEPTION(
2160  opened == 0, std::runtime_error,
2161  "readSparseFile: Failed to open file \"" << filename << "\" on "
2162  "Process 0.");
2163  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2164  callFillComplete, tolerant, debug);
2165  }
2166 
2192  static Teuchos::RCP<sparse_matrix_type>
2193  readSparse (std::istream& in,
2194  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2195  const bool callFillComplete=true,
2196  const bool tolerant=false,
2197  const bool debug=false)
2198  {
2199  using Teuchos::MatrixMarket::Banner;
2200  using Teuchos::arcp;
2201  using Teuchos::ArrayRCP;
2202  using Teuchos::broadcast;
2203  using Teuchos::null;
2204  using Teuchos::ptr;
2205  using Teuchos::RCP;
2206  using Teuchos::REDUCE_MAX;
2207  using Teuchos::reduceAll;
2208  using Teuchos::Tuple;
2209  using std::cerr;
2210  using std::endl;
2211  typedef Teuchos::ScalarTraits<scalar_type> STS;
2212 
2213  const bool extraDebug = false;
2214  const int myRank = pComm->getRank ();
2215  const int rootRank = 0;
2216 
2217  // Current line number in the input stream. Various calls
2218  // will modify this depending on the number of lines that are
2219  // read from the input stream. Only Rank 0 modifies this.
2220  size_t lineNumber = 1;
2221 
2222  if (debug && myRank == rootRank) {
2223  cerr << "Matrix Market reader: readSparse:" << endl
2224  << "-- Reading banner line" << endl;
2225  }
2226 
2227  // The "Banner" tells you whether the input stream represents
2228  // a sparse matrix, the symmetry type of the matrix, and the
2229  // type of the data it contains.
2230  //
2231  // pBanner will only be nonnull on MPI Rank 0. It will be
2232  // null on all other MPI processes.
2233  RCP<const Banner> pBanner;
2234  {
2235  // We read and validate the Banner on Proc 0, but broadcast
2236  // the validation result to all processes.
2237  // Teuchos::broadcast doesn't currently work with bool, so
2238  // we use int (true -> 1, false -> 0).
2239  int bannerIsCorrect = 1;
2240  std::ostringstream errMsg;
2241 
2242  if (myRank == rootRank) {
2243  // Read the Banner line from the input stream.
2244  try {
2245  pBanner = readBanner (in, lineNumber, tolerant, debug);
2246  }
2247  catch (std::exception& e) {
2248  errMsg << "Attempt to read the Matrix Market file's Banner line "
2249  "threw an exception: " << e.what();
2250  bannerIsCorrect = 0;
2251  }
2252 
2253  if (bannerIsCorrect) {
2254  // Validate the Banner for the case of a sparse matrix.
2255  // We validate on Proc 0, since it reads the Banner.
2256 
2257  // In intolerant mode, the matrix type must be "coordinate".
2258  if (! tolerant && pBanner->matrixType() != "coordinate") {
2259  bannerIsCorrect = 0;
2260  errMsg << "The Matrix Market input file must contain a "
2261  "\"coordinate\"-format sparse matrix in order to create a "
2262  "Tpetra::CrsMatrix object from it, but the file's matrix "
2263  "type is \"" << pBanner->matrixType() << "\" instead.";
2264  }
2265  // In tolerant mode, we allow the matrix type to be
2266  // anything other than "array" (which would mean that
2267  // the file contains a dense matrix).
2268  if (tolerant && pBanner->matrixType() == "array") {
2269  bannerIsCorrect = 0;
2270  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2271  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2272  "object from it, but the file's matrix type is \"array\" "
2273  "instead. That probably means the file contains dense matrix "
2274  "data.";
2275  }
2276  }
2277  } // Proc 0: Done reading the Banner, hopefully successfully.
2278 
2279  // Broadcast from Proc 0 whether the Banner was read correctly.
2280  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2281 
2282  // If the Banner is invalid, all processes throw an
2283  // exception. Only Proc 0 gets the exception message, but
2284  // that's OK, since the main point is to "stop the world"
2285  // (rather than throw an exception on one process and leave
2286  // the others hanging).
2287  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2288  std::invalid_argument, errMsg.str ());
2289  } // Done reading the Banner line and broadcasting success.
2290  if (debug && myRank == rootRank) {
2291  cerr << "-- Reading dimensions line" << endl;
2292  }
2293 
2294  // Read the matrix dimensions from the Matrix Market metadata.
2295  // dims = (numRows, numCols, numEntries). Proc 0 does the
2296  // reading, but it broadcasts the results to all MPI
2297  // processes. Thus, readCoordDims() is a collective
2298  // operation. It does a collective check for correctness too.
2299  Tuple<global_ordinal_type, 3> dims =
2300  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2301 
2302  if (debug && myRank == rootRank) {
2303  cerr << "-- Making Adder for collecting matrix data" << endl;
2304  }
2305 
2306  // "Adder" object for collecting all the sparse matrix entries
2307  // from the input stream. This is only nonnull on Proc 0.
2308  RCP<adder_type> pAdder =
2309  makeAdder (pComm, pBanner, dims, tolerant, debug);
2310 
2311  if (debug && myRank == rootRank) {
2312  cerr << "-- Reading matrix data" << endl;
2313  }
2314  //
2315  // Read the matrix entries from the input stream on Proc 0.
2316  //
2317  {
2318  // We use readSuccess to broadcast the results of the read
2319  // (succeeded or not) to all MPI processes. Since
2320  // Teuchos::broadcast doesn't currently know how to send
2321  // bools, we convert to int (true -> 1, false -> 0).
2322  int readSuccess = 1;
2323  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2324  if (myRank == rootRank) {
2325  try {
2326  // Reader for "coordinate" format sparse matrix data.
2327  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2328  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2329  reader_type reader (pAdder);
2330 
2331  // Read the sparse matrix entries.
2332  std::pair<bool, std::vector<size_t> > results =
2333  reader.read (in, lineNumber, tolerant, debug);
2334  readSuccess = results.first ? 1 : 0;
2335  }
2336  catch (std::exception& e) {
2337  readSuccess = 0;
2338  errMsg << e.what();
2339  }
2340  }
2341  broadcast (*pComm, rootRank, ptr (&readSuccess));
2342 
2343  // It would be nice to add a "verbose" flag, so that in
2344  // tolerant mode, we could log any bad line number(s) on
2345  // Proc 0. For now, we just throw if the read fails to
2346  // succeed.
2347  //
2348  // Question: If we're in tolerant mode, and if the read did
2349  // not succeed, should we attempt to call fillComplete()?
2350  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2351  "Failed to read the Matrix Market sparse matrix file: "
2352  << errMsg.str());
2353  } // Done reading the matrix entries (stored on Proc 0 for now)
2354 
2355  if (debug && myRank == rootRank) {
2356  cerr << "-- Successfully read the Matrix Market data" << endl;
2357  }
2358 
2359  // In tolerant mode, we need to rebroadcast the matrix
2360  // dimensions, since they may be different after reading the
2361  // actual matrix data. We only need to broadcast the number
2362  // of rows and columns. Only Rank 0 needs to know the actual
2363  // global number of entries, since (a) we need to merge
2364  // duplicates on Rank 0 first anyway, and (b) when we
2365  // distribute the entries, each rank other than Rank 0 will
2366  // only need to know how many entries it owns, not the total
2367  // number of entries.
2368  if (tolerant) {
2369  if (debug && myRank == rootRank) {
2370  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2371  << endl
2372  << "----- Dimensions before: "
2373  << dims[0] << " x " << dims[1]
2374  << endl;
2375  }
2376  // Packed coordinate matrix dimensions (numRows, numCols).
2377  Tuple<global_ordinal_type, 2> updatedDims;
2378  if (myRank == rootRank) {
2379  // If one or more bottom rows of the matrix contain no
2380  // entries, then the Adder will report that the number
2381  // of rows is less than that specified in the
2382  // metadata. We allow this case, and favor the
2383  // metadata so that the zero row(s) will be included.
2384  updatedDims[0] =
2385  std::max (dims[0], pAdder->getAdder()->numRows());
2386  updatedDims[1] = pAdder->getAdder()->numCols();
2387  }
2388  broadcast (*pComm, rootRank, updatedDims);
2389  dims[0] = updatedDims[0];
2390  dims[1] = updatedDims[1];
2391  if (debug && myRank == rootRank) {
2392  cerr << "----- Dimensions after: " << dims[0] << " x "
2393  << dims[1] << endl;
2394  }
2395  }
2396  else {
2397  // In strict mode, we require that the matrix's metadata and
2398  // its actual data agree, at least somewhat. In particular,
2399  // the number of rows must agree, since otherwise we cannot
2400  // distribute the matrix correctly.
2401 
2402  // Teuchos::broadcast() doesn't know how to broadcast bools,
2403  // so we use an int with the standard 1 == true, 0 == false
2404  // encoding.
2405  int dimsMatch = 1;
2406  if (myRank == rootRank) {
2407  // If one or more bottom rows of the matrix contain no
2408  // entries, then the Adder will report that the number of
2409  // rows is less than that specified in the metadata. We
2410  // allow this case, and favor the metadata, but do not
2411  // allow the Adder to think there are more rows in the
2412  // matrix than the metadata says.
2413  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2414  dimsMatch = 0;
2415  }
2416  }
2417  broadcast (*pComm, 0, ptr (&dimsMatch));
2418  if (dimsMatch == 0) {
2419  // We're in an error state anyway, so we might as well
2420  // work a little harder to print an informative error
2421  // message.
2422  //
2423  // Broadcast the Adder's idea of the matrix dimensions
2424  // from Proc 0 to all processes.
2425  Tuple<global_ordinal_type, 2> addersDims;
2426  if (myRank == rootRank) {
2427  addersDims[0] = pAdder->getAdder()->numRows();
2428  addersDims[1] = pAdder->getAdder()->numCols();
2429  }
2430  broadcast (*pComm, 0, addersDims);
2431  TEUCHOS_TEST_FOR_EXCEPTION(
2432  dimsMatch == 0, std::runtime_error,
2433  "The matrix metadata says that the matrix is " << dims[0] << " x "
2434  << dims[1] << ", but the actual data says that the matrix is "
2435  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2436  "data includes more rows than reported in the metadata. This "
2437  "is not allowed when parsing in strict mode. Parse the matrix in "
2438  "tolerant mode to ignore the metadata when it disagrees with the "
2439  "data.");
2440  }
2441  } // Matrix dimensions (# rows, # cols, # entries) agree.
2442 
2443  if (debug && myRank == rootRank) {
2444  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2445  }
2446 
2447  // Now that we've read in all the matrix entries from the
2448  // input stream into the adder on Proc 0, post-process them
2449  // into CSR format (still on Proc 0). This will facilitate
2450  // distributing them to all the processors.
2451  //
2452  // These arrays represent the global matrix data as a CSR
2453  // matrix (with numEntriesPerRow as redundant but convenient
2454  // metadata, since it's computable from rowPtr and vice
2455  // versa). They are valid only on Proc 0.
2456  ArrayRCP<size_t> numEntriesPerRow;
2457  ArrayRCP<size_t> rowPtr;
2458  ArrayRCP<global_ordinal_type> colInd;
2459  ArrayRCP<scalar_type> values;
2460 
2461  // Proc 0 first merges duplicate entries, and then converts
2462  // the coordinate-format matrix data to CSR.
2463  {
2464  int mergeAndConvertSucceeded = 1;
2465  std::ostringstream errMsg;
2466 
2467  if (myRank == rootRank) {
2468  try {
2469  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2470  global_ordinal_type> element_type;
2471 
2472  // Number of rows in the matrix. If we are in tolerant
2473  // mode, we've already synchronized dims with the actual
2474  // matrix data. If in strict mode, we should use dims
2475  // (as read from the file's metadata) rather than the
2476  // matrix data to determine the dimensions. (The matrix
2477  // data will claim fewer rows than the metadata, if one
2478  // or more rows have no entries stored in the file.)
2479  const size_type numRows = dims[0];
2480 
2481  // Additively merge duplicate matrix entries.
2482  pAdder->getAdder()->merge ();
2483 
2484  // Get a temporary const view of the merged matrix entries.
2485  const std::vector<element_type>& entries =
2486  pAdder->getAdder()->getEntries();
2487 
2488  // Number of matrix entries (after merging).
2489  const size_t numEntries = (size_t)entries.size();
2490 
2491  if (debug) {
2492  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2493  << " rows and numEntries=" << numEntries
2494  << " entries." << endl;
2495  }
2496 
2497  // Make space for the CSR matrix data. Converting to
2498  // CSR is easier if we fill numEntriesPerRow with zeros
2499  // at first.
2500  numEntriesPerRow = arcp<size_t> (numRows);
2501  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2502  rowPtr = arcp<size_t> (numRows+1);
2503  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2504  colInd = arcp<global_ordinal_type> (numEntries);
2505  values = arcp<scalar_type> (numEntries);
2506 
2507  // Convert from array-of-structs coordinate format to CSR
2508  // (compressed sparse row) format.
2509  global_ordinal_type prvRow = 0;
2510  size_t curPos = 0;
2511  rowPtr[0] = 0;
2512  for (curPos = 0; curPos < numEntries; ++curPos) {
2513  const element_type& curEntry = entries[curPos];
2514  const global_ordinal_type curRow = curEntry.rowIndex();
2515  TEUCHOS_TEST_FOR_EXCEPTION(
2516  curRow < prvRow, std::logic_error,
2517  "Row indices are out of order, even though they are supposed "
2518  "to be sorted. curRow = " << curRow << ", prvRow = "
2519  << prvRow << ", at curPos = " << curPos << ". Please report "
2520  "this bug to the Tpetra developers.");
2521  if (curRow > prvRow) {
2522  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2523  rowPtr[r] = curPos;
2524  }
2525  prvRow = curRow;
2526  }
2527  numEntriesPerRow[curRow]++;
2528  colInd[curPos] = curEntry.colIndex();
2529  values[curPos] = curEntry.value();
2530  }
2531  // rowPtr has one more entry than numEntriesPerRow. The
2532  // last entry of rowPtr is the number of entries in
2533  // colInd and values.
2534  rowPtr[numRows] = numEntries;
2535  } // Finished conversion to CSR format
2536  catch (std::exception& e) {
2537  mergeAndConvertSucceeded = 0;
2538  errMsg << "Failed to merge sparse matrix entries and convert to "
2539  "CSR format: " << e.what();
2540  }
2541 
2542  if (debug && mergeAndConvertSucceeded) {
2543  // Number of rows in the matrix.
2544  const size_type numRows = dims[0];
2545  const size_type maxToDisplay = 100;
2546 
2547  cerr << "----- Proc 0: numEntriesPerRow[0.."
2548  << (numEntriesPerRow.size()-1) << "] ";
2549  if (numRows > maxToDisplay) {
2550  cerr << "(only showing first and last few entries) ";
2551  }
2552  cerr << "= [";
2553  if (numRows > 0) {
2554  if (numRows > maxToDisplay) {
2555  for (size_type k = 0; k < 2; ++k) {
2556  cerr << numEntriesPerRow[k] << " ";
2557  }
2558  cerr << "... ";
2559  for (size_type k = numRows-2; k < numRows-1; ++k) {
2560  cerr << numEntriesPerRow[k] << " ";
2561  }
2562  }
2563  else {
2564  for (size_type k = 0; k < numRows-1; ++k) {
2565  cerr << numEntriesPerRow[k] << " ";
2566  }
2567  }
2568  cerr << numEntriesPerRow[numRows-1];
2569  } // numRows > 0
2570  cerr << "]" << endl;
2571 
2572  cerr << "----- Proc 0: rowPtr ";
2573  if (numRows > maxToDisplay) {
2574  cerr << "(only showing first and last few entries) ";
2575  }
2576  cerr << "= [";
2577  if (numRows > maxToDisplay) {
2578  for (size_type k = 0; k < 2; ++k) {
2579  cerr << rowPtr[k] << " ";
2580  }
2581  cerr << "... ";
2582  for (size_type k = numRows-2; k < numRows; ++k) {
2583  cerr << rowPtr[k] << " ";
2584  }
2585  }
2586  else {
2587  for (size_type k = 0; k < numRows; ++k) {
2588  cerr << rowPtr[k] << " ";
2589  }
2590  }
2591  cerr << rowPtr[numRows] << "]" << endl;
2592  }
2593  } // if myRank == rootRank
2594  } // Done converting sparse matrix data to CSR format
2595 
2596  // Now we're done with the Adder, so we can release the
2597  // reference ("free" it) to save space. This only actually
2598  // does anything on Rank 0, since pAdder is null on all the
2599  // other MPI processes.
2600  pAdder = null;
2601 
2602  if (debug && myRank == rootRank) {
2603  cerr << "-- Making range, domain, and row maps" << endl;
2604  }
2605 
2606  // Make the maps that describe the matrix's range and domain,
2607  // and the distribution of its rows. Creating a Map is a
2608  // collective operation, so we don't have to do a broadcast of
2609  // a success Boolean.
2610  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2611  RCP<const map_type> pDomainMap =
2612  makeDomainMap (pRangeMap, dims[0], dims[1]);
2613  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2614 
2615  if (debug && myRank == rootRank) {
2616  cerr << "-- Distributing the matrix data" << endl;
2617  }
2618 
2619  // Distribute the matrix data. Each processor has to add the
2620  // rows that it owns. If you try to make Proc 0 call
2621  // insertGlobalValues() for _all_ the rows, not just those it
2622  // owns, then fillComplete() will compute the number of
2623  // columns incorrectly. That's why Proc 0 has to distribute
2624  // the matrix data and why we make all the processors (not
2625  // just Proc 0) call insertGlobalValues() on their own data.
2626  //
2627  // These arrays represent each processor's part of the matrix
2628  // data, in "CSR" format (sort of, since the row indices might
2629  // not be contiguous).
2630  ArrayRCP<size_t> myNumEntriesPerRow;
2631  ArrayRCP<size_t> myRowPtr;
2632  ArrayRCP<global_ordinal_type> myColInd;
2633  ArrayRCP<scalar_type> myValues;
2634  // Distribute the matrix data. This is a collective operation.
2635  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2636  numEntriesPerRow, rowPtr, colInd, values, debug);
2637 
2638  if (debug && myRank == rootRank) {
2639  cerr << "-- Inserting matrix entries on each processor";
2640  if (callFillComplete) {
2641  cerr << " and calling fillComplete()";
2642  }
2643  cerr << endl;
2644  }
2645  // Each processor inserts its part of the matrix data, and
2646  // then they all call fillComplete(). This method invalidates
2647  // the my* distributed matrix data before calling
2648  // fillComplete(), in order to save space. In general, we
2649  // never store more than two copies of the matrix's entries in
2650  // memory at once, which is no worse than what Tpetra
2651  // promises.
2652  RCP<sparse_matrix_type> pMatrix =
2653  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2654  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2655  // Only use a reduce-all in debug mode to check if pMatrix is
2656  // null. Otherwise, just throw an exception. We never expect
2657  // a null pointer here, so we can save a communication.
2658  if (debug) {
2659  int localIsNull = pMatrix.is_null () ? 1 : 0;
2660  int globalIsNull = 0;
2661  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2662  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2663  "Reader::makeMatrix() returned a null pointer on at least one "
2664  "process. Please report this bug to the Tpetra developers.");
2665  }
2666  else {
2667  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2668  "Reader::makeMatrix() returned a null pointer. "
2669  "Please report this bug to the Tpetra developers.");
2670  }
2671 
2672  // We can't get the dimensions of the matrix until after
2673  // fillComplete() is called. Thus, we can't do the sanity
2674  // check (dimensions read from the Matrix Market data,
2675  // vs. dimensions reported by the CrsMatrix) unless the user
2676  // asked makeMatrix() to call fillComplete().
2677  //
2678  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2679  // what one might think it does, so you have to ask the range
2680  // resp. domain map for the number of rows resp. columns.
2681  if (callFillComplete) {
2682  const int numProcs = pComm->getSize ();
2683 
2684  if (extraDebug && debug) {
2685  const global_size_t globalNumRows =
2686  pRangeMap->getGlobalNumElements ();
2687  const global_size_t globalNumCols =
2688  pDomainMap->getGlobalNumElements ();
2689  if (myRank == rootRank) {
2690  cerr << "-- Matrix is "
2691  << globalNumRows << " x " << globalNumCols
2692  << " with " << pMatrix->getGlobalNumEntries()
2693  << " entries, and index base "
2694  << pMatrix->getIndexBase() << "." << endl;
2695  }
2696  pComm->barrier ();
2697  for (int p = 0; p < numProcs; ++p) {
2698  if (myRank == p) {
2699  cerr << "-- Proc " << p << " owns "
2700  << pMatrix->getNodeNumCols() << " columns, and "
2701  << pMatrix->getNodeNumEntries() << " entries." << endl;
2702  }
2703  pComm->barrier ();
2704  }
2705  } // if (extraDebug && debug)
2706  } // if (callFillComplete)
2707 
2708  if (debug && myRank == rootRank) {
2709  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2710  << endl;
2711  }
2712  return pMatrix;
2713  }
2714 
2715 
2744  static Teuchos::RCP<sparse_matrix_type>
2745  readSparse (std::istream& in,
2746  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2747  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2748  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2749  const bool tolerant=false,
2750  const bool debug=false)
2751  {
2752  using Teuchos::MatrixMarket::Banner;
2753  using Teuchos::arcp;
2754  using Teuchos::ArrayRCP;
2755  using Teuchos::broadcast;
2756  using Teuchos::null;
2757  using Teuchos::ptr;
2758  using Teuchos::RCP;
2759  using Teuchos::reduceAll;
2760  using Teuchos::Tuple;
2761  using std::cerr;
2762  using std::endl;
2763  typedef Teuchos::ScalarTraits<scalar_type> STS;
2764 
2765  const bool extraDebug = false;
2766  const int myRank = pComm->getRank ();
2767  const int rootRank = 0;
2768 
2769  // Current line number in the input stream. Various calls
2770  // will modify this depending on the number of lines that are
2771  // read from the input stream. Only Rank 0 modifies this.
2772  size_t lineNumber = 1;
2773 
2774  if (debug && myRank == rootRank) {
2775  cerr << "Matrix Market reader: readSparse:" << endl
2776  << "-- Reading banner line" << endl;
2777  }
2778 
2779  // The "Banner" tells you whether the input stream represents
2780  // a sparse matrix, the symmetry type of the matrix, and the
2781  // type of the data it contains.
2782  //
2783  // pBanner will only be nonnull on MPI Rank 0. It will be
2784  // null on all other MPI processes.
2785  RCP<const Banner> pBanner;
2786  {
2787  // We read and validate the Banner on Proc 0, but broadcast
2788  // the validation result to all processes.
2789  // Teuchos::broadcast doesn't currently work with bool, so
2790  // we use int (true -> 1, false -> 0).
2791  int bannerIsCorrect = 1;
2792  std::ostringstream errMsg;
2793 
2794  if (myRank == rootRank) {
2795  // Read the Banner line from the input stream.
2796  try {
2797  pBanner = readBanner (in, lineNumber, tolerant, debug);
2798  }
2799  catch (std::exception& e) {
2800  errMsg << "Attempt to read the Matrix Market file's Banner line "
2801  "threw an exception: " << e.what();
2802  bannerIsCorrect = 0;
2803  }
2804 
2805  if (bannerIsCorrect) {
2806  // Validate the Banner for the case of a sparse matrix.
2807  // We validate on Proc 0, since it reads the Banner.
2808 
2809  // In intolerant mode, the matrix type must be "coordinate".
2810  if (! tolerant && pBanner->matrixType() != "coordinate") {
2811  bannerIsCorrect = 0;
2812  errMsg << "The Matrix Market input file must contain a "
2813  "\"coordinate\"-format sparse matrix in order to create a "
2814  "Tpetra::CrsMatrix object from it, but the file's matrix "
2815  "type is \"" << pBanner->matrixType() << "\" instead.";
2816  }
2817  // In tolerant mode, we allow the matrix type to be
2818  // anything other than "array" (which would mean that
2819  // the file contains a dense matrix).
2820  if (tolerant && pBanner->matrixType() == "array") {
2821  bannerIsCorrect = 0;
2822  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2823  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2824  "object from it, but the file's matrix type is \"array\" "
2825  "instead. That probably means the file contains dense matrix "
2826  "data.";
2827  }
2828  }
2829  } // Proc 0: Done reading the Banner, hopefully successfully.
2830 
2831  // Broadcast from Proc 0 whether the Banner was read correctly.
2832  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2833 
2834  // If the Banner is invalid, all processes throw an
2835  // exception. Only Proc 0 gets the exception message, but
2836  // that's OK, since the main point is to "stop the world"
2837  // (rather than throw an exception on one process and leave
2838  // the others hanging).
2839  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2840  std::invalid_argument, errMsg.str ());
2841  } // Done reading the Banner line and broadcasting success.
2842  if (debug && myRank == rootRank) {
2843  cerr << "-- Reading dimensions line" << endl;
2844  }
2845 
2846  // Read the matrix dimensions from the Matrix Market metadata.
2847  // dims = (numRows, numCols, numEntries). Proc 0 does the
2848  // reading, but it broadcasts the results to all MPI
2849  // processes. Thus, readCoordDims() is a collective
2850  // operation. It does a collective check for correctness too.
2851  Tuple<global_ordinal_type, 3> dims =
2852  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2853 
2854  if (debug && myRank == rootRank) {
2855  cerr << "-- Making Adder for collecting matrix data" << endl;
2856  }
2857 
2858  // "Adder" object for collecting all the sparse matrix entries
2859  // from the input stream. This is only nonnull on Proc 0.
2860  RCP<adder_type> pAdder =
2861  makeAdder (pComm, pBanner, dims, tolerant, debug);
2862 
2863  if (debug && myRank == rootRank) {
2864  cerr << "-- Reading matrix data" << endl;
2865  }
2866  //
2867  // Read the matrix entries from the input stream on Proc 0.
2868  //
2869  {
2870  // We use readSuccess to broadcast the results of the read
2871  // (succeeded or not) to all MPI processes. Since
2872  // Teuchos::broadcast doesn't currently know how to send
2873  // bools, we convert to int (true -> 1, false -> 0).
2874  int readSuccess = 1;
2875  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2876  if (myRank == rootRank) {
2877  try {
2878  // Reader for "coordinate" format sparse matrix data.
2879  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2880  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2881  reader_type reader (pAdder);
2882 
2883  // Read the sparse matrix entries.
2884  std::pair<bool, std::vector<size_t> > results =
2885  reader.read (in, lineNumber, tolerant, debug);
2886  readSuccess = results.first ? 1 : 0;
2887  }
2888  catch (std::exception& e) {
2889  readSuccess = 0;
2890  errMsg << e.what();
2891  }
2892  }
2893  broadcast (*pComm, rootRank, ptr (&readSuccess));
2894 
2895  // It would be nice to add a "verbose" flag, so that in
2896  // tolerant mode, we could log any bad line number(s) on
2897  // Proc 0. For now, we just throw if the read fails to
2898  // succeed.
2899  //
2900  // Question: If we're in tolerant mode, and if the read did
2901  // not succeed, should we attempt to call fillComplete()?
2902  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2903  "Failed to read the Matrix Market sparse matrix file: "
2904  << errMsg.str());
2905  } // Done reading the matrix entries (stored on Proc 0 for now)
2906 
2907  if (debug && myRank == rootRank) {
2908  cerr << "-- Successfully read the Matrix Market data" << endl;
2909  }
2910 
2911  // In tolerant mode, we need to rebroadcast the matrix
2912  // dimensions, since they may be different after reading the
2913  // actual matrix data. We only need to broadcast the number
2914  // of rows and columns. Only Rank 0 needs to know the actual
2915  // global number of entries, since (a) we need to merge
2916  // duplicates on Rank 0 first anyway, and (b) when we
2917  // distribute the entries, each rank other than Rank 0 will
2918  // only need to know how many entries it owns, not the total
2919  // number of entries.
2920  if (tolerant) {
2921  if (debug && myRank == rootRank) {
2922  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2923  << endl
2924  << "----- Dimensions before: "
2925  << dims[0] << " x " << dims[1]
2926  << endl;
2927  }
2928  // Packed coordinate matrix dimensions (numRows, numCols).
2929  Tuple<global_ordinal_type, 2> updatedDims;
2930  if (myRank == rootRank) {
2931  // If one or more bottom rows of the matrix contain no
2932  // entries, then the Adder will report that the number
2933  // of rows is less than that specified in the
2934  // metadata. We allow this case, and favor the
2935  // metadata so that the zero row(s) will be included.
2936  updatedDims[0] =
2937  std::max (dims[0], pAdder->getAdder()->numRows());
2938  updatedDims[1] = pAdder->getAdder()->numCols();
2939  }
2940  broadcast (*pComm, rootRank, updatedDims);
2941  dims[0] = updatedDims[0];
2942  dims[1] = updatedDims[1];
2943  if (debug && myRank == rootRank) {
2944  cerr << "----- Dimensions after: " << dims[0] << " x "
2945  << dims[1] << endl;
2946  }
2947  }
2948  else {
2949  // In strict mode, we require that the matrix's metadata and
2950  // its actual data agree, at least somewhat. In particular,
2951  // the number of rows must agree, since otherwise we cannot
2952  // distribute the matrix correctly.
2953 
2954  // Teuchos::broadcast() doesn't know how to broadcast bools,
2955  // so we use an int with the standard 1 == true, 0 == false
2956  // encoding.
2957  int dimsMatch = 1;
2958  if (myRank == rootRank) {
2959  // If one or more bottom rows of the matrix contain no
2960  // entries, then the Adder will report that the number of
2961  // rows is less than that specified in the metadata. We
2962  // allow this case, and favor the metadata, but do not
2963  // allow the Adder to think there are more rows in the
2964  // matrix than the metadata says.
2965  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2966  dimsMatch = 0;
2967  }
2968  }
2969  broadcast (*pComm, 0, ptr (&dimsMatch));
2970  if (dimsMatch == 0) {
2971  // We're in an error state anyway, so we might as well
2972  // work a little harder to print an informative error
2973  // message.
2974  //
2975  // Broadcast the Adder's idea of the matrix dimensions
2976  // from Proc 0 to all processes.
2977  Tuple<global_ordinal_type, 2> addersDims;
2978  if (myRank == rootRank) {
2979  addersDims[0] = pAdder->getAdder()->numRows();
2980  addersDims[1] = pAdder->getAdder()->numCols();
2981  }
2982  broadcast (*pComm, 0, addersDims);
2983  TEUCHOS_TEST_FOR_EXCEPTION(
2984  dimsMatch == 0, std::runtime_error,
2985  "The matrix metadata says that the matrix is " << dims[0] << " x "
2986  << dims[1] << ", but the actual data says that the matrix is "
2987  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2988  "data includes more rows than reported in the metadata. This "
2989  "is not allowed when parsing in strict mode. Parse the matrix in "
2990  "tolerant mode to ignore the metadata when it disagrees with the "
2991  "data.");
2992  }
2993  } // Matrix dimensions (# rows, # cols, # entries) agree.
2994 
2995  if (debug && myRank == rootRank) {
2996  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2997  }
2998 
2999  // Now that we've read in all the matrix entries from the
3000  // input stream into the adder on Proc 0, post-process them
3001  // into CSR format (still on Proc 0). This will facilitate
3002  // distributing them to all the processors.
3003  //
3004  // These arrays represent the global matrix data as a CSR
3005  // matrix (with numEntriesPerRow as redundant but convenient
3006  // metadata, since it's computable from rowPtr and vice
3007  // versa). They are valid only on Proc 0.
3008  ArrayRCP<size_t> numEntriesPerRow;
3009  ArrayRCP<size_t> rowPtr;
3010  ArrayRCP<global_ordinal_type> colInd;
3011  ArrayRCP<scalar_type> values;
3012 
3013  // Proc 0 first merges duplicate entries, and then converts
3014  // the coordinate-format matrix data to CSR.
3015  {
3016  int mergeAndConvertSucceeded = 1;
3017  std::ostringstream errMsg;
3018 
3019  if (myRank == rootRank) {
3020  try {
3021  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3022  global_ordinal_type> element_type;
3023 
3024  // Number of rows in the matrix. If we are in tolerant
3025  // mode, we've already synchronized dims with the actual
3026  // matrix data. If in strict mode, we should use dims
3027  // (as read from the file's metadata) rather than the
3028  // matrix data to determine the dimensions. (The matrix
3029  // data will claim fewer rows than the metadata, if one
3030  // or more rows have no entries stored in the file.)
3031  const size_type numRows = dims[0];
3032 
3033  // Additively merge duplicate matrix entries.
3034  pAdder->getAdder()->merge ();
3035 
3036  // Get a temporary const view of the merged matrix entries.
3037  const std::vector<element_type>& entries =
3038  pAdder->getAdder()->getEntries();
3039 
3040  // Number of matrix entries (after merging).
3041  const size_t numEntries = (size_t)entries.size();
3042 
3043  if (debug) {
3044  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3045  << " rows and numEntries=" << numEntries
3046  << " entries." << endl;
3047  }
3048 
3049  // Make space for the CSR matrix data. Converting to
3050  // CSR is easier if we fill numEntriesPerRow with zeros
3051  // at first.
3052  numEntriesPerRow = arcp<size_t> (numRows);
3053  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3054  rowPtr = arcp<size_t> (numRows+1);
3055  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3056  colInd = arcp<global_ordinal_type> (numEntries);
3057  values = arcp<scalar_type> (numEntries);
3058 
3059  // Convert from array-of-structs coordinate format to CSR
3060  // (compressed sparse row) format.
3061  global_ordinal_type prvRow = 0;
3062  size_t curPos = 0;
3063  rowPtr[0] = 0;
3064  for (curPos = 0; curPos < numEntries; ++curPos) {
3065  const element_type& curEntry = entries[curPos];
3066  const global_ordinal_type curRow = curEntry.rowIndex();
3067  TEUCHOS_TEST_FOR_EXCEPTION(
3068  curRow < prvRow, std::logic_error,
3069  "Row indices are out of order, even though they are supposed "
3070  "to be sorted. curRow = " << curRow << ", prvRow = "
3071  << prvRow << ", at curPos = " << curPos << ". Please report "
3072  "this bug to the Tpetra developers.");
3073  if (curRow > prvRow) {
3074  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3075  rowPtr[r] = curPos;
3076  }
3077  prvRow = curRow;
3078  }
3079  numEntriesPerRow[curRow]++;
3080  colInd[curPos] = curEntry.colIndex();
3081  values[curPos] = curEntry.value();
3082  }
3083  // rowPtr has one more entry than numEntriesPerRow. The
3084  // last entry of rowPtr is the number of entries in
3085  // colInd and values.
3086  rowPtr[numRows] = numEntries;
3087  } // Finished conversion to CSR format
3088  catch (std::exception& e) {
3089  mergeAndConvertSucceeded = 0;
3090  errMsg << "Failed to merge sparse matrix entries and convert to "
3091  "CSR format: " << e.what();
3092  }
3093 
3094  if (debug && mergeAndConvertSucceeded) {
3095  // Number of rows in the matrix.
3096  const size_type numRows = dims[0];
3097  const size_type maxToDisplay = 100;
3098 
3099  cerr << "----- Proc 0: numEntriesPerRow[0.."
3100  << (numEntriesPerRow.size()-1) << "] ";
3101  if (numRows > maxToDisplay) {
3102  cerr << "(only showing first and last few entries) ";
3103  }
3104  cerr << "= [";
3105  if (numRows > 0) {
3106  if (numRows > maxToDisplay) {
3107  for (size_type k = 0; k < 2; ++k) {
3108  cerr << numEntriesPerRow[k] << " ";
3109  }
3110  cerr << "... ";
3111  for (size_type k = numRows-2; k < numRows-1; ++k) {
3112  cerr << numEntriesPerRow[k] << " ";
3113  }
3114  }
3115  else {
3116  for (size_type k = 0; k < numRows-1; ++k) {
3117  cerr << numEntriesPerRow[k] << " ";
3118  }
3119  }
3120  cerr << numEntriesPerRow[numRows-1];
3121  } // numRows > 0
3122  cerr << "]" << endl;
3123 
3124  cerr << "----- Proc 0: rowPtr ";
3125  if (numRows > maxToDisplay) {
3126  cerr << "(only showing first and last few entries) ";
3127  }
3128  cerr << "= [";
3129  if (numRows > maxToDisplay) {
3130  for (size_type k = 0; k < 2; ++k) {
3131  cerr << rowPtr[k] << " ";
3132  }
3133  cerr << "... ";
3134  for (size_type k = numRows-2; k < numRows; ++k) {
3135  cerr << rowPtr[k] << " ";
3136  }
3137  }
3138  else {
3139  for (size_type k = 0; k < numRows; ++k) {
3140  cerr << rowPtr[k] << " ";
3141  }
3142  }
3143  cerr << rowPtr[numRows] << "]" << endl;
3144  }
3145  } // if myRank == rootRank
3146  } // Done converting sparse matrix data to CSR format
3147 
3148  // Now we're done with the Adder, so we can release the
3149  // reference ("free" it) to save space. This only actually
3150  // does anything on Rank 0, since pAdder is null on all the
3151  // other MPI processes.
3152  pAdder = null;
3153 
3154  if (debug && myRank == rootRank) {
3155  cerr << "-- Making range, domain, and row maps" << endl;
3156  }
3157 
3158  // Make the maps that describe the matrix's range and domain,
3159  // and the distribution of its rows. Creating a Map is a
3160  // collective operation, so we don't have to do a broadcast of
3161  // a success Boolean.
3162  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3163  RCP<const map_type> pDomainMap =
3164  makeDomainMap (pRangeMap, dims[0], dims[1]);
3165  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3166 
3167  if (debug && myRank == rootRank) {
3168  cerr << "-- Distributing the matrix data" << endl;
3169  }
3170 
3171  // Distribute the matrix data. Each processor has to add the
3172  // rows that it owns. If you try to make Proc 0 call
3173  // insertGlobalValues() for _all_ the rows, not just those it
3174  // owns, then fillComplete() will compute the number of
3175  // columns incorrectly. That's why Proc 0 has to distribute
3176  // the matrix data and why we make all the processors (not
3177  // just Proc 0) call insertGlobalValues() on their own data.
3178  //
3179  // These arrays represent each processor's part of the matrix
3180  // data, in "CSR" format (sort of, since the row indices might
3181  // not be contiguous).
3182  ArrayRCP<size_t> myNumEntriesPerRow;
3183  ArrayRCP<size_t> myRowPtr;
3184  ArrayRCP<global_ordinal_type> myColInd;
3185  ArrayRCP<scalar_type> myValues;
3186  // Distribute the matrix data. This is a collective operation.
3187  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3188  numEntriesPerRow, rowPtr, colInd, values, debug);
3189 
3190  if (debug && myRank == rootRank) {
3191  cerr << "-- Inserting matrix entries on each process "
3192  "and calling fillComplete()" << endl;
3193  }
3194  // Each processor inserts its part of the matrix data, and
3195  // then they all call fillComplete(). This method invalidates
3196  // the my* distributed matrix data before calling
3197  // fillComplete(), in order to save space. In general, we
3198  // never store more than two copies of the matrix's entries in
3199  // memory at once, which is no worse than what Tpetra
3200  // promises.
3201  Teuchos::RCP<sparse_matrix_type> pMatrix =
3202  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3203  pRowMap, pRangeMap, pDomainMap, constructorParams,
3204  fillCompleteParams);
3205  // Only use a reduce-all in debug mode to check if pMatrix is
3206  // null. Otherwise, just throw an exception. We never expect
3207  // a null pointer here, so we can save a communication.
3208  if (debug) {
3209  int localIsNull = pMatrix.is_null () ? 1 : 0;
3210  int globalIsNull = 0;
3211  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3212  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3213  "Reader::makeMatrix() returned a null pointer on at least one "
3214  "process. Please report this bug to the Tpetra developers.");
3215  }
3216  else {
3217  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3218  "Reader::makeMatrix() returned a null pointer. "
3219  "Please report this bug to the Tpetra developers.");
3220  }
3221 
3222  // Sanity check for dimensions (read from the Matrix Market
3223  // data, vs. dimensions reported by the CrsMatrix).
3224  //
3225  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3226  // what one might think it does, so you have to ask the range
3227  // resp. domain map for the number of rows resp. columns.
3228  if (extraDebug && debug) {
3229  const int numProcs = pComm->getSize ();
3230  const global_size_t globalNumRows =
3231  pRangeMap->getGlobalNumElements();
3232  const global_size_t globalNumCols =
3233  pDomainMap->getGlobalNumElements();
3234  if (myRank == rootRank) {
3235  cerr << "-- Matrix is "
3236  << globalNumRows << " x " << globalNumCols
3237  << " with " << pMatrix->getGlobalNumEntries()
3238  << " entries, and index base "
3239  << pMatrix->getIndexBase() << "." << endl;
3240  }
3241  pComm->barrier ();
3242  for (int p = 0; p < numProcs; ++p) {
3243  if (myRank == p) {
3244  cerr << "-- Proc " << p << " owns "
3245  << pMatrix->getNodeNumCols() << " columns, and "
3246  << pMatrix->getNodeNumEntries() << " entries." << endl;
3247  }
3248  pComm->barrier ();
3249  }
3250  } // if (extraDebug && debug)
3251 
3252  if (debug && myRank == rootRank) {
3253  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3254  << endl;
3255  }
3256  return pMatrix;
3257  }
3258 
3259 
3300  static Teuchos::RCP<sparse_matrix_type>
3301  readSparse (std::istream& in,
3302  const Teuchos::RCP<const map_type>& rowMap,
3303  Teuchos::RCP<const map_type>& colMap,
3304  const Teuchos::RCP<const map_type>& domainMap,
3305  const Teuchos::RCP<const map_type>& rangeMap,
3306  const bool callFillComplete=true,
3307  const bool tolerant=false,
3308  const bool debug=false)
3309  {
3310  using Teuchos::MatrixMarket::Banner;
3311  using Teuchos::arcp;
3312  using Teuchos::ArrayRCP;
3313  using Teuchos::ArrayView;
3314  using Teuchos::as;
3315  using Teuchos::broadcast;
3316  using Teuchos::Comm;
3317  using Teuchos::null;
3318  using Teuchos::ptr;
3319  using Teuchos::RCP;
3320  using Teuchos::reduceAll;
3321  using Teuchos::Tuple;
3322  using std::cerr;
3323  using std::endl;
3324  typedef Teuchos::ScalarTraits<scalar_type> STS;
3325 
3326  RCP<const Comm<int> > pComm = rowMap->getComm ();
3327  const int myRank = pComm->getRank ();
3328  const int rootRank = 0;
3329  const bool extraDebug = false;
3330 
3331  // Fast checks for invalid input. We can't check other
3332  // attributes of the Maps until we've read in the matrix
3333  // dimensions.
3334  TEUCHOS_TEST_FOR_EXCEPTION(
3335  rowMap.is_null (), std::invalid_argument,
3336  "Row Map must be nonnull.");
3337  TEUCHOS_TEST_FOR_EXCEPTION(
3338  rangeMap.is_null (), std::invalid_argument,
3339  "Range Map must be nonnull.");
3340  TEUCHOS_TEST_FOR_EXCEPTION(
3341  domainMap.is_null (), std::invalid_argument,
3342  "Domain Map must be nonnull.");
3343  TEUCHOS_TEST_FOR_EXCEPTION(
3344  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3345  std::invalid_argument,
3346  "The specified row Map's communicator (rowMap->getComm())"
3347  "differs from the given separately supplied communicator pComm.");
3348  TEUCHOS_TEST_FOR_EXCEPTION(
3349  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3350  std::invalid_argument,
3351  "The specified domain Map's communicator (domainMap->getComm())"
3352  "differs from the given separately supplied communicator pComm.");
3353  TEUCHOS_TEST_FOR_EXCEPTION(
3354  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3355  std::invalid_argument,
3356  "The specified range Map's communicator (rangeMap->getComm())"
3357  "differs from the given separately supplied communicator pComm.");
3358 
3359  // Current line number in the input stream. Various calls
3360  // will modify this depending on the number of lines that are
3361  // read from the input stream. Only Rank 0 modifies this.
3362  size_t lineNumber = 1;
3363 
3364  if (debug && myRank == rootRank) {
3365  cerr << "Matrix Market reader: readSparse:" << endl
3366  << "-- Reading banner line" << endl;
3367  }
3368 
3369  // The "Banner" tells you whether the input stream represents
3370  // a sparse matrix, the symmetry type of the matrix, and the
3371  // type of the data it contains.
3372  //
3373  // pBanner will only be nonnull on MPI Rank 0. It will be
3374  // null on all other MPI processes.
3375  RCP<const Banner> pBanner;
3376  {
3377  // We read and validate the Banner on Proc 0, but broadcast
3378  // the validation result to all processes.
3379  // Teuchos::broadcast doesn't currently work with bool, so
3380  // we use int (true -> 1, false -> 0).
3381  int bannerIsCorrect = 1;
3382  std::ostringstream errMsg;
3383 
3384  if (myRank == rootRank) {
3385  // Read the Banner line from the input stream.
3386  try {
3387  pBanner = readBanner (in, lineNumber, tolerant, debug);
3388  }
3389  catch (std::exception& e) {
3390  errMsg << "Attempt to read the Matrix Market file's Banner line "
3391  "threw an exception: " << e.what();
3392  bannerIsCorrect = 0;
3393  }
3394 
3395  if (bannerIsCorrect) {
3396  // Validate the Banner for the case of a sparse matrix.
3397  // We validate on Proc 0, since it reads the Banner.
3398 
3399  // In intolerant mode, the matrix type must be "coordinate".
3400  if (! tolerant && pBanner->matrixType() != "coordinate") {
3401  bannerIsCorrect = 0;
3402  errMsg << "The Matrix Market input file must contain a "
3403  "\"coordinate\"-format sparse matrix in order to create a "
3404  "Tpetra::CrsMatrix object from it, but the file's matrix "
3405  "type is \"" << pBanner->matrixType() << "\" instead.";
3406  }
3407  // In tolerant mode, we allow the matrix type to be
3408  // anything other than "array" (which would mean that
3409  // the file contains a dense matrix).
3410  if (tolerant && pBanner->matrixType() == "array") {
3411  bannerIsCorrect = 0;
3412  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3413  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3414  "object from it, but the file's matrix type is \"array\" "
3415  "instead. That probably means the file contains dense matrix "
3416  "data.";
3417  }
3418  }
3419  } // Proc 0: Done reading the Banner, hopefully successfully.
3420 
3421  // Broadcast from Proc 0 whether the Banner was read correctly.
3422  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3423 
3424  // If the Banner is invalid, all processes throw an
3425  // exception. Only Proc 0 gets the exception message, but
3426  // that's OK, since the main point is to "stop the world"
3427  // (rather than throw an exception on one process and leave
3428  // the others hanging).
3429  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3430  std::invalid_argument, errMsg.str ());
3431  } // Done reading the Banner line and broadcasting success.
3432  if (debug && myRank == rootRank) {
3433  cerr << "-- Reading dimensions line" << endl;
3434  }
3435 
3436  // Read the matrix dimensions from the Matrix Market metadata.
3437  // dims = (numRows, numCols, numEntries). Proc 0 does the
3438  // reading, but it broadcasts the results to all MPI
3439  // processes. Thus, readCoordDims() is a collective
3440  // operation. It does a collective check for correctness too.
3441  Tuple<global_ordinal_type, 3> dims =
3442  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3443 
3444  if (debug && myRank == rootRank) {
3445  cerr << "-- Making Adder for collecting matrix data" << endl;
3446  }
3447 
3448  // "Adder" object for collecting all the sparse matrix entries
3449  // from the input stream. This is only nonnull on Proc 0.
3450  // The Adder internally converts the one-based indices (native
3451  // Matrix Market format) into zero-based indices.
3452  RCP<adder_type> pAdder =
3453  makeAdder (pComm, pBanner, dims, tolerant, debug);
3454 
3455  if (debug && myRank == rootRank) {
3456  cerr << "-- Reading matrix data" << endl;
3457  }
3458  //
3459  // Read the matrix entries from the input stream on Proc 0.
3460  //
3461  {
3462  // We use readSuccess to broadcast the results of the read
3463  // (succeeded or not) to all MPI processes. Since
3464  // Teuchos::broadcast doesn't currently know how to send
3465  // bools, we convert to int (true -> 1, false -> 0).
3466  int readSuccess = 1;
3467  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3468  if (myRank == rootRank) {
3469  try {
3470  // Reader for "coordinate" format sparse matrix data.
3471  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3472  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3473  reader_type reader (pAdder);
3474 
3475  // Read the sparse matrix entries.
3476  std::pair<bool, std::vector<size_t> > results =
3477  reader.read (in, lineNumber, tolerant, debug);
3478  readSuccess = results.first ? 1 : 0;
3479  }
3480  catch (std::exception& e) {
3481  readSuccess = 0;
3482  errMsg << e.what();
3483  }
3484  }
3485  broadcast (*pComm, rootRank, ptr (&readSuccess));
3486 
3487  // It would be nice to add a "verbose" flag, so that in
3488  // tolerant mode, we could log any bad line number(s) on
3489  // Proc 0. For now, we just throw if the read fails to
3490  // succeed.
3491  //
3492  // Question: If we're in tolerant mode, and if the read did
3493  // not succeed, should we attempt to call fillComplete()?
3494  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3495  "Failed to read the Matrix Market sparse matrix file: "
3496  << errMsg.str());
3497  } // Done reading the matrix entries (stored on Proc 0 for now)
3498 
3499  if (debug && myRank == rootRank) {
3500  cerr << "-- Successfully read the Matrix Market data" << endl;
3501  }
3502 
3503  // In tolerant mode, we need to rebroadcast the matrix
3504  // dimensions, since they may be different after reading the
3505  // actual matrix data. We only need to broadcast the number
3506  // of rows and columns. Only Rank 0 needs to know the actual
3507  // global number of entries, since (a) we need to merge
3508  // duplicates on Rank 0 first anyway, and (b) when we
3509  // distribute the entries, each rank other than Rank 0 will
3510  // only need to know how many entries it owns, not the total
3511  // number of entries.
3512  if (tolerant) {
3513  if (debug && myRank == rootRank) {
3514  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3515  << endl
3516  << "----- Dimensions before: "
3517  << dims[0] << " x " << dims[1]
3518  << endl;
3519  }
3520  // Packed coordinate matrix dimensions (numRows, numCols).
3521  Tuple<global_ordinal_type, 2> updatedDims;
3522  if (myRank == rootRank) {
3523  // If one or more bottom rows of the matrix contain no
3524  // entries, then the Adder will report that the number
3525  // of rows is less than that specified in the
3526  // metadata. We allow this case, and favor the
3527  // metadata so that the zero row(s) will be included.
3528  updatedDims[0] =
3529  std::max (dims[0], pAdder->getAdder()->numRows());
3530  updatedDims[1] = pAdder->getAdder()->numCols();
3531  }
3532  broadcast (*pComm, rootRank, updatedDims);
3533  dims[0] = updatedDims[0];
3534  dims[1] = updatedDims[1];
3535  if (debug && myRank == rootRank) {
3536  cerr << "----- Dimensions after: " << dims[0] << " x "
3537  << dims[1] << endl;
3538  }
3539  }
3540  else {
3541  // In strict mode, we require that the matrix's metadata and
3542  // its actual data agree, at least somewhat. In particular,
3543  // the number of rows must agree, since otherwise we cannot
3544  // distribute the matrix correctly.
3545 
3546  // Teuchos::broadcast() doesn't know how to broadcast bools,
3547  // so we use an int with the standard 1 == true, 0 == false
3548  // encoding.
3549  int dimsMatch = 1;
3550  if (myRank == rootRank) {
3551  // If one or more bottom rows of the matrix contain no
3552  // entries, then the Adder will report that the number of
3553  // rows is less than that specified in the metadata. We
3554  // allow this case, and favor the metadata, but do not
3555  // allow the Adder to think there are more rows in the
3556  // matrix than the metadata says.
3557  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3558  dimsMatch = 0;
3559  }
3560  }
3561  broadcast (*pComm, 0, ptr (&dimsMatch));
3562  if (dimsMatch == 0) {
3563  // We're in an error state anyway, so we might as well
3564  // work a little harder to print an informative error
3565  // message.
3566  //
3567  // Broadcast the Adder's idea of the matrix dimensions
3568  // from Proc 0 to all processes.
3569  Tuple<global_ordinal_type, 2> addersDims;
3570  if (myRank == rootRank) {
3571  addersDims[0] = pAdder->getAdder()->numRows();
3572  addersDims[1] = pAdder->getAdder()->numCols();
3573  }
3574  broadcast (*pComm, 0, addersDims);
3575  TEUCHOS_TEST_FOR_EXCEPTION(
3576  dimsMatch == 0, std::runtime_error,
3577  "The matrix metadata says that the matrix is " << dims[0] << " x "
3578  << dims[1] << ", but the actual data says that the matrix is "
3579  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3580  "data includes more rows than reported in the metadata. This "
3581  "is not allowed when parsing in strict mode. Parse the matrix in "
3582  "tolerant mode to ignore the metadata when it disagrees with the "
3583  "data.");
3584  }
3585  } // Matrix dimensions (# rows, # cols, # entries) agree.
3586 
3587  if (debug && myRank == rootRank) {
3588  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3589  }
3590 
3591  // Now that we've read in all the matrix entries from the
3592  // input stream into the adder on Proc 0, post-process them
3593  // into CSR format (still on Proc 0). This will facilitate
3594  // distributing them to all the processors.
3595  //
3596  // These arrays represent the global matrix data as a CSR
3597  // matrix (with numEntriesPerRow as redundant but convenient
3598  // metadata, since it's computable from rowPtr and vice
3599  // versa). They are valid only on Proc 0.
3600  ArrayRCP<size_t> numEntriesPerRow;
3601  ArrayRCP<size_t> rowPtr;
3602  ArrayRCP<global_ordinal_type> colInd;
3603  ArrayRCP<scalar_type> values;
3604  size_t maxNumEntriesPerRow = 0;
3605 
3606  // Proc 0 first merges duplicate entries, and then converts
3607  // the coordinate-format matrix data to CSR.
3608  {
3609  int mergeAndConvertSucceeded = 1;
3610  std::ostringstream errMsg;
3611 
3612  if (myRank == rootRank) {
3613  try {
3614  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3615  global_ordinal_type> element_type;
3616 
3617  // Number of rows in the matrix. If we are in tolerant
3618  // mode, we've already synchronized dims with the actual
3619  // matrix data. If in strict mode, we should use dims
3620  // (as read from the file's metadata) rather than the
3621  // matrix data to determine the dimensions. (The matrix
3622  // data will claim fewer rows than the metadata, if one
3623  // or more rows have no entries stored in the file.)
3624  const size_type numRows = dims[0];
3625 
3626  // Additively merge duplicate matrix entries.
3627  pAdder->getAdder()->merge ();
3628 
3629  // Get a temporary const view of the merged matrix entries.
3630  const std::vector<element_type>& entries =
3631  pAdder->getAdder()->getEntries();
3632 
3633  // Number of matrix entries (after merging).
3634  const size_t numEntries = (size_t)entries.size();
3635 
3636  if (debug) {
3637  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3638  << " rows and numEntries=" << numEntries
3639  << " entries." << endl;
3640  }
3641 
3642  // Make space for the CSR matrix data. Converting to
3643  // CSR is easier if we fill numEntriesPerRow with zeros
3644  // at first.
3645  numEntriesPerRow = arcp<size_t> (numRows);
3646  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3647  rowPtr = arcp<size_t> (numRows+1);
3648  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3649  colInd = arcp<global_ordinal_type> (numEntries);
3650  values = arcp<scalar_type> (numEntries);
3651 
3652  // Convert from array-of-structs coordinate format to CSR
3653  // (compressed sparse row) format.
3654  global_ordinal_type prvRow = 0;
3655  size_t curPos = 0;
3656  rowPtr[0] = 0;
3657  for (curPos = 0; curPos < numEntries; ++curPos) {
3658  const element_type& curEntry = entries[curPos];
3659  const global_ordinal_type curRow = curEntry.rowIndex();
3660  TEUCHOS_TEST_FOR_EXCEPTION(
3661  curRow < prvRow, std::logic_error,
3662  "Row indices are out of order, even though they are supposed "
3663  "to be sorted. curRow = " << curRow << ", prvRow = "
3664  << prvRow << ", at curPos = " << curPos << ". Please report "
3665  "this bug to the Tpetra developers.");
3666  if (curRow > prvRow) {
3667  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3668  rowPtr[r] = curPos;
3669  }
3670  prvRow = curRow;
3671  }
3672  numEntriesPerRow[curRow]++;
3673  colInd[curPos] = curEntry.colIndex();
3674  values[curPos] = curEntry.value();
3675  }
3676  // rowPtr has one more entry than numEntriesPerRow. The
3677  // last entry of rowPtr is the number of entries in
3678  // colInd and values.
3679  rowPtr[numRows] = numEntries;
3680  } // Finished conversion to CSR format
3681  catch (std::exception& e) {
3682  mergeAndConvertSucceeded = 0;
3683  errMsg << "Failed to merge sparse matrix entries and convert to "
3684  "CSR format: " << e.what();
3685  }
3686 
3687  if (debug && mergeAndConvertSucceeded) {
3688  // Number of rows in the matrix.
3689  const size_type numRows = dims[0];
3690  const size_type maxToDisplay = 100;
3691 
3692  cerr << "----- Proc 0: numEntriesPerRow[0.."
3693  << (numEntriesPerRow.size()-1) << "] ";
3694  if (numRows > maxToDisplay) {
3695  cerr << "(only showing first and last few entries) ";
3696  }
3697  cerr << "= [";
3698  if (numRows > 0) {
3699  if (numRows > maxToDisplay) {
3700  for (size_type k = 0; k < 2; ++k) {
3701  cerr << numEntriesPerRow[k] << " ";
3702  }
3703  cerr << "... ";
3704  for (size_type k = numRows-2; k < numRows-1; ++k) {
3705  cerr << numEntriesPerRow[k] << " ";
3706  }
3707  }
3708  else {
3709  for (size_type k = 0; k < numRows-1; ++k) {
3710  cerr << numEntriesPerRow[k] << " ";
3711  }
3712  }
3713  cerr << numEntriesPerRow[numRows-1];
3714  } // numRows > 0
3715  cerr << "]" << endl;
3716 
3717  cerr << "----- Proc 0: rowPtr ";
3718  if (numRows > maxToDisplay) {
3719  cerr << "(only showing first and last few entries) ";
3720  }
3721  cerr << "= [";
3722  if (numRows > maxToDisplay) {
3723  for (size_type k = 0; k < 2; ++k) {
3724  cerr << rowPtr[k] << " ";
3725  }
3726  cerr << "... ";
3727  for (size_type k = numRows-2; k < numRows; ++k) {
3728  cerr << rowPtr[k] << " ";
3729  }
3730  }
3731  else {
3732  for (size_type k = 0; k < numRows; ++k) {
3733  cerr << rowPtr[k] << " ";
3734  }
3735  }
3736  cerr << rowPtr[numRows] << "]" << endl;
3737 
3738  cerr << "----- Proc 0: colInd = [";
3739  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3740  cerr << colInd[k] << " ";
3741  }
3742  cerr << "]" << endl;
3743  }
3744  } // if myRank == rootRank
3745  } // Done converting sparse matrix data to CSR format
3746 
3747  // Now we're done with the Adder, so we can release the
3748  // reference ("free" it) to save space. This only actually
3749  // does anything on Rank 0, since pAdder is null on all the
3750  // other MPI processes.
3751  pAdder = null;
3752 
3753  // Verify details of the Maps. Don't count the global number
3754  // of entries in the row Map, since that number doesn't
3755  // correctly count overlap.
3756  if (debug && myRank == rootRank) {
3757  cerr << "-- Verifying Maps" << endl;
3758  }
3759  TEUCHOS_TEST_FOR_EXCEPTION(
3760  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3761  std::invalid_argument,
3762  "The range Map has " << rangeMap->getGlobalNumElements ()
3763  << " entries, but the matrix has a global number of rows " << dims[0]
3764  << ".");
3765  TEUCHOS_TEST_FOR_EXCEPTION(
3766  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3767  std::invalid_argument,
3768  "The domain Map has " << domainMap->getGlobalNumElements ()
3769  << " entries, but the matrix has a global number of columns "
3770  << dims[1] << ".");
3771 
3772  // Create a row Map which is entirely owned on Proc 0.
3773  RCP<Teuchos::FancyOStream> err = debug ?
3774  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3775 
3776  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3777  ArrayView<const global_ordinal_type> myRows =
3778  gatherRowMap->getNodeElementList ();
3779  const size_type myNumRows = myRows.size ();
3780  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3781 
3782  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3783  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3784  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3785  if (gatherNumEntriesPerRow[i_] > maxNumEntriesPerRow)
3786  maxNumEntriesPerRow = gatherNumEntriesPerRow[i_];
3787  }
3788 
3789  // Create a matrix using this Map, and fill in on Proc 0. We
3790  // know how many entries there are in each row, so we can use
3791  // static profile.
3792  RCP<sparse_matrix_type> A_proc0 =
3793  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow (),
3794  Tpetra::StaticProfile));
3795  if (myRank == rootRank) {
3796  if (debug) {
3797  cerr << "-- Proc 0: Filling gather matrix" << endl;
3798  }
3799  if (debug) {
3800  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3801  }
3802 
3803  // Add Proc 0's matrix entries to the CrsMatrix.
3804  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3805  size_type i = myRows[i_] - indexBase;
3806 
3807  const size_type curPos = as<size_type> (rowPtr[i]);
3808  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3809  ArrayView<global_ordinal_type> curColInd =
3810  colInd.view (curPos, curNumEntries);
3811  ArrayView<scalar_type> curValues =
3812  values.view (curPos, curNumEntries);
3813 
3814  // Modify the column indices in place to have the right index base.
3815  for (size_type k = 0; k < curNumEntries; ++k) {
3816  curColInd[k] += indexBase;
3817  }
3818  if (debug) {
3819  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3820  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3821  }
3822  // Avoid constructing empty views of ArrayRCP objects.
3823  if (curNumEntries > 0) {
3824  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3825  }
3826  }
3827  // Now we can save space by deallocating numEntriesPerRow,
3828  // rowPtr, colInd, and values, since we've already put those
3829  // data in the matrix.
3830  numEntriesPerRow = null;
3831  rowPtr = null;
3832  colInd = null;
3833  values = null;
3834  } // if myRank == rootRank
3835 
3836  broadcast<int,size_t> (*pComm, 0, &maxNumEntriesPerRow);
3837 
3838  RCP<sparse_matrix_type> A;
3839  if (colMap.is_null ()) {
3840  A = rcp (new sparse_matrix_type (rowMap, maxNumEntriesPerRow));
3841  } else {
3842  A = rcp (new sparse_matrix_type (rowMap, colMap, maxNumEntriesPerRow));
3843  }
3845  export_type exp (gatherRowMap, rowMap);
3846  A->doExport (*A_proc0, exp, INSERT);
3847 
3848  if (callFillComplete) {
3849  A->fillComplete (domainMap, rangeMap);
3850  }
3851 
3852  // We can't get the dimensions of the matrix until after
3853  // fillComplete() is called. Thus, we can't do the sanity
3854  // check (dimensions read from the Matrix Market data,
3855  // vs. dimensions reported by the CrsMatrix) unless the user
3856  // asked us to call fillComplete().
3857  //
3858  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3859  // what one might think it does, so you have to ask the range
3860  // resp. domain map for the number of rows resp. columns.
3861  if (callFillComplete) {
3862  const int numProcs = pComm->getSize ();
3863 
3864  if (extraDebug && debug) {
3865  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3866  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3867  if (myRank == rootRank) {
3868  cerr << "-- Matrix is "
3869  << globalNumRows << " x " << globalNumCols
3870  << " with " << A->getGlobalNumEntries()
3871  << " entries, and index base "
3872  << A->getIndexBase() << "." << endl;
3873  }
3874  pComm->barrier ();
3875  for (int p = 0; p < numProcs; ++p) {
3876  if (myRank == p) {
3877  cerr << "-- Proc " << p << " owns "
3878  << A->getNodeNumCols() << " columns, and "
3879  << A->getNodeNumEntries() << " entries." << endl;
3880  }
3881  pComm->barrier ();
3882  }
3883  } // if (extraDebug && debug)
3884  } // if (callFillComplete)
3885 
3886  if (debug && myRank == rootRank) {
3887  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3888  << endl;
3889  }
3890  return A;
3891  }
3892 
3921  static Teuchos::RCP<multivector_type>
3922  readDenseFile (const std::string& filename,
3923  const Teuchos::RCP<const comm_type>& comm,
3924  Teuchos::RCP<const map_type>& map,
3925  const bool tolerant=false,
3926  const bool debug=false)
3927  {
3928  std::ifstream in;
3929  if (comm->getRank () == 0) { // Only open the file on Proc 0.
3930  in.open (filename.c_str ()); // Destructor closes safely
3931  }
3932  return readDense (in, comm, map, tolerant, debug);
3933  }
3934 
3935 
3965  static Teuchos::RCP<vector_type>
3966  readVectorFile (const std::string& filename,
3967  const Teuchos::RCP<const comm_type>& comm,
3968  Teuchos::RCP<const map_type>& map,
3969  const bool tolerant=false,
3970  const bool debug=false)
3971  {
3972  std::ifstream in;
3973  if (comm->getRank () == 0) { // Only open the file on Proc 0.
3974  in.open (filename.c_str ()); // Destructor closes safely
3975  }
3976  return readVector (in, comm, map, tolerant, debug);
3977  }
3978 
3979 
4046  static Teuchos::RCP<multivector_type>
4047  readDense (std::istream& in,
4048  const Teuchos::RCP<const comm_type>& comm,
4049  Teuchos::RCP<const map_type>& map,
4050  const bool tolerant=false,
4051  const bool debug=false)
4052  {
4053  Teuchos::RCP<Teuchos::FancyOStream> err =
4054  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4055  return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4056  }
4057 
4058 
4060  static Teuchos::RCP<vector_type>
4061  readVector (std::istream& in,
4062  const Teuchos::RCP<const comm_type>& comm,
4063  Teuchos::RCP<const map_type>& map,
4064  const bool tolerant=false,
4065  const bool debug=false)
4066  {
4067  Teuchos::RCP<Teuchos::FancyOStream> err =
4068  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4069  return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4070  }
4071 
4072 
4093  static Teuchos::RCP<const map_type>
4094  readMapFile (const std::string& filename,
4095  const Teuchos::RCP<const comm_type>& comm,
4096  const bool tolerant=false,
4097  const bool debug=false)
4098  {
4099  using Teuchos::inOutArg;
4100  using Teuchos::broadcast;
4101  std::ifstream in;
4102 
4103  int success = 1;
4104  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4105  in.open (filename.c_str ()); // Destructor closes safely
4106  if (! in) {
4107  success = 0;
4108  }
4109  }
4110  broadcast<int, int> (*comm, 0, inOutArg (success));
4111  TEUCHOS_TEST_FOR_EXCEPTION(
4112  success == 0, std::runtime_error,
4113  "Tpetra::MatrixMarket::Reader::readMapFile: "
4114  "Failed to read file \"" << filename << "\" on Process 0.");
4115  return readMap (in, comm, tolerant, debug);
4116  }
4117 
4118 
4119  private:
4120  template<class MultiVectorScalarType>
4121  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4124  node_type> >
4125  readDenseImpl (std::istream& in,
4126  const Teuchos::RCP<const comm_type>& comm,
4127  Teuchos::RCP<const map_type>& map,
4128  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4129  const bool tolerant=false,
4130  const bool debug=false)
4131  {
4132  using Teuchos::MatrixMarket::Banner;
4133  using Teuchos::MatrixMarket::checkCommentLine;
4134  using Teuchos::ArrayRCP;
4135  using Teuchos::as;
4136  using Teuchos::broadcast;
4137  using Teuchos::outArg;
4138  using Teuchos::RCP;
4139  using Teuchos::Tuple;
4140  using std::endl;
4141  typedef MultiVectorScalarType ST;
4142  typedef local_ordinal_type LO;
4143  typedef global_ordinal_type GO;
4144  typedef node_type NT;
4145  typedef Teuchos::ScalarTraits<ST> STS;
4146  typedef typename STS::magnitudeType MT;
4147  typedef Teuchos::ScalarTraits<MT> STM;
4149 
4150  // Rank 0 is the only (MPI) process allowed to read from the
4151  // input stream.
4152  const int myRank = comm->getRank ();
4153 
4154  if (! err.is_null ()) {
4155  err->pushTab ();
4156  }
4157  if (debug) {
4158  *err << myRank << ": readDenseImpl" << endl;
4159  }
4160  if (! err.is_null ()) {
4161  err->pushTab ();
4162  }
4163 
4164  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4165  // instances be identical and that the Node instances be
4166  // identical. The essential condition is more complicated to
4167  // test and isn't the same for all Node types. Thus, we just
4168  // leave it up to the user.
4169 
4170  // // If map is nonnull, check the precondition that its
4171  // // communicator resp. node equal comm resp. node. Checking
4172  // // now avoids doing a lot of file reading before we detect the
4173  // // violated precondition.
4174  // TEUCHOS_TEST_FOR_EXCEPTION(
4175  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4176  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4177  // "communicator and node must equal the supplied communicator resp. "
4178  // "node.");
4179 
4180  // Process 0 will read in the matrix dimensions from the file,
4181  // and broadcast them to all ranks in the given communicator.
4182  // There are only 2 dimensions in the matrix, but we use the
4183  // third element of the Tuple to encode the banner's reported
4184  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4185  // (same as "real"). We don't allow pattern matrices (i.e.,
4186  // graphs) since they only make sense for sparse data.
4187  Tuple<GO, 3> dims;
4188  dims[0] = 0;
4189  dims[1] = 0;
4190 
4191  // Current line number in the input stream. Only valid on
4192  // Proc 0. Various calls will modify this depending on the
4193  // number of lines that are read from the input stream.
4194  size_t lineNumber = 1;
4195 
4196  // Capture errors and their messages on Proc 0.
4197  std::ostringstream exMsg;
4198  int localBannerReadSuccess = 1;
4199  int localDimsReadSuccess = 1;
4200 
4201  // Only Proc 0 gets to read matrix data from the input stream.
4202  if (myRank == 0) {
4203  if (debug) {
4204  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4205  }
4206 
4207  // The "Banner" tells you whether the input stream
4208  // represents a dense matrix, the symmetry type of the
4209  // matrix, and the type of the data it contains.
4210  RCP<const Banner> pBanner;
4211  try {
4212  pBanner = readBanner (in, lineNumber, tolerant, debug);
4213  } catch (std::exception& e) {
4214  exMsg << e.what ();
4215  localBannerReadSuccess = 0;
4216  }
4217  // Make sure the input stream is the right kind of data.
4218  if (localBannerReadSuccess) {
4219  if (pBanner->matrixType () != "array") {
4220  exMsg << "The Matrix Market file does not contain dense matrix "
4221  "data. Its banner (first) line says that its matrix type is \""
4222  << pBanner->matrixType () << "\", rather that the required "
4223  "\"array\".";
4224  localBannerReadSuccess = 0;
4225  } else if (pBanner->dataType() == "pattern") {
4226  exMsg << "The Matrix Market file's banner (first) "
4227  "line claims that the matrix's data type is \"pattern\". This does "
4228  "not make sense for a dense matrix, yet the file reports the matrix "
4229  "as dense. The only valid data types for a dense matrix are "
4230  "\"real\", \"complex\", and \"integer\".";
4231  localBannerReadSuccess = 0;
4232  } else {
4233  // Encode the data type reported by the Banner as the
4234  // third element of the dimensions Tuple.
4235  dims[2] = encodeDataType (pBanner->dataType ());
4236  }
4237  } // if we successfully read the banner line
4238 
4239  // At this point, we've successfully read the banner line.
4240  // Now read the dimensions line.
4241  if (localBannerReadSuccess) {
4242  if (debug) {
4243  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4244  }
4245  // Keep reading lines from the input stream until we find
4246  // a non-comment line, or until we run out of lines. The
4247  // latter is an error, since every "array" format Matrix
4248  // Market file must have a dimensions line after the
4249  // banner (even if the matrix has zero rows or columns, or
4250  // zero entries).
4251  std::string line;
4252  bool commentLine = true;
4253 
4254  while (commentLine) {
4255  // Test whether it is even valid to read from the input
4256  // stream wrapping the line.
4257  if (in.eof () || in.fail ()) {
4258  exMsg << "Unable to get array dimensions line (at all) from line "
4259  << lineNumber << " of input stream. The input stream "
4260  << "claims that it is "
4261  << (in.eof() ? "at end-of-file." : "in a failed state.");
4262  localDimsReadSuccess = 0;
4263  } else {
4264  // Try to get the next line from the input stream.
4265  if (getline (in, line)) {
4266  ++lineNumber; // We did actually read a line.
4267  }
4268  // Is the current line a comment line? Ignore start
4269  // and size; they are only useful for reading the
4270  // actual matrix entries. (We could use them here as
4271  // an optimization, but we've chosen not to.)
4272  size_t start = 0, size = 0;
4273  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4274  } // whether we failed to read the line at all
4275  } // while the line we just read is a comment line
4276 
4277  //
4278  // Get <numRows> <numCols> from the line we just read.
4279  //
4280  std::istringstream istr (line);
4281 
4282  // Test whether it is even valid to read from the input
4283  // stream wrapping the line.
4284  if (istr.eof () || istr.fail ()) {
4285  exMsg << "Unable to read any data from line " << lineNumber
4286  << " of input; the line should contain the matrix dimensions "
4287  << "\"<numRows> <numCols>\".";
4288  localDimsReadSuccess = 0;
4289  } else { // It's valid to read from the line.
4290  GO theNumRows = 0;
4291  istr >> theNumRows; // Read in the number of rows.
4292  if (istr.fail ()) {
4293  exMsg << "Failed to get number of rows from line "
4294  << lineNumber << " of input; the line should contains the "
4295  << "matrix dimensions \"<numRows> <numCols>\".";
4296  localDimsReadSuccess = 0;
4297  } else { // We successfully read the number of rows
4298  dims[0] = theNumRows; // Save the number of rows
4299  if (istr.eof ()) { // Do we still have data to read?
4300  exMsg << "No more data after number of rows on line "
4301  << lineNumber << " of input; the line should contain the "
4302  << "matrix dimensions \"<numRows> <numCols>\".";
4303  localDimsReadSuccess = 0;
4304  } else { // Still data left to read; read in number of columns.
4305  GO theNumCols = 0;
4306  istr >> theNumCols; // Read in the number of columns
4307  if (istr.fail ()) {
4308  exMsg << "Failed to get number of columns from line "
4309  << lineNumber << " of input; the line should contain "
4310  << "the matrix dimensions \"<numRows> <numCols>\".";
4311  localDimsReadSuccess = 0;
4312  } else { // We successfully read the number of columns
4313  dims[1] = theNumCols; // Save the number of columns
4314  } // if istr.fail ()
4315  } // if istr.eof ()
4316  } // if we read the number of rows
4317  } // if the input stream wrapping the dims line was (in)valid
4318  } // if we successfully read the banner line
4319  } // if (myRank == 0)
4320 
4321  // Broadcast the matrix dimensions, the encoded data type, and
4322  // whether or not Proc 0 succeeded in reading the banner and
4323  // dimensions.
4324  Tuple<GO, 5> bannerDimsReadResult;
4325  if (myRank == 0) {
4326  bannerDimsReadResult[0] = dims[0]; // numRows
4327  bannerDimsReadResult[1] = dims[1]; // numCols
4328  bannerDimsReadResult[2] = dims[2]; // encoded data type
4329  bannerDimsReadResult[3] = localBannerReadSuccess;
4330  bannerDimsReadResult[4] = localDimsReadSuccess;
4331  }
4332  // Broadcast matrix dimensions and the encoded data type from
4333  // Proc 0 to all the MPI processes.
4334  broadcast (*comm, 0, bannerDimsReadResult);
4335 
4336  TEUCHOS_TEST_FOR_EXCEPTION(
4337  bannerDimsReadResult[3] == 0, std::runtime_error,
4338  "Failed to read banner line: " << exMsg.str ());
4339  TEUCHOS_TEST_FOR_EXCEPTION(
4340  bannerDimsReadResult[4] == 0, std::runtime_error,
4341  "Failed to read matrix dimensions line: " << exMsg.str ());
4342  if (myRank != 0) {
4343  dims[0] = bannerDimsReadResult[0];
4344  dims[1] = bannerDimsReadResult[1];
4345  dims[2] = bannerDimsReadResult[2];
4346  }
4347 
4348  // Tpetra objects want the matrix dimensions in these types.
4349  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4350  const size_t numCols = static_cast<size_t> (dims[1]);
4351 
4352  // Make a "Proc 0 owns everything" Map that we will use to
4353  // read in the multivector entries in the correct order on
4354  // Proc 0. This must be a collective
4355  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4356  if (map.is_null ()) {
4357  // The user didn't supply a Map. Make a contiguous
4358  // distributed Map for them, using the read-in multivector
4359  // dimensions.
4360  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4361  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4362  // At this point, map exists and has a nonnull node.
4363  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4364  comm);
4365  }
4366  else { // The user supplied a Map.
4367  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4368  }
4369 
4370  // Make a multivector X owned entirely by Proc 0.
4371  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4372 
4373  //
4374  // On Proc 0, read the Matrix Market data from the input
4375  // stream into the multivector X.
4376  //
4377  int localReadDataSuccess = 1;
4378  if (myRank == 0) {
4379  try {
4380  if (debug) {
4381  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4382  << endl;
4383  }
4384 
4385  // Make sure that we can get a 1-D view of X.
4386  TEUCHOS_TEST_FOR_EXCEPTION(
4387  ! X->isConstantStride (), std::logic_error,
4388  "Can't get a 1-D view of the entries of the MultiVector X on "
4389  "Process 0, because the stride between the columns of X is not "
4390  "constant. This shouldn't happen because we just created X and "
4391  "haven't filled it in yet. Please report this bug to the Tpetra "
4392  "developers.");
4393 
4394  // Get a writeable 1-D view of the entries of X. Rank 0
4395  // owns all of them. The view will expire at the end of
4396  // scope, so (if necessary) it will be written back to X
4397  // at this time.
4398  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4399  TEUCHOS_TEST_FOR_EXCEPTION(
4400  as<global_size_t> (X_view.size ()) < numRows * numCols,
4401  std::logic_error,
4402  "The view of X has size " << X_view << " which is not enough to "
4403  "accommodate the expected number of entries numRows*numCols = "
4404  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4405  "Please report this bug to the Tpetra developers.");
4406  const size_t stride = X->getStride ();
4407 
4408  // The third element of the dimensions Tuple encodes the data
4409  // type reported by the Banner: "real" == 0, "complex" == 1,
4410  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4411  // allow dense matrices to be pattern matrices, so dims[2] ==
4412  // 0 or 1. We've already checked for this above.
4413  const bool isComplex = (dims[2] == 1);
4414  size_type count = 0, curRow = 0, curCol = 0;
4415 
4416  std::string line;
4417  while (getline (in, line)) {
4418  ++lineNumber;
4419  // Is the current line a comment line? If it's not,
4420  // line.substr(start,size) contains the data.
4421  size_t start = 0, size = 0;
4422  const bool commentLine =
4423  checkCommentLine (line, start, size, lineNumber, tolerant);
4424  if (! commentLine) {
4425  // Make sure we have room in which to put the new matrix
4426  // entry. We check this only after checking for a
4427  // comment line, because there may be one or more
4428  // comment lines at the end of the file. In tolerant
4429  // mode, we simply ignore any extra data.
4430  if (count >= X_view.size()) {
4431  if (tolerant) {
4432  break;
4433  }
4434  else {
4435  TEUCHOS_TEST_FOR_EXCEPTION(
4436  count >= X_view.size(),
4437  std::runtime_error,
4438  "The Matrix Market input stream has more data in it than "
4439  "its metadata reported. Current line number is "
4440  << lineNumber << ".");
4441  }
4442  }
4443 
4444  // mfh 19 Dec 2012: Ignore everything up to the initial
4445  // colon. writeDense() has the option to print out the
4446  // global row index in front of each entry, followed by
4447  // a colon and space.
4448  {
4449  const size_t pos = line.substr (start, size).find (':');
4450  if (pos != std::string::npos) {
4451  start = pos+1;
4452  }
4453  }
4454  std::istringstream istr (line.substr (start, size));
4455  // Does the line contain anything at all? Can we
4456  // safely read from the input stream wrapping the
4457  // line?
4458  if (istr.eof() || istr.fail()) {
4459  // In tolerant mode, simply ignore the line.
4460  if (tolerant) {
4461  break;
4462  }
4463  // We repeat the full test here so the exception
4464  // message is more informative.
4465  TEUCHOS_TEST_FOR_EXCEPTION(
4466  ! tolerant && (istr.eof() || istr.fail()),
4467  std::runtime_error,
4468  "Line " << lineNumber << " of the Matrix Market file is "
4469  "empty, or we cannot read from it for some other reason.");
4470  }
4471  // Current matrix entry to read in.
4472  ST val = STS::zero();
4473  // Real and imaginary parts of the current matrix entry.
4474  // The imaginary part is zero if the matrix is real-valued.
4475  MT real = STM::zero(), imag = STM::zero();
4476 
4477  // isComplex refers to the input stream's data, not to
4478  // the scalar type S. It's OK to read real-valued
4479  // data into a matrix storing complex-valued data; in
4480  // that case, all entries' imaginary parts are zero.
4481  if (isComplex) {
4482  // STS::real() and STS::imag() return a copy of
4483  // their respective components, not a writeable
4484  // reference. Otherwise we could just assign to
4485  // them using the istream extraction operator (>>).
4486  // That's why we have separate magnitude type "real"
4487  // and "imag" variables.
4488 
4489  // Attempt to read the real part of the current entry.
4490  istr >> real;
4491  if (istr.fail()) {
4492  TEUCHOS_TEST_FOR_EXCEPTION(
4493  ! tolerant && istr.eof(), std::runtime_error,
4494  "Failed to get the real part of a complex-valued matrix "
4495  "entry from line " << lineNumber << " of the Matrix Market "
4496  "file.");
4497  // In tolerant mode, just skip bad lines.
4498  if (tolerant) {
4499  break;
4500  }
4501  } else if (istr.eof()) {
4502  TEUCHOS_TEST_FOR_EXCEPTION(
4503  ! tolerant && istr.eof(), std::runtime_error,
4504  "Missing imaginary part of a complex-valued matrix entry "
4505  "on line " << lineNumber << " of the Matrix Market file.");
4506  // In tolerant mode, let any missing imaginary part be 0.
4507  } else {
4508  // Attempt to read the imaginary part of the current
4509  // matrix entry.
4510  istr >> imag;
4511  TEUCHOS_TEST_FOR_EXCEPTION(
4512  ! tolerant && istr.fail(), std::runtime_error,
4513  "Failed to get the imaginary part of a complex-valued "
4514  "matrix entry from line " << lineNumber << " of the "
4515  "Matrix Market file.");
4516  // In tolerant mode, let any missing or corrupted
4517  // imaginary part be 0.
4518  }
4519  } else { // Matrix Market file contains real-valued data.
4520  // Attempt to read the current matrix entry.
4521  istr >> real;
4522  TEUCHOS_TEST_FOR_EXCEPTION(
4523  ! tolerant && istr.fail(), std::runtime_error,
4524  "Failed to get a real-valued matrix entry from line "
4525  << lineNumber << " of the Matrix Market file.");
4526  // In tolerant mode, simply ignore the line if
4527  // we failed to read a matrix entry.
4528  if (istr.fail() && tolerant) {
4529  break;
4530  }
4531  }
4532  // In tolerant mode, we simply let pass through whatever
4533  // data we got.
4534  TEUCHOS_TEST_FOR_EXCEPTION(
4535  ! tolerant && istr.fail(), std::runtime_error,
4536  "Failed to read matrix data from line " << lineNumber
4537  << " of the Matrix Market file.");
4538 
4539  // Assign val = ST(real, imag).
4540  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4541 
4542  curRow = count % numRows;
4543  curCol = count / numRows;
4544  X_view[curRow + curCol*stride] = val;
4545  ++count;
4546  } // if not a comment line
4547  } // while there are still lines in the file, get the next one
4548 
4549  TEUCHOS_TEST_FOR_EXCEPTION(
4550  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4551  std::runtime_error,
4552  "The Matrix Market metadata reports that the dense matrix is "
4553  << numRows << " x " << numCols << ", and thus has "
4554  << numRows*numCols << " total entries, but we only found " << count
4555  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4556  } catch (std::exception& e) {
4557  exMsg << e.what ();
4558  localReadDataSuccess = 0;
4559  }
4560  } // if (myRank == 0)
4561 
4562  if (debug) {
4563  *err << myRank << ": readDenseImpl: done reading data" << endl;
4564  }
4565 
4566  // Synchronize on whether Proc 0 successfully read the data.
4567  int globalReadDataSuccess = localReadDataSuccess;
4568  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4569  TEUCHOS_TEST_FOR_EXCEPTION(
4570  globalReadDataSuccess == 0, std::runtime_error,
4571  "Failed to read the multivector's data: " << exMsg.str ());
4572 
4573  // If there's only one MPI process and the user didn't supply
4574  // a Map (i.e., pMap is null), we're done. Set pMap to the
4575  // Map used to distribute X, and return X.
4576  if (comm->getSize () == 1 && map.is_null ()) {
4577  map = proc0Map;
4578  if (! err.is_null ()) {
4579  err->popTab ();
4580  }
4581  if (debug) {
4582  *err << myRank << ": readDenseImpl: done" << endl;
4583  }
4584  if (! err.is_null ()) {
4585  err->popTab ();
4586  }
4587  return X;
4588  }
4589 
4590  if (debug) {
4591  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4592  }
4593 
4594  // Make a multivector Y with the distributed map pMap.
4595  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4596 
4597  if (debug) {
4598  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4599  }
4600 
4601  // Make an Export object that will export X to Y. First
4602  // argument is the source map, second argument is the target
4603  // map.
4604  Export<LO, GO, NT> exporter (proc0Map, map, err);
4605 
4606  if (debug) {
4607  *err << myRank << ": readDenseImpl: Exporting" << endl;
4608  }
4609  // Export X into Y.
4610  Y->doExport (*X, exporter, INSERT);
4611 
4612  if (! err.is_null ()) {
4613  err->popTab ();
4614  }
4615  if (debug) {
4616  *err << myRank << ": readDenseImpl: done" << endl;
4617  }
4618  if (! err.is_null ()) {
4619  err->popTab ();
4620  }
4621 
4622  // Y is distributed over all process(es) in the communicator.
4623  return Y;
4624  }
4625 
4626 
4627  template<class VectorScalarType>
4628  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4631  node_type> >
4632  readVectorImpl (std::istream& in,
4633  const Teuchos::RCP<const comm_type>& comm,
4634  Teuchos::RCP<const map_type>& map,
4635  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4636  const bool tolerant=false,
4637  const bool debug=false)
4638  {
4639  using Teuchos::MatrixMarket::Banner;
4640  using Teuchos::MatrixMarket::checkCommentLine;
4641  using Teuchos::as;
4642  using Teuchos::broadcast;
4643  using Teuchos::outArg;
4644  using Teuchos::RCP;
4645  using Teuchos::Tuple;
4646  using std::endl;
4647  typedef VectorScalarType ST;
4648  typedef local_ordinal_type LO;
4649  typedef global_ordinal_type GO;
4650  typedef node_type NT;
4651  typedef Teuchos::ScalarTraits<ST> STS;
4652  typedef typename STS::magnitudeType MT;
4653  typedef Teuchos::ScalarTraits<MT> STM;
4654  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4655 
4656  // Rank 0 is the only (MPI) process allowed to read from the
4657  // input stream.
4658  const int myRank = comm->getRank ();
4659 
4660  if (! err.is_null ()) {
4661  err->pushTab ();
4662  }
4663  if (debug) {
4664  *err << myRank << ": readVectorImpl" << endl;
4665  }
4666  if (! err.is_null ()) {
4667  err->pushTab ();
4668  }
4669 
4670  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4671  // instances be identical and that the Node instances be
4672  // identical. The essential condition is more complicated to
4673  // test and isn't the same for all Node types. Thus, we just
4674  // leave it up to the user.
4675 
4676  // // If map is nonnull, check the precondition that its
4677  // // communicator resp. node equal comm resp. node. Checking
4678  // // now avoids doing a lot of file reading before we detect the
4679  // // violated precondition.
4680  // TEUCHOS_TEST_FOR_EXCEPTION(
4681  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4682  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4683  // "communicator and node must equal the supplied communicator resp. "
4684  // "node.");
4685 
4686  // Process 0 will read in the matrix dimensions from the file,
4687  // and broadcast them to all ranks in the given communicator.
4688  // There are only 2 dimensions in the matrix, but we use the
4689  // third element of the Tuple to encode the banner's reported
4690  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4691  // (same as "real"). We don't allow pattern matrices (i.e.,
4692  // graphs) since they only make sense for sparse data.
4693  Tuple<GO, 3> dims;
4694  dims[0] = 0;
4695  dims[1] = 0;
4696 
4697  // Current line number in the input stream. Only valid on
4698  // Proc 0. Various calls will modify this depending on the
4699  // number of lines that are read from the input stream.
4700  size_t lineNumber = 1;
4701 
4702  // Capture errors and their messages on Proc 0.
4703  std::ostringstream exMsg;
4704  int localBannerReadSuccess = 1;
4705  int localDimsReadSuccess = 1;
4706 
4707  // Only Proc 0 gets to read matrix data from the input stream.
4708  if (myRank == 0) {
4709  if (debug) {
4710  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4711  }
4712 
4713  // The "Banner" tells you whether the input stream
4714  // represents a dense matrix, the symmetry type of the
4715  // matrix, and the type of the data it contains.
4716  RCP<const Banner> pBanner;
4717  try {
4718  pBanner = readBanner (in, lineNumber, tolerant, debug);
4719  } catch (std::exception& e) {
4720  exMsg << e.what ();
4721  localBannerReadSuccess = 0;
4722  }
4723  // Make sure the input stream is the right kind of data.
4724  if (localBannerReadSuccess) {
4725  if (pBanner->matrixType () != "array") {
4726  exMsg << "The Matrix Market file does not contain dense matrix "
4727  "data. Its banner (first) line says that its matrix type is \""
4728  << pBanner->matrixType () << "\", rather that the required "
4729  "\"array\".";
4730  localBannerReadSuccess = 0;
4731  } else if (pBanner->dataType() == "pattern") {
4732  exMsg << "The Matrix Market file's banner (first) "
4733  "line claims that the matrix's data type is \"pattern\". This does "
4734  "not make sense for a dense matrix, yet the file reports the matrix "
4735  "as dense. The only valid data types for a dense matrix are "
4736  "\"real\", \"complex\", and \"integer\".";
4737  localBannerReadSuccess = 0;
4738  } else {
4739  // Encode the data type reported by the Banner as the
4740  // third element of the dimensions Tuple.
4741  dims[2] = encodeDataType (pBanner->dataType ());
4742  }
4743  } // if we successfully read the banner line
4744 
4745  // At this point, we've successfully read the banner line.
4746  // Now read the dimensions line.
4747  if (localBannerReadSuccess) {
4748  if (debug) {
4749  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4750  }
4751  // Keep reading lines from the input stream until we find
4752  // a non-comment line, or until we run out of lines. The
4753  // latter is an error, since every "array" format Matrix
4754  // Market file must have a dimensions line after the
4755  // banner (even if the matrix has zero rows or columns, or
4756  // zero entries).
4757  std::string line;
4758  bool commentLine = true;
4759 
4760  while (commentLine) {
4761  // Test whether it is even valid to read from the input
4762  // stream wrapping the line.
4763  if (in.eof () || in.fail ()) {
4764  exMsg << "Unable to get array dimensions line (at all) from line "
4765  << lineNumber << " of input stream. The input stream "
4766  << "claims that it is "
4767  << (in.eof() ? "at end-of-file." : "in a failed state.");
4768  localDimsReadSuccess = 0;
4769  } else {
4770  // Try to get the next line from the input stream.
4771  if (getline (in, line)) {
4772  ++lineNumber; // We did actually read a line.
4773  }
4774  // Is the current line a comment line? Ignore start
4775  // and size; they are only useful for reading the
4776  // actual matrix entries. (We could use them here as
4777  // an optimization, but we've chosen not to.)
4778  size_t start = 0, size = 0;
4779  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4780  } // whether we failed to read the line at all
4781  } // while the line we just read is a comment line
4782 
4783  //
4784  // Get <numRows> <numCols> from the line we just read.
4785  //
4786  std::istringstream istr (line);
4787 
4788  // Test whether it is even valid to read from the input
4789  // stream wrapping the line.
4790  if (istr.eof () || istr.fail ()) {
4791  exMsg << "Unable to read any data from line " << lineNumber
4792  << " of input; the line should contain the matrix dimensions "
4793  << "\"<numRows> <numCols>\".";
4794  localDimsReadSuccess = 0;
4795  } else { // It's valid to read from the line.
4796  GO theNumRows = 0;
4797  istr >> theNumRows; // Read in the number of rows.
4798  if (istr.fail ()) {
4799  exMsg << "Failed to get number of rows from line "
4800  << lineNumber << " of input; the line should contains the "
4801  << "matrix dimensions \"<numRows> <numCols>\".";
4802  localDimsReadSuccess = 0;
4803  } else { // We successfully read the number of rows
4804  dims[0] = theNumRows; // Save the number of rows
4805  if (istr.eof ()) { // Do we still have data to read?
4806  exMsg << "No more data after number of rows on line "
4807  << lineNumber << " of input; the line should contain the "
4808  << "matrix dimensions \"<numRows> <numCols>\".";
4809  localDimsReadSuccess = 0;
4810  } else { // Still data left to read; read in number of columns.
4811  GO theNumCols = 0;
4812  istr >> theNumCols; // Read in the number of columns
4813  if (istr.fail ()) {
4814  exMsg << "Failed to get number of columns from line "
4815  << lineNumber << " of input; the line should contain "
4816  << "the matrix dimensions \"<numRows> <numCols>\".";
4817  localDimsReadSuccess = 0;
4818  } else { // We successfully read the number of columns
4819  dims[1] = theNumCols; // Save the number of columns
4820  } // if istr.fail ()
4821  } // if istr.eof ()
4822  } // if we read the number of rows
4823  } // if the input stream wrapping the dims line was (in)valid
4824  } // if we successfully read the banner line
4825  } // if (myRank == 0)
4826 
4827  // Check if file has a Vector
4828  if (dims[1]!=1) {
4829  exMsg << "File does not contain a 1D Vector";
4830  localDimsReadSuccess = 0;
4831  }
4832 
4833  // Broadcast the matrix dimensions, the encoded data type, and
4834  // whether or not Proc 0 succeeded in reading the banner and
4835  // dimensions.
4836  Tuple<GO, 5> bannerDimsReadResult;
4837  if (myRank == 0) {
4838  bannerDimsReadResult[0] = dims[0]; // numRows
4839  bannerDimsReadResult[1] = dims[1]; // numCols
4840  bannerDimsReadResult[2] = dims[2]; // encoded data type
4841  bannerDimsReadResult[3] = localBannerReadSuccess;
4842  bannerDimsReadResult[4] = localDimsReadSuccess;
4843  }
4844 
4845  // Broadcast matrix dimensions and the encoded data type from
4846  // Proc 0 to all the MPI processes.
4847  broadcast (*comm, 0, bannerDimsReadResult);
4848 
4849  TEUCHOS_TEST_FOR_EXCEPTION(
4850  bannerDimsReadResult[3] == 0, std::runtime_error,
4851  "Failed to read banner line: " << exMsg.str ());
4852  TEUCHOS_TEST_FOR_EXCEPTION(
4853  bannerDimsReadResult[4] == 0, std::runtime_error,
4854  "Failed to read matrix dimensions line: " << exMsg.str ());
4855  if (myRank != 0) {
4856  dims[0] = bannerDimsReadResult[0];
4857  dims[1] = bannerDimsReadResult[1];
4858  dims[2] = bannerDimsReadResult[2];
4859  }
4860 
4861  // Tpetra objects want the matrix dimensions in these types.
4862  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4863  const size_t numCols = static_cast<size_t> (dims[1]);
4864 
4865  // Make a "Proc 0 owns everything" Map that we will use to
4866  // read in the multivector entries in the correct order on
4867  // Proc 0. This must be a collective
4868  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4869  if (map.is_null ()) {
4870  // The user didn't supply a Map. Make a contiguous
4871  // distributed Map for them, using the read-in multivector
4872  // dimensions.
4873  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4874  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4875  // At this point, map exists and has a nonnull node.
4876  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4877  comm);
4878  }
4879  else { // The user supplied a Map.
4880  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4881  }
4882 
4883  // Make a multivector X owned entirely by Proc 0.
4884  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
4885 
4886  //
4887  // On Proc 0, read the Matrix Market data from the input
4888  // stream into the multivector X.
4889  //
4890  int localReadDataSuccess = 1;
4891  if (myRank == 0) {
4892  try {
4893  if (debug) {
4894  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
4895  << endl;
4896  }
4897 
4898  // Make sure that we can get a 1-D view of X.
4899  TEUCHOS_TEST_FOR_EXCEPTION(
4900  ! X->isConstantStride (), std::logic_error,
4901  "Can't get a 1-D view of the entries of the MultiVector X on "
4902  "Process 0, because the stride between the columns of X is not "
4903  "constant. This shouldn't happen because we just created X and "
4904  "haven't filled it in yet. Please report this bug to the Tpetra "
4905  "developers.");
4906 
4907  // Get a writeable 1-D view of the entries of X. Rank 0
4908  // owns all of them. The view will expire at the end of
4909  // scope, so (if necessary) it will be written back to X
4910  // at this time.
4911  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4912  TEUCHOS_TEST_FOR_EXCEPTION(
4913  as<global_size_t> (X_view.size ()) < numRows * numCols,
4914  std::logic_error,
4915  "The view of X has size " << X_view << " which is not enough to "
4916  "accommodate the expected number of entries numRows*numCols = "
4917  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4918  "Please report this bug to the Tpetra developers.");
4919  const size_t stride = X->getStride ();
4920 
4921  // The third element of the dimensions Tuple encodes the data
4922  // type reported by the Banner: "real" == 0, "complex" == 1,
4923  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4924  // allow dense matrices to be pattern matrices, so dims[2] ==
4925  // 0 or 1. We've already checked for this above.
4926  const bool isComplex = (dims[2] == 1);
4927  size_type count = 0, curRow = 0, curCol = 0;
4928 
4929  std::string line;
4930  while (getline (in, line)) {
4931  ++lineNumber;
4932  // Is the current line a comment line? If it's not,
4933  // line.substr(start,size) contains the data.
4934  size_t start = 0, size = 0;
4935  const bool commentLine =
4936  checkCommentLine (line, start, size, lineNumber, tolerant);
4937  if (! commentLine) {
4938  // Make sure we have room in which to put the new matrix
4939  // entry. We check this only after checking for a
4940  // comment line, because there may be one or more
4941  // comment lines at the end of the file. In tolerant
4942  // mode, we simply ignore any extra data.
4943  if (count >= X_view.size()) {
4944  if (tolerant) {
4945  break;
4946  }
4947  else {
4948  TEUCHOS_TEST_FOR_EXCEPTION(
4949  count >= X_view.size(),
4950  std::runtime_error,
4951  "The Matrix Market input stream has more data in it than "
4952  "its metadata reported. Current line number is "
4953  << lineNumber << ".");
4954  }
4955  }
4956 
4957  // mfh 19 Dec 2012: Ignore everything up to the initial
4958  // colon. writeDense() has the option to print out the
4959  // global row index in front of each entry, followed by
4960  // a colon and space.
4961  {
4962  const size_t pos = line.substr (start, size).find (':');
4963  if (pos != std::string::npos) {
4964  start = pos+1;
4965  }
4966  }
4967  std::istringstream istr (line.substr (start, size));
4968  // Does the line contain anything at all? Can we
4969  // safely read from the input stream wrapping the
4970  // line?
4971  if (istr.eof() || istr.fail()) {
4972  // In tolerant mode, simply ignore the line.
4973  if (tolerant) {
4974  break;
4975  }
4976  // We repeat the full test here so the exception
4977  // message is more informative.
4978  TEUCHOS_TEST_FOR_EXCEPTION(
4979  ! tolerant && (istr.eof() || istr.fail()),
4980  std::runtime_error,
4981  "Line " << lineNumber << " of the Matrix Market file is "
4982  "empty, or we cannot read from it for some other reason.");
4983  }
4984  // Current matrix entry to read in.
4985  ST val = STS::zero();
4986  // Real and imaginary parts of the current matrix entry.
4987  // The imaginary part is zero if the matrix is real-valued.
4988  MT real = STM::zero(), imag = STM::zero();
4989 
4990  // isComplex refers to the input stream's data, not to
4991  // the scalar type S. It's OK to read real-valued
4992  // data into a matrix storing complex-valued data; in
4993  // that case, all entries' imaginary parts are zero.
4994  if (isComplex) {
4995  // STS::real() and STS::imag() return a copy of
4996  // their respective components, not a writeable
4997  // reference. Otherwise we could just assign to
4998  // them using the istream extraction operator (>>).
4999  // That's why we have separate magnitude type "real"
5000  // and "imag" variables.
5001 
5002  // Attempt to read the real part of the current entry.
5003  istr >> real;
5004  if (istr.fail()) {
5005  TEUCHOS_TEST_FOR_EXCEPTION(
5006  ! tolerant && istr.eof(), std::runtime_error,
5007  "Failed to get the real part of a complex-valued matrix "
5008  "entry from line " << lineNumber << " of the Matrix Market "
5009  "file.");
5010  // In tolerant mode, just skip bad lines.
5011  if (tolerant) {
5012  break;
5013  }
5014  } else if (istr.eof()) {
5015  TEUCHOS_TEST_FOR_EXCEPTION(
5016  ! tolerant && istr.eof(), std::runtime_error,
5017  "Missing imaginary part of a complex-valued matrix entry "
5018  "on line " << lineNumber << " of the Matrix Market file.");
5019  // In tolerant mode, let any missing imaginary part be 0.
5020  } else {
5021  // Attempt to read the imaginary part of the current
5022  // matrix entry.
5023  istr >> imag;
5024  TEUCHOS_TEST_FOR_EXCEPTION(
5025  ! tolerant && istr.fail(), std::runtime_error,
5026  "Failed to get the imaginary part of a complex-valued "
5027  "matrix entry from line " << lineNumber << " of the "
5028  "Matrix Market file.");
5029  // In tolerant mode, let any missing or corrupted
5030  // imaginary part be 0.
5031  }
5032  } else { // Matrix Market file contains real-valued data.
5033  // Attempt to read the current matrix entry.
5034  istr >> real;
5035  TEUCHOS_TEST_FOR_EXCEPTION(
5036  ! tolerant && istr.fail(), std::runtime_error,
5037  "Failed to get a real-valued matrix entry from line "
5038  << lineNumber << " of the Matrix Market file.");
5039  // In tolerant mode, simply ignore the line if
5040  // we failed to read a matrix entry.
5041  if (istr.fail() && tolerant) {
5042  break;
5043  }
5044  }
5045  // In tolerant mode, we simply let pass through whatever
5046  // data we got.
5047  TEUCHOS_TEST_FOR_EXCEPTION(
5048  ! tolerant && istr.fail(), std::runtime_error,
5049  "Failed to read matrix data from line " << lineNumber
5050  << " of the Matrix Market file.");
5051 
5052  // Assign val = ST(real, imag).
5053  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5054 
5055  curRow = count % numRows;
5056  curCol = count / numRows;
5057  X_view[curRow + curCol*stride] = val;
5058  ++count;
5059  } // if not a comment line
5060  } // while there are still lines in the file, get the next one
5061 
5062  TEUCHOS_TEST_FOR_EXCEPTION(
5063  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5064  std::runtime_error,
5065  "The Matrix Market metadata reports that the dense matrix is "
5066  << numRows << " x " << numCols << ", and thus has "
5067  << numRows*numCols << " total entries, but we only found " << count
5068  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5069  } catch (std::exception& e) {
5070  exMsg << e.what ();
5071  localReadDataSuccess = 0;
5072  }
5073  } // if (myRank == 0)
5074 
5075  if (debug) {
5076  *err << myRank << ": readVectorImpl: done reading data" << endl;
5077  }
5078 
5079  // Synchronize on whether Proc 0 successfully read the data.
5080  int globalReadDataSuccess = localReadDataSuccess;
5081  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5082  TEUCHOS_TEST_FOR_EXCEPTION(
5083  globalReadDataSuccess == 0, std::runtime_error,
5084  "Failed to read the multivector's data: " << exMsg.str ());
5085 
5086  // If there's only one MPI process and the user didn't supply
5087  // a Map (i.e., pMap is null), we're done. Set pMap to the
5088  // Map used to distribute X, and return X.
5089  if (comm->getSize () == 1 && map.is_null ()) {
5090  map = proc0Map;
5091  if (! err.is_null ()) {
5092  err->popTab ();
5093  }
5094  if (debug) {
5095  *err << myRank << ": readVectorImpl: done" << endl;
5096  }
5097  if (! err.is_null ()) {
5098  err->popTab ();
5099  }
5100  return X;
5101  }
5102 
5103  if (debug) {
5104  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5105  }
5106 
5107  // Make a multivector Y with the distributed map pMap.
5108  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5109 
5110  if (debug) {
5111  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5112  }
5113 
5114  // Make an Export object that will export X to Y. First
5115  // argument is the source map, second argument is the target
5116  // map.
5117  Export<LO, GO, NT> exporter (proc0Map, map, err);
5118 
5119  if (debug) {
5120  *err << myRank << ": readVectorImpl: Exporting" << endl;
5121  }
5122  // Export X into Y.
5123  Y->doExport (*X, exporter, INSERT);
5124 
5125  if (! err.is_null ()) {
5126  err->popTab ();
5127  }
5128  if (debug) {
5129  *err << myRank << ": readVectorImpl: done" << endl;
5130  }
5131  if (! err.is_null ()) {
5132  err->popTab ();
5133  }
5134 
5135  // Y is distributed over all process(es) in the communicator.
5136  return Y;
5137  }
5138 
5139  public:
5159  static Teuchos::RCP<const map_type>
5160  readMap (std::istream& in,
5161  const Teuchos::RCP<const comm_type>& comm,
5162  const bool tolerant=false,
5163  const bool debug=false)
5164  {
5165  Teuchos::RCP<Teuchos::FancyOStream> err =
5166  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5167  return readMap (in, comm, err, tolerant, debug);
5168  }
5169 
5170 
5196  static Teuchos::RCP<const map_type>
5197  readMap (std::istream& in,
5198  const Teuchos::RCP<const comm_type>& comm,
5199  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5200  const bool tolerant=false,
5201  const bool debug=false)
5202  {
5203  using Teuchos::arcp;
5204  using Teuchos::Array;
5205  using Teuchos::ArrayRCP;
5206  using Teuchos::as;
5207  using Teuchos::broadcast;
5208  using Teuchos::Comm;
5209  using Teuchos::CommRequest;
5210  using Teuchos::inOutArg;
5211  using Teuchos::ireceive;
5212  using Teuchos::outArg;
5213  using Teuchos::RCP;
5214  using Teuchos::receive;
5215  using Teuchos::reduceAll;
5216  using Teuchos::REDUCE_MIN;
5217  using Teuchos::isend;
5218  using Teuchos::SerialComm;
5219  using Teuchos::toString;
5220  using Teuchos::wait;
5221  using std::endl;
5222  typedef Tpetra::global_size_t GST;
5223  typedef ptrdiff_t int_type; // Can hold int and GO
5224  typedef local_ordinal_type LO;
5225  typedef global_ordinal_type GO;
5226  typedef node_type NT;
5228 
5229  const int numProcs = comm->getSize ();
5230  const int myRank = comm->getRank ();
5231 
5232  if (err.is_null ()) {
5233  err->pushTab ();
5234  }
5235  if (debug) {
5236  std::ostringstream os;
5237  os << myRank << ": readMap: " << endl;
5238  *err << os.str ();
5239  }
5240  if (err.is_null ()) {
5241  err->pushTab ();
5242  }
5243 
5244  // Tag for receive-size / send-size messages. writeMap used
5245  // tags 1337 and 1338; we count up from there.
5246  const int sizeTag = 1339;
5247  // Tag for receive-data / send-data messages.
5248  const int dataTag = 1340;
5249 
5250  // These are for sends on Process 0, and for receives on all
5251  // other processes. sizeReq is for the {receive,send}-size
5252  // message, and dataReq is for the message containing the
5253  // actual GIDs to belong to the receiving process.
5254  RCP<CommRequest<int> > sizeReq;
5255  RCP<CommRequest<int> > dataReq;
5256 
5257  // Each process will have to receive the number of GIDs to
5258  // expect. Thus, we can post the receives now, and cancel
5259  // them if something should go wrong in the meantime.
5260  ArrayRCP<int_type> numGidsToRecv (1);
5261  numGidsToRecv[0] = 0;
5262  if (myRank != 0) {
5263  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5264  }
5265 
5266  int readSuccess = 1;
5267  std::ostringstream exMsg;
5268  RCP<MV> data; // Will only be valid on Proc 0
5269  if (myRank == 0) {
5270  // If we want to reuse readDenseImpl, we have to make a
5271  // communicator that only contains Proc 0. Otherwise,
5272  // readDenseImpl will redistribute the data to all
5273  // processes. While we eventually want that, neither we nor
5274  // readDenseImpl know the correct Map to use at the moment.
5275  // That depends on the second column of the multivector.
5276  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5277  try {
5278  RCP<const map_type> dataMap;
5279  // This is currently the only place where we use the
5280  // 'tolerant' argument. Later, if we want to be clever,
5281  // we could have tolerant mode allow PIDs out of order.
5282  data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug);
5283  (void) dataMap; // Silence "unused" warnings
5284  if (data.is_null ()) {
5285  readSuccess = 0;
5286  exMsg << "readDenseImpl() returned null." << endl;
5287  }
5288  } catch (std::exception& e) {
5289  readSuccess = 0;
5290  exMsg << e.what () << endl;
5291  }
5292  }
5293 
5294  // Map from PID to all the GIDs for that PID.
5295  // Only populated on Process 0.
5296  std::map<int, Array<GO> > pid2gids;
5297 
5298  // The index base must be the global minimum GID.
5299  // We will compute this on Process 0 and broadcast,
5300  // so that all processes can set up the Map.
5301  int_type globalNumGIDs = 0;
5302 
5303  // The index base must be the global minimum GID.
5304  // We will compute this on Process 0 and broadcast,
5305  // so that all processes can set up the Map.
5306  GO indexBase = 0;
5307 
5308  // Process 0: If the above read of the MultiVector succeeded,
5309  // extract the GIDs and PIDs into pid2gids, and find the
5310  // global min GID.
5311  if (myRank == 0 && readSuccess == 1) {
5312  if (data->getNumVectors () == 2) { // Map format 1.0
5313  ArrayRCP<const GO> GIDs = data->getData (0);
5314  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5315  globalNumGIDs = GIDs.size ();
5316 
5317  // Start computing the global min GID, while collecting
5318  // the GIDs for each PID.
5319  if (globalNumGIDs > 0) {
5320  const int pid = static_cast<int> (PIDs[0]);
5321 
5322  if (pid < 0 || pid >= numProcs) {
5323  readSuccess = 0;
5324  exMsg << "Tpetra::MatrixMarket::readMap: "
5325  << "Encountered invalid PID " << pid << "." << endl;
5326  }
5327  else {
5328  const GO gid = GIDs[0];
5329  pid2gids[pid].push_back (gid);
5330  indexBase = gid; // the current min GID
5331  }
5332  }
5333  if (readSuccess == 1) {
5334  // Collect the rest of the GIDs for each PID, and compute
5335  // the global min GID.
5336  for (size_type k = 1; k < globalNumGIDs; ++k) {
5337  const int pid = static_cast<int> (PIDs[k]);
5338  if (pid < 0 || pid >= numProcs) {
5339  readSuccess = 0;
5340  exMsg << "Tpetra::MatrixMarket::readMap: "
5341  << "Encountered invalid PID " << pid << "." << endl;
5342  }
5343  else {
5344  const int_type gid = GIDs[k];
5345  pid2gids[pid].push_back (gid);
5346  if (gid < indexBase) {
5347  indexBase = gid; // the current min GID
5348  }
5349  }
5350  }
5351  }
5352  }
5353  else if (data->getNumVectors () == 1) { // Map format 2.0
5354  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5355  readSuccess = 0;
5356  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5357  "wrong format (for Map format 2.0). The global number of rows "
5358  "in the MultiVector must be even (divisible by 2)." << endl;
5359  }
5360  else {
5361  ArrayRCP<const GO> theData = data->getData (0);
5362  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5363  static_cast<GO> (2);
5364 
5365  // Start computing the global min GID, while
5366  // collecting the GIDs for each PID.
5367  if (globalNumGIDs > 0) {
5368  const int pid = static_cast<int> (theData[1]);
5369  if (pid < 0 || pid >= numProcs) {
5370  readSuccess = 0;
5371  exMsg << "Tpetra::MatrixMarket::readMap: "
5372  << "Encountered invalid PID " << pid << "." << endl;
5373  }
5374  else {
5375  const GO gid = theData[0];
5376  pid2gids[pid].push_back (gid);
5377  indexBase = gid; // the current min GID
5378  }
5379  }
5380  // Collect the rest of the GIDs for each PID, and
5381  // compute the global min GID.
5382  for (int_type k = 1; k < globalNumGIDs; ++k) {
5383  const int pid = static_cast<int> (theData[2*k + 1]);
5384  if (pid < 0 || pid >= numProcs) {
5385  readSuccess = 0;
5386  exMsg << "Tpetra::MatrixMarket::readMap: "
5387  << "Encountered invalid PID " << pid << "." << endl;
5388  }
5389  else {
5390  const GO gid = theData[2*k];
5391  pid2gids[pid].push_back (gid);
5392  if (gid < indexBase) {
5393  indexBase = gid; // the current min GID
5394  }
5395  }
5396  } // for each GID
5397  } // if the amount of data is correct
5398  }
5399  else {
5400  readSuccess = 0;
5401  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5402  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5403  "the old Map format 1.0).";
5404  }
5405  } // myRank is zero
5406 
5407  // Broadcast the indexBase, the global number of GIDs, and the
5408  // current success status. Use int_type for all of these.
5409  {
5410  int_type readResults[3];
5411  readResults[0] = static_cast<int_type> (indexBase);
5412  readResults[1] = static_cast<int_type> (globalNumGIDs);
5413  readResults[2] = static_cast<int_type> (readSuccess);
5414  broadcast<int, int_type> (*comm, 0, 3, readResults);
5415 
5416  indexBase = static_cast<GO> (readResults[0]);
5417  globalNumGIDs = static_cast<int_type> (readResults[1]);
5418  readSuccess = static_cast<int> (readResults[2]);
5419  }
5420 
5421  // Unwinding the stack will invoke sizeReq's destructor, which
5422  // will cancel the receive-size request on all processes that
5423  // posted it.
5424  TEUCHOS_TEST_FOR_EXCEPTION(
5425  readSuccess != 1, std::runtime_error,
5426  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5427  "following exception message: " << exMsg.str ());
5428 
5429  if (myRank == 0) {
5430  // Proc 0: Send each process' number of GIDs to that process.
5431  for (int p = 1; p < numProcs; ++p) {
5432  ArrayRCP<int_type> numGidsToSend (1);
5433 
5434  auto it = pid2gids.find (p);
5435  if (it == pid2gids.end ()) {
5436  numGidsToSend[0] = 0;
5437  } else {
5438  numGidsToSend[0] = it->second.size ();
5439  }
5440  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5441  wait<int> (*comm, outArg (sizeReq));
5442  }
5443  }
5444  else {
5445  // Wait on the receive-size message to finish.
5446  wait<int> (*comm, outArg (sizeReq));
5447  }
5448 
5449  // Allocate / get the array for my GIDs.
5450  // Only Process 0 will have its actual GIDs at this point.
5451  ArrayRCP<GO> myGids;
5452  int_type myNumGids = 0;
5453  if (myRank == 0) {
5454  GO* myGidsRaw = NULL;
5455 
5456  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5457  if (it != pid2gids.end ()) {
5458  myGidsRaw = it->second.getRawPtr ();
5459  myNumGids = it->second.size ();
5460  // Nonowning ArrayRCP just views the Array.
5461  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5462  }
5463  }
5464  else { // myRank != 0
5465  myNumGids = numGidsToRecv[0];
5466  myGids = arcp<GO> (myNumGids);
5467  }
5468 
5469  if (myRank != 0) {
5470  // Post receive for data, now that we know how much data we
5471  // will receive. Only post receive if my process actually
5472  // has nonzero GIDs.
5473  if (myNumGids > 0) {
5474  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5475  }
5476  }
5477 
5478  for (int p = 1; p < numProcs; ++p) {
5479  if (myRank == 0) {
5480  ArrayRCP<GO> sendGids; // to send to Process p
5481  GO* sendGidsRaw = NULL;
5482  int_type numSendGids = 0;
5483 
5484  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5485  if (it != pid2gids.end ()) {
5486  numSendGids = it->second.size ();
5487  sendGidsRaw = it->second.getRawPtr ();
5488  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5489  }
5490  // Only send if that process actually has nonzero GIDs.
5491  if (numSendGids > 0) {
5492  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5493  }
5494  wait<int> (*comm, outArg (dataReq));
5495  }
5496  else if (myRank == p) {
5497  // Wait on my receive of GIDs to finish.
5498  wait<int> (*comm, outArg (dataReq));
5499  }
5500  } // for each process rank p in 1, 2, ..., numProcs-1
5501 
5502  if (debug) {
5503  std::ostringstream os;
5504  os << myRank << ": readMap: creating Map" << endl;
5505  *err << os.str ();
5506  }
5507  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5508  RCP<const map_type> newMap;
5509 
5510  // Create the Map; test whether the constructor threw. This
5511  // avoids deadlock and makes error reporting more readable.
5512 
5513  int lclSuccess = 1;
5514  int gblSuccess = 0; // output argument
5515  std::ostringstream errStrm;
5516  try {
5517  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5518  }
5519  catch (std::exception& e) {
5520  lclSuccess = 0;
5521  errStrm << "Process " << comm->getRank () << " threw an exception: "
5522  << e.what () << std::endl;
5523  }
5524  catch (...) {
5525  lclSuccess = 0;
5526  errStrm << "Process " << comm->getRank () << " threw an exception "
5527  "not a subclass of std::exception" << std::endl;
5528  }
5529  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5530  lclSuccess, Teuchos::outArg (gblSuccess));
5531  if (gblSuccess != 1) {
5532  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5533  }
5534  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5535 
5536  if (err.is_null ()) {
5537  err->popTab ();
5538  }
5539  if (debug) {
5540  std::ostringstream os;
5541  os << myRank << ": readMap: done" << endl;
5542  *err << os.str ();
5543  }
5544  if (err.is_null ()) {
5545  err->popTab ();
5546  }
5547  return newMap;
5548  }
5549 
5550 
5551  private:
5552 
5563  static int
5564  encodeDataType (const std::string& dataType)
5565  {
5566  if (dataType == "real" || dataType == "integer") {
5567  return 0;
5568  } else if (dataType == "complex") {
5569  return 1;
5570  } else if (dataType == "pattern") {
5571  return 2;
5572  } else {
5573  // We should never get here, since Banner validates the
5574  // reported data type and ensures it is one of the accepted
5575  // values.
5576  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5577  "Unrecognized Matrix Market data type \"" << dataType
5578  << "\". We should never get here. "
5579  "Please report this bug to the Tpetra developers.");
5580  }
5581  }
5582  };
5583 
5612  template<class SparseMatrixType>
5613  class Writer {
5614  public:
5616  typedef SparseMatrixType sparse_matrix_type;
5617  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5618 
5620  typedef typename SparseMatrixType::scalar_type scalar_type;
5622  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5628  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5630  typedef typename SparseMatrixType::node_type node_type;
5631 
5633  typedef MultiVector<scalar_type,
5641 
5644 
5676  static void
5677  writeSparseFile (const std::string& filename,
5678  const sparse_matrix_type& matrix,
5679  const std::string& matrixName,
5680  const std::string& matrixDescription,
5681  const bool debug=false)
5682  {
5683  Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
5684  TEUCHOS_TEST_FOR_EXCEPTION
5685  (comm.is_null (), std::invalid_argument,
5686  "The input matrix's communicator (Teuchos::Comm object) is null.");
5687  const int myRank = comm->getRank ();
5688  std::ofstream out;
5689 
5690  // Only open the file on Rank 0.
5691  if (myRank == 0) {
5692  out.open (filename.c_str ());
5693  }
5694  writeSparse (out, matrix, matrixName, matrixDescription, debug);
5695  // We can rely on the destructor of the output stream to close
5696  // the file on scope exit, even if writeSparse() throws an
5697  // exception.
5698  }
5699 
5701  static void
5702  writeSparseFile (const std::string& filename,
5703  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5704  const std::string& matrixName,
5705  const std::string& matrixDescription,
5706  const bool debug=false)
5707  {
5708  TEUCHOS_TEST_FOR_EXCEPTION
5709  (pMatrix.is_null (), std::invalid_argument,
5710  "The input matrix is null.");
5711  writeSparseFile (filename, *pMatrix, matrixName,
5712  matrixDescription, debug);
5713  }
5714 
5734  static void
5735  writeSparseFile (const std::string& filename,
5736  const sparse_matrix_type& matrix,
5737  const bool debug=false)
5738  {
5739  writeSparseFile (filename, matrix, "", "", debug);
5740  }
5741 
5743  static void
5744  writeSparseFile (const std::string& filename,
5745  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5746  const bool debug=false)
5747  {
5748  writeSparseFile (filename, *pMatrix, "", "", debug);
5749  }
5750 
5781  static void
5782  writeSparse (std::ostream& out,
5783  const sparse_matrix_type& matrix,
5784  const std::string& matrixName,
5785  const std::string& matrixDescription,
5786  const bool debug=false)
5787  {
5788  using Teuchos::ArrayView;
5789  using Teuchos::Comm;
5790  using Teuchos::FancyOStream;
5791  using Teuchos::getFancyOStream;
5792  using Teuchos::null;
5793  using Teuchos::RCP;
5794  using Teuchos::rcpFromRef;
5795  using std::cerr;
5796  using std::endl;
5797  using ST = scalar_type;
5798  using LO = local_ordinal_type;
5799  using GO = global_ordinal_type;
5800  using STS = typename Teuchos::ScalarTraits<ST>;
5801 
5802  // Make the output stream write floating-point numbers in
5803  // scientific notation. It will politely put the output
5804  // stream back to its state on input, when this scope
5805  // terminates.
5806  Teuchos::SetScientific<ST> sci (out);
5807 
5808  // Get the matrix's communicator.
5809  RCP<const Comm<int> > comm = matrix.getComm ();
5810  TEUCHOS_TEST_FOR_EXCEPTION(
5811  comm.is_null (), std::invalid_argument,
5812  "The input matrix's communicator (Teuchos::Comm object) is null.");
5813  const int myRank = comm->getRank ();
5814 
5815  // Optionally, make a stream for debugging output.
5816  RCP<FancyOStream> err =
5817  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
5818  if (debug) {
5819  std::ostringstream os;
5820  os << myRank << ": writeSparse" << endl;
5821  *err << os.str ();
5822  comm->barrier ();
5823  os << "-- " << myRank << ": past barrier" << endl;
5824  *err << os.str ();
5825  }
5826 
5827  // Whether to print debugging output to stderr.
5828  const bool debugPrint = debug && myRank == 0;
5829 
5830  RCP<const map_type> rowMap = matrix.getRowMap ();
5831  RCP<const map_type> colMap = matrix.getColMap ();
5832  RCP<const map_type> domainMap = matrix.getDomainMap ();
5833  RCP<const map_type> rangeMap = matrix.getRangeMap ();
5834 
5835  const global_size_t numRows = rangeMap->getGlobalNumElements ();
5836  const global_size_t numCols = domainMap->getGlobalNumElements ();
5837 
5838  if (debug && myRank == 0) {
5839  std::ostringstream os;
5840  os << "-- Input sparse matrix is:"
5841  << "---- " << numRows << " x " << numCols << endl
5842  << "---- "
5843  << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
5844  << " indexed." << endl
5845  << "---- Its row map has " << rowMap->getGlobalNumElements ()
5846  << " elements." << endl
5847  << "---- Its col map has " << colMap->getGlobalNumElements ()
5848  << " elements." << endl;
5849  *err << os.str ();
5850  }
5851  // Make the "gather" row map, where Proc 0 owns all rows and
5852  // the other procs own no rows.
5853  const size_t localNumRows = (myRank == 0) ? numRows : 0;
5854  if (debug) {
5855  std::ostringstream os;
5856  os << "-- " << myRank << ": making gatherRowMap" << endl;
5857  *err << os.str ();
5858  }
5859  RCP<const map_type> gatherRowMap =
5860  Details::computeGatherMap (rowMap, err, debug);
5861 
5862  // Since the matrix may in general be non-square, we need to
5863  // make a column map as well. In this case, the column map
5864  // contains all the columns of the original matrix, because we
5865  // are gathering the whole matrix onto Proc 0. We call
5866  // computeGatherMap to preserve the original order of column
5867  // indices over all the processes.
5868  const size_t localNumCols = (myRank == 0) ? numCols : 0;
5869  RCP<const map_type> gatherColMap =
5870  Details::computeGatherMap (colMap, err, debug);
5871 
5872  // Current map is the source map, gather map is the target map.
5873  typedef Import<LO, GO, node_type> import_type;
5874  import_type importer (rowMap, gatherRowMap);
5875 
5876  // Create a new CrsMatrix to hold the result of the import.
5877  // The constructor needs a column map as well as a row map,
5878  // for the case that the matrix is not square.
5879  RCP<sparse_matrix_type> newMatrix =
5880  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
5881  static_cast<size_t> (0)));
5882  // Import the sparse matrix onto Proc 0.
5883  newMatrix->doImport (matrix, importer, INSERT);
5884 
5885  // fillComplete() needs the domain and range maps for the case
5886  // that the matrix is not square.
5887  {
5888  RCP<const map_type> gatherDomainMap =
5889  rcp (new map_type (numCols, localNumCols,
5890  domainMap->getIndexBase (),
5891  comm));
5892  RCP<const map_type> gatherRangeMap =
5893  rcp (new map_type (numRows, localNumRows,
5894  rangeMap->getIndexBase (),
5895  comm));
5896  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
5897  }
5898 
5899  if (debugPrint) {
5900  cerr << "-- Output sparse matrix is:"
5901  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
5902  << " x "
5903  << newMatrix->getDomainMap ()->getGlobalNumElements ()
5904  << " with "
5905  << newMatrix->getGlobalNumEntries () << " entries;" << endl
5906  << "---- "
5907  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
5908  << " indexed." << endl
5909  << "---- Its row map has "
5910  << newMatrix->getRowMap ()->getGlobalNumElements ()
5911  << " elements, with index base "
5912  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
5913  << "---- Its col map has "
5914  << newMatrix->getColMap ()->getGlobalNumElements ()
5915  << " elements, with index base "
5916  << newMatrix->getColMap ()->getIndexBase () << "." << endl
5917  << "---- Element count of output matrix's column Map may differ "
5918  << "from that of the input matrix's column Map, if some columns "
5919  << "of the matrix contain no entries." << endl;
5920  }
5921 
5922  //
5923  // Print the metadata and the matrix entries on Rank 0.
5924  //
5925  if (myRank == 0) {
5926  // Print the Matrix Market banner line. CrsMatrix stores
5927  // data nonsymmetrically ("general"). This implies that
5928  // readSparse() on a symmetrically stored input file,
5929  // followed by writeSparse() on the resulting sparse matrix,
5930  // will result in an output file with a different banner
5931  // line than the original input file.
5932  out << "%%MatrixMarket matrix coordinate "
5933  << (STS::isComplex ? "complex" : "real")
5934  << " general" << endl;
5935 
5936  // Print comments (the matrix name and / or description).
5937  if (matrixName != "") {
5938  printAsComment (out, matrixName);
5939  }
5940  if (matrixDescription != "") {
5941  printAsComment (out, matrixDescription);
5942  }
5943 
5944  // Print the Matrix Market header (# rows, # columns, #
5945  // nonzeros). Use the range resp. domain map for the number
5946  // of rows resp. columns, since Tpetra::CrsMatrix uses the
5947  // column map for the number of columns. That only
5948  // corresponds to the "linear-algebraic" number of columns
5949  // when the column map is uniquely owned (a.k.a. one-to-one),
5950  // which only happens if the matrix is (block) diagonal.
5951  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
5952  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
5953  << newMatrix->getGlobalNumEntries () << endl;
5954 
5955  // The Matrix Market format expects one-based row and column
5956  // indices. We'll convert the indices on output from
5957  // whatever index base they use to one-based indices.
5958  const GO rowIndexBase = gatherRowMap->getIndexBase ();
5959  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
5960  //
5961  // Print the entries of the matrix.
5962  //
5963  // newMatrix can never be globally indexed, since we called
5964  // fillComplete() on it. We include code for both cases
5965  // (globally or locally indexed) just in case that ever
5966  // changes.
5967  if (newMatrix->isGloballyIndexed()) {
5968  // We know that the "gather" row Map is contiguous, so we
5969  // don't need to get the list of GIDs.
5970  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
5971  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
5972  for (GO globalRowIndex = minAllGlobalIndex;
5973  globalRowIndex <= maxAllGlobalIndex; // inclusive range
5974  ++globalRowIndex) {
5975  ArrayView<const GO> ind;
5976  ArrayView<const ST> val;
5977  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
5978  auto indIter = ind.begin ();
5979  auto valIter = val.begin ();
5980  for (; indIter != ind.end() && valIter != val.end();
5981  ++indIter, ++valIter) {
5982  const GO globalColIndex = *indIter;
5983  // Convert row and column indices to 1-based.
5984  // This works because the global index type is signed.
5985  out << (globalRowIndex + 1 - rowIndexBase) << " "
5986  << (globalColIndex + 1 - colIndexBase) << " ";
5987  if (STS::isComplex) {
5988  out << STS::real (*valIter) << " " << STS::imag (*valIter);
5989  } else {
5990  out << *valIter;
5991  }
5992  out << endl;
5993  } // For each entry in the current row
5994  } // For each row of the "gather" matrix
5995  }
5996  else { // newMatrix is locally indexed
5997  using OTG = Teuchos::OrdinalTraits<GO>;
5998  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
5999  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6000  ++localRowIndex) {
6001  // Convert from local to global row index.
6002  const GO globalRowIndex =
6003  gatherRowMap->getGlobalElement (localRowIndex);
6004  TEUCHOS_TEST_FOR_EXCEPTION(
6005  globalRowIndex == OTG::invalid(), std::logic_error,
6006  "Failed to convert the supposed local row index "
6007  << localRowIndex << " into a global row index. "
6008  "Please report this bug to the Tpetra developers.");
6009  ArrayView<const LO> ind;
6010  ArrayView<const ST> val;
6011  newMatrix->getLocalRowView (localRowIndex, ind, val);
6012  auto indIter = ind.begin ();
6013  auto valIter = val.begin ();
6014  for (; indIter != ind.end() && valIter != val.end();
6015  ++indIter, ++valIter) {
6016  // Convert the column index from local to global.
6017  const GO globalColIndex =
6018  newMatrix->getColMap()->getGlobalElement (*indIter);
6019  TEUCHOS_TEST_FOR_EXCEPTION(
6020  globalColIndex == OTG::invalid(), std::logic_error,
6021  "On local row " << localRowIndex << " of the sparse matrix: "
6022  "Failed to convert the supposed local column index "
6023  << *indIter << " into a global column index. Please report "
6024  "this bug to the Tpetra developers.");
6025  // Convert row and column indices to 1-based.
6026  // This works because the global index type is signed.
6027  out << (globalRowIndex + 1 - rowIndexBase) << " "
6028  << (globalColIndex + 1 - colIndexBase) << " ";
6029  if (STS::isComplex) {
6030  out << STS::real (*valIter) << " " << STS::imag (*valIter);
6031  } else {
6032  out << *valIter;
6033  }
6034  out << endl;
6035  } // For each entry in the current row
6036  } // For each row of the "gather" matrix
6037  } // Whether the "gather" matrix is locally or globally indexed
6038  } // If my process' rank is 0
6039  }
6040 
6042  static void
6043  writeSparse (std::ostream& out,
6044  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6045  const std::string& matrixName,
6046  const std::string& matrixDescription,
6047  const bool debug=false)
6048  {
6049  TEUCHOS_TEST_FOR_EXCEPTION
6050  (pMatrix.is_null (), std::invalid_argument,
6051  "The input matrix is null.");
6052  writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6053  }
6054 
6085  static void
6086  writeSparseGraph (std::ostream& out,
6087  const crs_graph_type& graph,
6088  const std::string& graphName,
6089  const std::string& graphDescription,
6090  const bool debug=false)
6091  {
6092  using Teuchos::ArrayView;
6093  using Teuchos::Comm;
6094  using Teuchos::FancyOStream;
6095  using Teuchos::getFancyOStream;
6096  using Teuchos::null;
6097  using Teuchos::RCP;
6098  using Teuchos::rcpFromRef;
6099  using std::cerr;
6100  using std::endl;
6101  typedef local_ordinal_type LO;
6102  typedef global_ordinal_type GO;
6103 
6104  // Get the graph's communicator. Processes on which the
6105  // graph's Map or communicator is null don't participate in
6106  // this operation. This function shouldn't even be called on
6107  // those processes.
6108  auto rowMap = graph.getRowMap ();
6109  if (rowMap.is_null ()) {
6110  return;
6111  }
6112  auto comm = rowMap->getComm ();
6113  if (comm.is_null ()) {
6114  return;
6115  }
6116  const int myRank = comm->getRank ();
6117 
6118  // Optionally, make a stream for debugging output.
6119  RCP<FancyOStream> err =
6120  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6121  if (debug) {
6122  std::ostringstream os;
6123  os << myRank << ": writeSparseGraph" << endl;
6124  *err << os.str ();
6125  comm->barrier ();
6126  os << "-- " << myRank << ": past barrier" << endl;
6127  *err << os.str ();
6128  }
6129 
6130  // Whether to print debugging output to stderr.
6131  const bool debugPrint = debug && myRank == 0;
6132 
6133  // We've already gotten the rowMap above.
6134  auto colMap = graph.getColMap ();
6135  auto domainMap = graph.getDomainMap ();
6136  auto rangeMap = graph.getRangeMap ();
6137 
6138  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6139  const global_size_t numCols = domainMap->getGlobalNumElements ();
6140 
6141  if (debug && myRank == 0) {
6142  std::ostringstream os;
6143  os << "-- Input sparse graph is:"
6144  << "---- " << numRows << " x " << numCols << " with "
6145  << graph.getGlobalNumEntries () << " entries;" << endl
6146  << "---- "
6147  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6148  << " indexed." << endl
6149  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6150  << " elements." << endl
6151  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6152  << " elements." << endl;
6153  *err << os.str ();
6154  }
6155  // Make the "gather" row map, where Proc 0 owns all rows and
6156  // the other procs own no rows.
6157  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6158  if (debug) {
6159  std::ostringstream os;
6160  os << "-- " << myRank << ": making gatherRowMap" << endl;
6161  *err << os.str ();
6162  }
6163  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6164 
6165  // Since the graph may in general be non-square, we need to
6166  // make a column map as well. In this case, the column map
6167  // contains all the columns of the original graph, because we
6168  // are gathering the whole graph onto Proc 0. We call
6169  // computeGatherMap to preserve the original order of column
6170  // indices over all the processes.
6171  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6172  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6173 
6174  // Current map is the source map, gather map is the target map.
6175  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6176 
6177  // Create a new CrsGraph to hold the result of the import.
6178  // The constructor needs a column map as well as a row map,
6179  // for the case that the graph is not square.
6180  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6181  static_cast<size_t> (0));
6182  // Import the sparse graph onto Proc 0.
6183  newGraph.doImport (graph, importer, INSERT);
6184 
6185  // fillComplete() needs the domain and range maps for the case
6186  // that the graph is not square.
6187  {
6188  RCP<const map_type> gatherDomainMap =
6189  rcp (new map_type (numCols, localNumCols,
6190  domainMap->getIndexBase (),
6191  comm));
6192  RCP<const map_type> gatherRangeMap =
6193  rcp (new map_type (numRows, localNumRows,
6194  rangeMap->getIndexBase (),
6195  comm));
6196  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6197  }
6198 
6199  if (debugPrint) {
6200  cerr << "-- Output sparse graph is:"
6201  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6202  << " x "
6203  << newGraph.getDomainMap ()->getGlobalNumElements ()
6204  << " with "
6205  << newGraph.getGlobalNumEntries () << " entries;" << endl
6206  << "---- "
6207  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6208  << " indexed." << endl
6209  << "---- Its row map has "
6210  << newGraph.getRowMap ()->getGlobalNumElements ()
6211  << " elements, with index base "
6212  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6213  << "---- Its col map has "
6214  << newGraph.getColMap ()->getGlobalNumElements ()
6215  << " elements, with index base "
6216  << newGraph.getColMap ()->getIndexBase () << "." << endl
6217  << "---- Element count of output graph's column Map may differ "
6218  << "from that of the input matrix's column Map, if some columns "
6219  << "of the matrix contain no entries." << endl;
6220  }
6221 
6222  //
6223  // Print the metadata and the graph entries on Process 0 of
6224  // the graph's communicator.
6225  //
6226  if (myRank == 0) {
6227  // Print the Matrix Market banner line. CrsGraph stores
6228  // data nonsymmetrically ("general"). This implies that
6229  // readSparseGraph() on a symmetrically stored input file,
6230  // followed by writeSparseGraph() on the resulting sparse
6231  // graph, will result in an output file with a different
6232  // banner line than the original input file.
6233  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6234 
6235  // Print comments (the graph name and / or description).
6236  if (graphName != "") {
6237  printAsComment (out, graphName);
6238  }
6239  if (graphDescription != "") {
6240  printAsComment (out, graphDescription);
6241  }
6242 
6243  // Print the Matrix Market header (# rows, # columns, #
6244  // stored entries). Use the range resp. domain map for the
6245  // number of rows resp. columns, since Tpetra::CrsGraph uses
6246  // the column map for the number of columns. That only
6247  // corresponds to the "linear-algebraic" number of columns
6248  // when the column map is uniquely owned
6249  // (a.k.a. one-to-one), which only happens if the graph is
6250  // block diagonal (one block per process).
6251  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6252  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6253  << newGraph.getGlobalNumEntries () << endl;
6254 
6255  // The Matrix Market format expects one-based row and column
6256  // indices. We'll convert the indices on output from
6257  // whatever index base they use to one-based indices.
6258  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6259  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6260  //
6261  // Print the entries of the graph.
6262  //
6263  // newGraph can never be globally indexed, since we called
6264  // fillComplete() on it. We include code for both cases
6265  // (globally or locally indexed) just in case that ever
6266  // changes.
6267  if (newGraph.isGloballyIndexed ()) {
6268  // We know that the "gather" row Map is contiguous, so we
6269  // don't need to get the list of GIDs.
6270  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6271  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6272  for (GO globalRowIndex = minAllGlobalIndex;
6273  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6274  ++globalRowIndex) {
6275  ArrayView<const GO> ind;
6276  newGraph.getGlobalRowView (globalRowIndex, ind);
6277  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6278  const GO globalColIndex = *indIter;
6279  // Convert row and column indices to 1-based.
6280  // This works because the global index type is signed.
6281  out << (globalRowIndex + 1 - rowIndexBase) << " "
6282  << (globalColIndex + 1 - colIndexBase) << " ";
6283  out << endl;
6284  } // For each entry in the current row
6285  } // For each row of the "gather" graph
6286  }
6287  else { // newGraph is locally indexed
6288  typedef Teuchos::OrdinalTraits<GO> OTG;
6289  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6290  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6291  ++localRowIndex) {
6292  // Convert from local to global row index.
6293  const GO globalRowIndex =
6294  gatherRowMap->getGlobalElement (localRowIndex);
6295  TEUCHOS_TEST_FOR_EXCEPTION
6296  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6297  "to convert the supposed local row index " << localRowIndex <<
6298  " into a global row index. Please report this bug to the "
6299  "Tpetra developers.");
6300  ArrayView<const LO> ind;
6301  newGraph.getLocalRowView (localRowIndex, ind);
6302  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6303  // Convert the column index from local to global.
6304  const GO globalColIndex =
6305  newGraph.getColMap ()->getGlobalElement (*indIter);
6306  TEUCHOS_TEST_FOR_EXCEPTION(
6307  globalColIndex == OTG::invalid(), std::logic_error,
6308  "On local row " << localRowIndex << " of the sparse graph: "
6309  "Failed to convert the supposed local column index "
6310  << *indIter << " into a global column index. Please report "
6311  "this bug to the Tpetra developers.");
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  } // Whether the "gather" graph is locally or globally indexed
6320  } // If my process' rank is 0
6321  }
6322 
6328  static void
6329  writeSparseGraph (std::ostream& out,
6330  const crs_graph_type& graph,
6331  const bool debug=false)
6332  {
6333  writeSparseGraph (out, graph, "", "", debug);
6334  }
6335 
6370  static void
6371  writeSparseGraphFile (const std::string& filename,
6372  const crs_graph_type& graph,
6373  const std::string& graphName,
6374  const std::string& graphDescription,
6375  const bool debug=false)
6376  {
6377  auto comm = graph.getComm ();
6378  if (comm.is_null ()) {
6379  // Processes on which the communicator is null shouldn't
6380  // even call this function. The convention is that
6381  // processes on which the object's communicator is null do
6382  // not participate in collective operations involving the
6383  // object.
6384  return;
6385  }
6386  const int myRank = comm->getRank ();
6387  std::ofstream out;
6388 
6389  // Only open the file on Process 0.
6390  if (myRank == 0) {
6391  out.open (filename.c_str ());
6392  }
6393  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6394  // We can rely on the destructor of the output stream to close
6395  // the file on scope exit, even if writeSparseGraph() throws
6396  // an exception.
6397  }
6398 
6403  static void
6404  writeSparseGraphFile (const std::string& filename,
6405  const crs_graph_type& graph,
6406  const bool debug=false)
6407  {
6408  writeSparseGraphFile (filename, graph, "", "", debug);
6409  }
6410 
6419  static void
6420  writeSparseGraphFile (const std::string& filename,
6421  const Teuchos::RCP<const crs_graph_type>& pGraph,
6422  const std::string& graphName,
6423  const std::string& graphDescription,
6424  const bool debug=false)
6425  {
6426  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6427  }
6428 
6438  static void
6439  writeSparseGraphFile (const std::string& filename,
6440  const Teuchos::RCP<const crs_graph_type>& pGraph,
6441  const bool debug=false)
6442  {
6443  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6444  }
6445 
6468  static void
6469  writeSparse (std::ostream& out,
6470  const sparse_matrix_type& matrix,
6471  const bool debug=false)
6472  {
6473  writeSparse (out, matrix, "", "", debug);
6474  }
6475 
6477  static void
6478  writeSparse (std::ostream& out,
6479  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6480  const bool debug=false)
6481  {
6482  writeSparse (out, *pMatrix, "", "", debug);
6483  }
6484 
6513  static void
6514  writeDenseFile (const std::string& filename,
6515  const multivector_type& X,
6516  const std::string& matrixName,
6517  const std::string& matrixDescription,
6518  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6519  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6520  {
6521  const int myRank = X.getMap ().is_null () ? 0 :
6522  (X.getMap ()->getComm ().is_null () ? 0 :
6523  X.getMap ()->getComm ()->getRank ());
6524  std::ofstream out;
6525 
6526  if (myRank == 0) { // Only open the file on Process 0.
6527  out.open (filename.c_str());
6528  }
6529 
6530  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6531  // We can rely on the destructor of the output stream to close
6532  // the file on scope exit, even if writeDense() throws an
6533  // exception.
6534  }
6535 
6541  static void
6542  writeDenseFile (const std::string& filename,
6543  const Teuchos::RCP<const multivector_type>& X,
6544  const std::string& matrixName,
6545  const std::string& matrixDescription,
6546  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6547  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6548  {
6549  TEUCHOS_TEST_FOR_EXCEPTION(
6550  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6551  "writeDenseFile: The input MultiVector X is null.");
6552  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6553  }
6554 
6560  static void
6561  writeDenseFile (const std::string& filename,
6562  const multivector_type& X,
6563  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6564  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6565  {
6566  writeDenseFile (filename, X, "", "", err, dbg);
6567  }
6568 
6574  static void
6575  writeDenseFile (const std::string& filename,
6576  const Teuchos::RCP<const multivector_type>& X,
6577  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6578  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6579  {
6580  TEUCHOS_TEST_FOR_EXCEPTION(
6581  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6582  "writeDenseFile: The input MultiVector X is null.");
6583  writeDenseFile (filename, *X, err, dbg);
6584  }
6585 
6586 
6617  static void
6618  writeDense (std::ostream& out,
6619  const multivector_type& X,
6620  const std::string& matrixName,
6621  const std::string& matrixDescription,
6622  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6623  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6624  {
6625  using Teuchos::Comm;
6626  using Teuchos::outArg;
6627  using Teuchos::REDUCE_MAX;
6628  using Teuchos::reduceAll;
6629  using Teuchos::RCP;
6630  using std::endl;
6631 
6632  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6633  Teuchos::null : X.getMap ()->getComm ();
6634  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6635 
6636  // If the caller provides a nonnull debug output stream, we
6637  // print debugging output to it. This is a local thing; we
6638  // don't have to check across processes.
6639  const bool debug = ! dbg.is_null ();
6640  if (debug) {
6641  dbg->pushTab ();
6642  std::ostringstream os;
6643  os << myRank << ": writeDense" << endl;
6644  *dbg << os.str ();
6645  dbg->pushTab ();
6646  }
6647  // Print the Matrix Market header.
6648  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6649 
6650  // Print each column one at a time. This is a (perhaps)
6651  // temporary fix for Bug 6288.
6652  const size_t numVecs = X.getNumVectors ();
6653  for (size_t j = 0; j < numVecs; ++j) {
6654  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6655  }
6656 
6657  if (debug) {
6658  dbg->popTab ();
6659  std::ostringstream os;
6660  os << myRank << ": writeDense: Done" << endl;
6661  *dbg << os.str ();
6662  dbg->popTab ();
6663  }
6664  }
6665 
6666  private:
6667 
6693  static void
6694  writeDenseHeader (std::ostream& out,
6695  const multivector_type& X,
6696  const std::string& matrixName,
6697  const std::string& matrixDescription,
6698  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6699  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6700  {
6701  using Teuchos::Comm;
6702  using Teuchos::outArg;
6703  using Teuchos::RCP;
6704  using Teuchos::REDUCE_MAX;
6705  using Teuchos::reduceAll;
6706  using std::endl;
6707  typedef Teuchos::ScalarTraits<scalar_type> STS;
6708  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
6709 
6710  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6711  Teuchos::null : X.getMap ()->getComm ();
6712  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6713  int lclErr = 0; // whether this MPI process has seen an error
6714  int gblErr = 0; // whether we know if some MPI process has seen an error
6715 
6716  // If the caller provides a nonnull debug output stream, we
6717  // print debugging output to it. This is a local thing; we
6718  // don't have to check across processes.
6719  const bool debug = ! dbg.is_null ();
6720 
6721  if (debug) {
6722  dbg->pushTab ();
6723  std::ostringstream os;
6724  os << myRank << ": writeDenseHeader" << endl;
6725  *dbg << os.str ();
6726  dbg->pushTab ();
6727  }
6728 
6729  //
6730  // Process 0: Write the MatrixMarket header.
6731  //
6732  if (myRank == 0) {
6733  try {
6734  // Print the Matrix Market header. MultiVector stores data
6735  // nonsymmetrically, hence "general" in the banner line.
6736  // Print first to a temporary string output stream, and then
6737  // write it to the main output stream, so that at least the
6738  // header output has transactional semantics. We can't
6739  // guarantee transactional semantics for the whole output,
6740  // since that would not be memory scalable. (This could be
6741  // done in the file system by using a temporary file; we
6742  // don't do this, but users could.)
6743  std::ostringstream hdr;
6744  {
6745  std::string dataType;
6746  if (STS::isComplex) {
6747  dataType = "complex";
6748  } else if (STS::isOrdinal) {
6749  dataType = "integer";
6750  } else {
6751  dataType = "real";
6752  }
6753  hdr << "%%MatrixMarket matrix array " << dataType << " general"
6754  << endl;
6755  }
6756 
6757  // Print comments (the matrix name and / or description).
6758  if (matrixName != "") {
6759  printAsComment (hdr, matrixName);
6760  }
6761  if (matrixDescription != "") {
6762  printAsComment (hdr, matrixDescription);
6763  }
6764  // Print the Matrix Market dimensions header for dense matrices.
6765  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
6766 
6767  // Write the MatrixMarket header to the output stream.
6768  out << hdr.str ();
6769  } catch (std::exception& e) {
6770  if (! err.is_null ()) {
6771  *err << prefix << "While writing the Matrix Market header, "
6772  "Process 0 threw an exception: " << e.what () << endl;
6773  }
6774  lclErr = 1;
6775  }
6776  } // if I am Process 0
6777 
6778  // Establish global agreement on the error state. It wouldn't
6779  // be good for other processes to keep going, if Process 0
6780  // finds out that it can't write to the given output stream.
6781  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
6782  TEUCHOS_TEST_FOR_EXCEPTION(
6783  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
6784  "which prevented this method from completing.");
6785 
6786  if (debug) {
6787  dbg->popTab ();
6788  *dbg << myRank << ": writeDenseHeader: Done" << endl;
6789  dbg->popTab ();
6790  }
6791  }
6792 
6810  static void
6811  writeDenseColumn (std::ostream& out,
6812  const multivector_type& X,
6813  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6814  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6815  {
6816  using Teuchos::arcp;
6817  using Teuchos::Array;
6818  using Teuchos::ArrayRCP;
6819  using Teuchos::ArrayView;
6820  using Teuchos::Comm;
6821  using Teuchos::CommRequest;
6822  using Teuchos::ireceive;
6823  using Teuchos::isend;
6824  using Teuchos::outArg;
6825  using Teuchos::REDUCE_MAX;
6826  using Teuchos::reduceAll;
6827  using Teuchos::RCP;
6828  using Teuchos::TypeNameTraits;
6829  using Teuchos::wait;
6830  using std::endl;
6831  typedef Teuchos::ScalarTraits<scalar_type> STS;
6832 
6833  const Comm<int>& comm = * (X.getMap ()->getComm ());
6834  const int myRank = comm.getRank ();
6835  const int numProcs = comm.getSize ();
6836  int lclErr = 0; // whether this MPI process has seen an error
6837  int gblErr = 0; // whether we know if some MPI process has seen an error
6838 
6839  // If the caller provides a nonnull debug output stream, we
6840  // print debugging output to it. This is a local thing; we
6841  // don't have to check across processes.
6842  const bool debug = ! dbg.is_null ();
6843 
6844  if (debug) {
6845  dbg->pushTab ();
6846  std::ostringstream os;
6847  os << myRank << ": writeDenseColumn" << endl;
6848  *dbg << os.str ();
6849  dbg->pushTab ();
6850  }
6851 
6852  // Make the output stream write floating-point numbers in
6853  // scientific notation. It will politely put the output
6854  // stream back to its state on input, when this scope
6855  // terminates.
6856  Teuchos::SetScientific<scalar_type> sci (out);
6857 
6858  const size_t myNumRows = X.getLocalLength ();
6859  const size_t numCols = X.getNumVectors ();
6860  // Use a different tag for the "size" messages than for the
6861  // "data" messages, in order to help us debug any mix-ups.
6862  const int sizeTag = 1337;
6863  const int dataTag = 1338;
6864 
6865  // Process 0 pipelines nonblocking receives with file output.
6866  //
6867  // Constraints:
6868  // - Process 0 can't post a receive for another process'
6869  // actual data, until it posts and waits on the receive
6870  // from that process with the amount of data to receive.
6871  // (We could just post receives with a max data size, but
6872  // I feel uncomfortable about that.)
6873  // - The C++ standard library doesn't allow nonblocking
6874  // output to an std::ostream. (Thus, we have to start a
6875  // receive or send before starting the write, and hope
6876  // that MPI completes it in the background.)
6877  //
6878  // Process 0: Post receive-size receives from Processes 1 and 2.
6879  // Process 1: Post send-size send to Process 0.
6880  // Process 2: Post send-size send to Process 0.
6881  //
6882  // All processes: Pack my entries.
6883  //
6884  // Process 1:
6885  // - Post send-data send to Process 0.
6886  // - Wait on my send-size send to Process 0.
6887  //
6888  // Process 0:
6889  // - Print MatrixMarket header.
6890  // - Print my entries.
6891  // - Wait on receive-size receive from Process 1.
6892  // - Post receive-data receive from Process 1.
6893  //
6894  // For each process p = 1, 2, ... numProcs-1:
6895  // If I am Process 0:
6896  // - Post receive-size receive from Process p + 2
6897  // - Wait on receive-size receive from Process p + 1
6898  // - Post receive-data receive from Process p + 1
6899  // - Wait on receive-data receive from Process p
6900  // - Write data from Process p.
6901  // Else if I am Process p:
6902  // - Wait on my send-data send.
6903  // Else if I am Process p+1:
6904  // - Post send-data send to Process 0.
6905  // - Wait on my send-size send.
6906  // Else if I am Process p+2:
6907  // - Post send-size send to Process 0.
6908  //
6909  // Pipelining has three goals here:
6910  // 1. Overlap communication (the receives) with file I/O
6911  // 2. Give Process 0 a chance to prepost some receives,
6912  // before sends show up, by packing local data before
6913  // posting sends
6914  // 3. Don't post _all_ receives or _all_ sends, because that
6915  // wouldn't be memory scalable. (Just because we can't
6916  // see how much memory MPI consumes, doesn't mean that it
6917  // doesn't consume any!)
6918 
6919  // These are used on every process. sendReqSize[0] holds the
6920  // number of rows on this process, and sendReqBuf holds this
6921  // process' data. Process 0 packs into sendReqBuf, but
6922  // doesn't send; it only uses that for printing. All other
6923  // processes send both of these to Process 0.
6924  RCP<CommRequest<int> > sendReqSize, sendReqData;
6925 
6926  // These are used only on Process 0, for received data. Keep
6927  // 3 of each, and treat the arrays as circular buffers. When
6928  // receiving from Process p, the corresponding array index
6929  // here is p % 3.
6930  Array<ArrayRCP<size_t> > recvSizeBufs (3);
6931  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
6932  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
6933  Array<RCP<CommRequest<int> > > recvDataReqs (3);
6934 
6935  // Buffer for nonblocking send of the "send size."
6936  ArrayRCP<size_t> sendDataSize (1);
6937  sendDataSize[0] = myNumRows;
6938 
6939  if (myRank == 0) {
6940  if (debug) {
6941  std::ostringstream os;
6942  os << myRank << ": Post receive-size receives from "
6943  "Procs 1 and 2: tag = " << sizeTag << endl;
6944  *dbg << os.str ();
6945  }
6946  // Process 0: Post receive-size receives from Processes 1 and 2.
6947  recvSizeBufs[0].resize (1);
6948  // Set these three to an invalid value as a flag. If we
6949  // don't get these messages, then the invalid value will
6950  // remain, so we can test for it.
6951  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6952  recvSizeBufs[1].resize (1);
6953  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6954  recvSizeBufs[2].resize (1);
6955  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6956  if (numProcs > 1) {
6957  recvSizeReqs[1] =
6958  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
6959  }
6960  if (numProcs > 2) {
6961  recvSizeReqs[2] =
6962  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
6963  }
6964  }
6965  else if (myRank == 1 || myRank == 2) {
6966  if (debug) {
6967  std::ostringstream os;
6968  os << myRank << ": Post send-size send: size = "
6969  << sendDataSize[0] << ", tag = " << sizeTag << endl;
6970  *dbg << os.str ();
6971  }
6972  // Prime the pipeline by having Processes 1 and 2 start
6973  // their send-size sends. We don't want _all_ the processes
6974  // to start their send-size sends, because that wouldn't be
6975  // memory scalable.
6976  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
6977  }
6978  else {
6979  if (debug) {
6980  std::ostringstream os;
6981  os << myRank << ": Not posting my send-size send yet" << endl;
6982  *dbg << os.str ();
6983  }
6984  }
6985 
6986  //
6987  // Pack my entries, in column-major order.
6988  //
6989  if (debug) {
6990  std::ostringstream os;
6991  os << myRank << ": Pack my entries" << endl;
6992  *dbg << os.str ();
6993  }
6994  ArrayRCP<scalar_type> sendDataBuf;
6995  try {
6996  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
6997  X.get1dCopy (sendDataBuf (), myNumRows);
6998  }
6999  catch (std::exception& e) {
7000  lclErr = 1;
7001  if (! err.is_null ()) {
7002  std::ostringstream os;
7003  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7004  "entries threw an exception: " << e.what () << endl;
7005  *err << os.str ();
7006  }
7007  }
7008  if (debug) {
7009  std::ostringstream os;
7010  os << myRank << ": Done packing my entries" << endl;
7011  *dbg << os.str ();
7012  }
7013 
7014  //
7015  // Process 1: post send-data send to Process 0.
7016  //
7017  if (myRank == 1) {
7018  if (debug) {
7019  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7020  << endl;
7021  }
7022  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7023  }
7024 
7025  //
7026  // Process 0: Write my entries.
7027  //
7028  if (myRank == 0) {
7029  if (debug) {
7030  std::ostringstream os;
7031  os << myRank << ": Write my entries" << endl;
7032  *dbg << os.str ();
7033  }
7034 
7035  // Write Process 0's data to the output stream.
7036  // Matrix Market prints dense matrices in column-major order.
7037  const size_t printNumRows = myNumRows;
7038  ArrayView<const scalar_type> printData = sendDataBuf ();
7039  const size_t printStride = printNumRows;
7040  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7041  lclErr = 1;
7042  if (! err.is_null ()) {
7043  std::ostringstream os;
7044  os << "Process " << myRank << ": My MultiVector data's size "
7045  << printData.size () << " does not match my local dimensions "
7046  << printStride << " x " << numCols << "." << endl;
7047  *err << os.str ();
7048  }
7049  }
7050  else {
7051  // Matrix Market dense format wants one number per line.
7052  // It wants each complex number as two real numbers (real
7053  // resp. imaginary parts) with a space between.
7054  for (size_t col = 0; col < numCols; ++col) {
7055  for (size_t row = 0; row < printNumRows; ++row) {
7056  if (STS::isComplex) {
7057  out << STS::real (printData[row + col * printStride]) << " "
7058  << STS::imag (printData[row + col * printStride]) << endl;
7059  } else {
7060  out << printData[row + col * printStride] << endl;
7061  }
7062  }
7063  }
7064  }
7065  }
7066 
7067  if (myRank == 0) {
7068  // Wait on receive-size receive from Process 1.
7069  const int recvRank = 1;
7070  const int circBufInd = recvRank % 3;
7071  if (debug) {
7072  std::ostringstream os;
7073  os << myRank << ": Wait on receive-size receive from Process "
7074  << recvRank << endl;
7075  *dbg << os.str ();
7076  }
7077  if (numProcs > 1) {
7078  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7079 
7080  // We received the number of rows of data. (The data
7081  // come in two columns.)
7082  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7083  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7084  lclErr = 1;
7085  if (! err.is_null ()) {
7086  std::ostringstream os;
7087  os << myRank << ": Result of receive-size receive from Process "
7088  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7089  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7090  "This should never happen, and suggests that the receive never "
7091  "got posted. Please report this bug to the Tpetra developers."
7092  << endl;
7093  *err << os.str ();
7094  }
7095 
7096  // If we're going to continue after error, set the
7097  // number of rows to receive to a reasonable size. This
7098  // may cause MPI_ERR_TRUNCATE if the sending process is
7099  // sending more than 0 rows, but that's better than MPI
7100  // overflowing due to the huge positive value that is
7101  // Teuchos::OrdinalTraits<size_t>::invalid().
7102  recvNumRows = 0;
7103  }
7104 
7105  // Post receive-data receive from Process 1.
7106  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7107  if (debug) {
7108  std::ostringstream os;
7109  os << myRank << ": Post receive-data receive from Process "
7110  << recvRank << ": tag = " << dataTag << ", buffer size = "
7111  << recvDataBufs[circBufInd].size () << endl;
7112  *dbg << os.str ();
7113  }
7114  if (! recvSizeReqs[circBufInd].is_null ()) {
7115  lclErr = 1;
7116  if (! err.is_null ()) {
7117  std::ostringstream os;
7118  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7119  "null, before posting the receive-data receive from Process "
7120  << recvRank << ". This should never happen. Please report "
7121  "this bug to the Tpetra developers." << endl;
7122  *err << os.str ();
7123  }
7124  }
7125  recvDataReqs[circBufInd] =
7126  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7127  recvRank, dataTag, comm);
7128  } // numProcs > 1
7129  }
7130  else if (myRank == 1) {
7131  // Wait on my send-size send.
7132  if (debug) {
7133  std::ostringstream os;
7134  os << myRank << ": Wait on my send-size send" << endl;
7135  *dbg << os.str ();
7136  }
7137  wait<int> (comm, outArg (sendReqSize));
7138  }
7139 
7140  //
7141  // Pipeline loop
7142  //
7143  for (int p = 1; p < numProcs; ++p) {
7144  if (myRank == 0) {
7145  if (p + 2 < numProcs) {
7146  // Post receive-size receive from Process p + 2.
7147  const int recvRank = p + 2;
7148  const int circBufInd = recvRank % 3;
7149  if (debug) {
7150  std::ostringstream os;
7151  os << myRank << ": Post receive-size receive from Process "
7152  << recvRank << ": tag = " << sizeTag << endl;
7153  *dbg << os.str ();
7154  }
7155  if (! recvSizeReqs[circBufInd].is_null ()) {
7156  lclErr = 1;
7157  if (! err.is_null ()) {
7158  std::ostringstream os;
7159  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7160  << "null, for the receive-size receive from Process "
7161  << recvRank << "! This may mean that this process never "
7162  << "finished waiting for the receive from Process "
7163  << (recvRank - 3) << "." << endl;
7164  *err << os.str ();
7165  }
7166  }
7167  recvSizeReqs[circBufInd] =
7168  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7169  recvRank, sizeTag, comm);
7170  }
7171 
7172  if (p + 1 < numProcs) {
7173  const int recvRank = p + 1;
7174  const int circBufInd = recvRank % 3;
7175 
7176  // Wait on receive-size receive from Process p + 1.
7177  if (debug) {
7178  std::ostringstream os;
7179  os << myRank << ": Wait on receive-size receive from Process "
7180  << recvRank << endl;
7181  *dbg << os.str ();
7182  }
7183  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7184 
7185  // We received the number of rows of data. (The data
7186  // come in two columns.)
7187  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7188  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7189  lclErr = 1;
7190  if (! err.is_null ()) {
7191  std::ostringstream os;
7192  os << myRank << ": Result of receive-size receive from Process "
7193  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7194  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7195  "This should never happen, and suggests that the receive never "
7196  "got posted. Please report this bug to the Tpetra developers."
7197  << endl;
7198  *err << os.str ();
7199  }
7200  // If we're going to continue after error, set the
7201  // number of rows to receive to a reasonable size.
7202  // This may cause MPI_ERR_TRUNCATE if the sending
7203  // process sends more than 0 rows, but that's better
7204  // than MPI overflowing due to the huge positive value
7205  // Teuchos::OrdinalTraits<size_t>::invalid().
7206  recvNumRows = 0;
7207  }
7208 
7209  // Post receive-data receive from Process p + 1.
7210  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7211  if (debug) {
7212  std::ostringstream os;
7213  os << myRank << ": Post receive-data receive from Process "
7214  << recvRank << ": tag = " << dataTag << ", buffer size = "
7215  << recvDataBufs[circBufInd].size () << endl;
7216  *dbg << os.str ();
7217  }
7218  if (! recvDataReqs[circBufInd].is_null ()) {
7219  lclErr = 1;
7220  if (! err.is_null ()) {
7221  std::ostringstream os;
7222  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7223  << "null, for the receive-data receive from Process "
7224  << recvRank << "! This may mean that this process never "
7225  << "finished waiting for the receive from Process "
7226  << (recvRank - 3) << "." << endl;
7227  *err << os.str ();
7228  }
7229  }
7230  recvDataReqs[circBufInd] =
7231  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7232  recvRank, dataTag, comm);
7233  }
7234 
7235  // Wait on receive-data receive from Process p.
7236  const int recvRank = p;
7237  const int circBufInd = recvRank % 3;
7238  if (debug) {
7239  std::ostringstream os;
7240  os << myRank << ": Wait on receive-data receive from Process "
7241  << recvRank << endl;
7242  *dbg << os.str ();
7243  }
7244  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7245 
7246  // Write Process p's data. Number of rows lives in
7247  // recvSizeBufs[circBufInd], and the actual data live in
7248  // recvDataBufs[circBufInd]. Do this after posting receives,
7249  // in order to expose overlap of comm. with file I/O.
7250  if (debug) {
7251  std::ostringstream os;
7252  os << myRank << ": Write entries from Process " << recvRank
7253  << endl;
7254  *dbg << os.str () << endl;
7255  }
7256  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7257  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7258  lclErr = 1;
7259  if (! err.is_null ()) {
7260  std::ostringstream os;
7261  os << myRank << ": Result of receive-size receive from Process "
7262  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7263  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7264  << ". This should never happen, and suggests that its "
7265  "receive-size receive was never posted. "
7266  "Please report this bug to the Tpetra developers." << endl;
7267  *err << os.str ();
7268  }
7269  // If we're going to continue after error, set the
7270  // number of rows to print to a reasonable size.
7271  printNumRows = 0;
7272  }
7273  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7274  lclErr = 1;
7275  if (! err.is_null ()) {
7276  std::ostringstream os;
7277  os << myRank << ": Result of receive-size receive from Proc "
7278  << recvRank << " was " << printNumRows << " > 0, but "
7279  "recvDataBufs[" << circBufInd << "] is null. This should "
7280  "never happen. Please report this bug to the Tpetra "
7281  "developers." << endl;
7282  *err << os.str ();
7283  }
7284  // If we're going to continue after error, set the
7285  // number of rows to print to a reasonable size.
7286  printNumRows = 0;
7287  }
7288 
7289  // Write the received data to the output stream.
7290  // Matrix Market prints dense matrices in column-major order.
7291  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7292  const size_t printStride = printNumRows;
7293  // Matrix Market dense format wants one number per line.
7294  // It wants each complex number as two real numbers (real
7295  // resp. imaginary parts) with a space between.
7296  for (size_t col = 0; col < numCols; ++col) {
7297  for (size_t row = 0; row < printNumRows; ++row) {
7298  if (STS::isComplex) {
7299  out << STS::real (printData[row + col * printStride]) << " "
7300  << STS::imag (printData[row + col * printStride]) << endl;
7301  } else {
7302  out << printData[row + col * printStride] << endl;
7303  }
7304  }
7305  }
7306  }
7307  else if (myRank == p) { // Process p
7308  // Wait on my send-data send.
7309  if (debug) {
7310  std::ostringstream os;
7311  os << myRank << ": Wait on my send-data send" << endl;
7312  *dbg << os.str ();
7313  }
7314  wait<int> (comm, outArg (sendReqData));
7315  }
7316  else if (myRank == p + 1) { // Process p + 1
7317  // Post send-data send to Process 0.
7318  if (debug) {
7319  std::ostringstream os;
7320  os << myRank << ": Post send-data send: tag = " << dataTag
7321  << endl;
7322  *dbg << os.str ();
7323  }
7324  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7325  // Wait on my send-size send.
7326  if (debug) {
7327  std::ostringstream os;
7328  os << myRank << ": Wait on my send-size send" << endl;
7329  *dbg << os.str ();
7330  }
7331  wait<int> (comm, outArg (sendReqSize));
7332  }
7333  else if (myRank == p + 2) { // Process p + 2
7334  // Post send-size send to Process 0.
7335  if (debug) {
7336  std::ostringstream os;
7337  os << myRank << ": Post send-size send: size = "
7338  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7339  *dbg << os.str ();
7340  }
7341  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7342  }
7343  }
7344 
7345  // Establish global agreement on the error state.
7346  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7347  TEUCHOS_TEST_FOR_EXCEPTION(
7348  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7349  "experienced some kind of error and was unable to complete.");
7350 
7351  if (debug) {
7352  dbg->popTab ();
7353  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7354  dbg->popTab ();
7355  }
7356  }
7357 
7358  public:
7359 
7365  static void
7366  writeDense (std::ostream& out,
7367  const Teuchos::RCP<const multivector_type>& X,
7368  const std::string& matrixName,
7369  const std::string& matrixDescription,
7370  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7371  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7372  {
7373  TEUCHOS_TEST_FOR_EXCEPTION(
7374  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7375  "writeDense: The input MultiVector X is null.");
7376  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7377  }
7378 
7384  static void
7385  writeDense (std::ostream& out,
7386  const multivector_type& X,
7387  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7388  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7389  {
7390  writeDense (out, X, "", "", err, dbg);
7391  }
7392 
7398  static void
7399  writeDense (std::ostream& out,
7400  const Teuchos::RCP<const multivector_type>& X,
7401  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7402  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7403  {
7404  TEUCHOS_TEST_FOR_EXCEPTION(
7405  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7406  "writeDense: The input MultiVector X is null.");
7407  writeDense (out, *X, "", "", err, dbg);
7408  }
7409 
7429  static void
7430  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7431  {
7432  Teuchos::RCP<Teuchos::FancyOStream> err =
7433  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7434  writeMap (out, map, err, debug);
7435  }
7436 
7445  static void
7446  writeMap (std::ostream& out,
7447  const map_type& map,
7448  const Teuchos::RCP<Teuchos::FancyOStream>& err,
7449  const bool debug=false)
7450  {
7451  using Teuchos::Array;
7452  using Teuchos::ArrayRCP;
7453  using Teuchos::ArrayView;
7454  using Teuchos::Comm;
7455  using Teuchos::CommRequest;
7456  using Teuchos::ireceive;
7457  using Teuchos::isend;
7458  using Teuchos::RCP;
7459  using Teuchos::TypeNameTraits;
7460  using Teuchos::wait;
7461  using std::endl;
7462  typedef global_ordinal_type GO;
7463  typedef int pid_type;
7464 
7465  // Treat the Map as a 1-column "multivector." This differs
7466  // from the previous two-column format, in which column 0 held
7467  // the GIDs, and column 1 held the corresponding PIDs. It
7468  // differs because printing that format requires knowing the
7469  // entire first column -- that is, all the GIDs -- in advance.
7470  // Sending messages from each process one at a time saves
7471  // memory, but it means that Process 0 doesn't ever have all
7472  // the GIDs at once.
7473  //
7474  // We pack the entries as ptrdiff_t, since this should be the
7475  // biggest signed built-in integer type that can hold any GO
7476  // or pid_type (= int) quantity without overflow. Test this
7477  // assumption at run time.
7478  typedef ptrdiff_t int_type;
7479  TEUCHOS_TEST_FOR_EXCEPTION(
7480  sizeof (GO) > sizeof (int_type), std::logic_error,
7481  "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7482  << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7483  << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7484  TEUCHOS_TEST_FOR_EXCEPTION(
7485  sizeof (pid_type) > sizeof (int_type), std::logic_error,
7486  "The (MPI) process rank type pid_type=" <<
7487  TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7488  "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7489  " = " << sizeof (ptrdiff_t) << ".");
7490 
7491  const Comm<int>& comm = * (map.getComm ());
7492  const int myRank = comm.getRank ();
7493  const int numProcs = comm.getSize ();
7494 
7495  if (! err.is_null ()) {
7496  err->pushTab ();
7497  }
7498  if (debug) {
7499  std::ostringstream os;
7500  os << myRank << ": writeMap" << endl;
7501  *err << os.str ();
7502  }
7503  if (! err.is_null ()) {
7504  err->pushTab ();
7505  }
7506 
7507  const size_t myNumRows = map.getNodeNumElements ();
7508  // Use a different tag for the "size" messages than for the
7509  // "data" messages, in order to help us debug any mix-ups.
7510  const int sizeTag = 1337;
7511  const int dataTag = 1338;
7512 
7513  // Process 0 pipelines nonblocking receives with file output.
7514  //
7515  // Constraints:
7516  // - Process 0 can't post a receive for another process'
7517  // actual data, until it posts and waits on the receive
7518  // from that process with the amount of data to receive.
7519  // (We could just post receives with a max data size, but
7520  // I feel uncomfortable about that.)
7521  // - The C++ standard library doesn't allow nonblocking
7522  // output to an std::ostream.
7523  //
7524  // Process 0: Post receive-size receives from Processes 1 and 2.
7525  // Process 1: Post send-size send to Process 0.
7526  // Process 2: Post send-size send to Process 0.
7527  //
7528  // All processes: Pack my GIDs and PIDs.
7529  //
7530  // Process 1:
7531  // - Post send-data send to Process 0.
7532  // - Wait on my send-size send to Process 0.
7533  //
7534  // Process 0:
7535  // - Print MatrixMarket header.
7536  // - Print my GIDs and PIDs.
7537  // - Wait on receive-size receive from Process 1.
7538  // - Post receive-data receive from Process 1.
7539  //
7540  // For each process p = 1, 2, ... numProcs-1:
7541  // If I am Process 0:
7542  // - Post receive-size receive from Process p + 2
7543  // - Wait on receive-size receive from Process p + 1
7544  // - Post receive-data receive from Process p + 1
7545  // - Wait on receive-data receive from Process p
7546  // - Write data from Process p.
7547  // Else if I am Process p:
7548  // - Wait on my send-data send.
7549  // Else if I am Process p+1:
7550  // - Post send-data send to Process 0.
7551  // - Wait on my send-size send.
7552  // Else if I am Process p+2:
7553  // - Post send-size send to Process 0.
7554  //
7555  // Pipelining has three goals here:
7556  // 1. Overlap communication (the receives) with file I/O
7557  // 2. Give Process 0 a chance to prepost some receives,
7558  // before sends show up, by packing local data before
7559  // posting sends
7560  // 3. Don't post _all_ receives or _all_ sends, because that
7561  // wouldn't be memory scalable. (Just because we can't
7562  // see how much memory MPI consumes, doesn't mean that it
7563  // doesn't consume any!)
7564 
7565  // These are used on every process. sendReqSize[0] holds the
7566  // number of rows on this process, and sendReqBuf holds this
7567  // process' data. Process 0 packs into sendReqBuf, but
7568  // doesn't send; it only uses that for printing. All other
7569  // processes send both of these to Process 0.
7570  RCP<CommRequest<int> > sendReqSize, sendReqData;
7571 
7572  // These are used only on Process 0, for received data. Keep
7573  // 3 of each, and treat the arrays as circular buffers. When
7574  // receiving from Process p, the corresponding array index
7575  // here is p % 3.
7576  Array<ArrayRCP<int_type> > recvSizeBufs (3);
7577  Array<ArrayRCP<int_type> > recvDataBufs (3);
7578  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7579  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7580 
7581  // Buffer for nonblocking send of the "send size."
7582  ArrayRCP<int_type> sendDataSize (1);
7583  sendDataSize[0] = myNumRows;
7584 
7585  if (myRank == 0) {
7586  if (debug) {
7587  std::ostringstream os;
7588  os << myRank << ": Post receive-size receives from "
7589  "Procs 1 and 2: tag = " << sizeTag << endl;
7590  *err << os.str ();
7591  }
7592  // Process 0: Post receive-size receives from Processes 1 and 2.
7593  recvSizeBufs[0].resize (1);
7594  (recvSizeBufs[0])[0] = -1; // error flag
7595  recvSizeBufs[1].resize (1);
7596  (recvSizeBufs[1])[0] = -1; // error flag
7597  recvSizeBufs[2].resize (1);
7598  (recvSizeBufs[2])[0] = -1; // error flag
7599  if (numProcs > 1) {
7600  recvSizeReqs[1] =
7601  ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7602  }
7603  if (numProcs > 2) {
7604  recvSizeReqs[2] =
7605  ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7606  }
7607  }
7608  else if (myRank == 1 || myRank == 2) {
7609  if (debug) {
7610  std::ostringstream os;
7611  os << myRank << ": Post send-size send: size = "
7612  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7613  *err << os.str ();
7614  }
7615  // Prime the pipeline by having Processes 1 and 2 start
7616  // their send-size sends. We don't want _all_ the processes
7617  // to start their send-size sends, because that wouldn't be
7618  // memory scalable.
7619  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7620  }
7621  else {
7622  if (debug) {
7623  std::ostringstream os;
7624  os << myRank << ": Not posting my send-size send yet" << endl;
7625  *err << os.str ();
7626  }
7627  }
7628 
7629  //
7630  // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7631  // consecutively, for better locality.
7632  //
7633 
7634  if (debug) {
7635  std::ostringstream os;
7636  os << myRank << ": Pack my GIDs and PIDs" << endl;
7637  *err << os.str ();
7638  }
7639 
7640  ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7641 
7642  if (map.isContiguous ()) {
7643  const int_type myMinGblIdx =
7644  static_cast<int_type> (map.getMinGlobalIndex ());
7645  for (size_t k = 0; k < myNumRows; ++k) {
7646  const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7647  const int_type pid = static_cast<int_type> (myRank);
7648  sendDataBuf[2*k] = gid;
7649  sendDataBuf[2*k+1] = pid;
7650  }
7651  }
7652  else {
7653  ArrayView<const GO> myGblInds = map.getNodeElementList ();
7654  for (size_t k = 0; k < myNumRows; ++k) {
7655  const int_type gid = static_cast<int_type> (myGblInds[k]);
7656  const int_type pid = static_cast<int_type> (myRank);
7657  sendDataBuf[2*k] = gid;
7658  sendDataBuf[2*k+1] = pid;
7659  }
7660  }
7661 
7662  if (debug) {
7663  std::ostringstream os;
7664  os << myRank << ": Done packing my GIDs and PIDs" << endl;
7665  *err << os.str ();
7666  }
7667 
7668  if (myRank == 1) {
7669  // Process 1: post send-data send to Process 0.
7670  if (debug) {
7671  *err << myRank << ": Post send-data send: tag = " << dataTag
7672  << endl;
7673  }
7674  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7675  }
7676 
7677  if (myRank == 0) {
7678  if (debug) {
7679  *err << myRank << ": Write MatrixMarket header" << endl;
7680  }
7681 
7682  // Process 0: Write the MatrixMarket header.
7683  // Description section explains each column.
7684  std::ostringstream hdr;
7685 
7686  // Print the Matrix Market header. MultiVector stores data
7687  // nonsymmetrically, hence "general" in the banner line.
7688  hdr << "%%MatrixMarket matrix array integer general" << endl
7689  << "% Format: Version 2.0" << endl
7690  << "%" << endl
7691  << "% This file encodes a Tpetra::Map." << endl
7692  << "% It is stored as a dense vector, with twice as many " << endl
7693  << "% entries as the global number of GIDs (global indices)." << endl
7694  << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7695  << "% is the rank of the process owning that GID." << endl
7696  << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
7697  out << hdr.str ();
7698 
7699  if (debug) {
7700  std::ostringstream os;
7701  os << myRank << ": Write my GIDs and PIDs" << endl;
7702  *err << os.str ();
7703  }
7704 
7705  // Write Process 0's data to the output stream.
7706  // Matrix Market prints dense matrices in column-major order.
7707  const int_type printNumRows = myNumRows;
7708  ArrayView<const int_type> printData = sendDataBuf ();
7709  for (int_type k = 0; k < printNumRows; ++k) {
7710  const int_type gid = printData[2*k];
7711  const int_type pid = printData[2*k+1];
7712  out << gid << endl << pid << endl;
7713  }
7714  }
7715 
7716  if (myRank == 0) {
7717  // Wait on receive-size receive from Process 1.
7718  const int recvRank = 1;
7719  const int circBufInd = recvRank % 3;
7720  if (debug) {
7721  std::ostringstream os;
7722  os << myRank << ": Wait on receive-size receive from Process "
7723  << recvRank << endl;
7724  *err << os.str ();
7725  }
7726  if (numProcs > 1) {
7727  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7728 
7729  // We received the number of rows of data. (The data
7730  // come in two columns.)
7731  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7732  if (debug && recvNumRows == -1) {
7733  std::ostringstream os;
7734  os << myRank << ": Result of receive-size receive from Process "
7735  << recvRank << " is -1. This should never happen, and "
7736  "suggests that the receive never got posted. Please report "
7737  "this bug to the Tpetra developers." << endl;
7738  *err << os.str ();
7739  }
7740 
7741  // Post receive-data receive from Process 1.
7742  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7743  if (debug) {
7744  std::ostringstream os;
7745  os << myRank << ": Post receive-data receive from Process "
7746  << recvRank << ": tag = " << dataTag << ", buffer size = "
7747  << recvDataBufs[circBufInd].size () << endl;
7748  *err << os.str ();
7749  }
7750  if (! recvSizeReqs[circBufInd].is_null ()) {
7751  std::ostringstream os;
7752  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7753  "null, before posting the receive-data receive from Process "
7754  << recvRank << ". This should never happen. Please report "
7755  "this bug to the Tpetra developers." << endl;
7756  *err << os.str ();
7757  }
7758  recvDataReqs[circBufInd] =
7759  ireceive<int, int_type> (recvDataBufs[circBufInd],
7760  recvRank, dataTag, comm);
7761  } // numProcs > 1
7762  }
7763  else if (myRank == 1) {
7764  // Wait on my send-size send.
7765  if (debug) {
7766  std::ostringstream os;
7767  os << myRank << ": Wait on my send-size send" << endl;
7768  *err << os.str ();
7769  }
7770  wait<int> (comm, outArg (sendReqSize));
7771  }
7772 
7773  //
7774  // Pipeline loop
7775  //
7776  for (int p = 1; p < numProcs; ++p) {
7777  if (myRank == 0) {
7778  if (p + 2 < numProcs) {
7779  // Post receive-size receive from Process p + 2.
7780  const int recvRank = p + 2;
7781  const int circBufInd = recvRank % 3;
7782  if (debug) {
7783  std::ostringstream os;
7784  os << myRank << ": Post receive-size receive from Process "
7785  << recvRank << ": tag = " << sizeTag << endl;
7786  *err << os.str ();
7787  }
7788  if (! recvSizeReqs[circBufInd].is_null ()) {
7789  std::ostringstream os;
7790  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7791  << "null, for the receive-size receive from Process "
7792  << recvRank << "! This may mean that this process never "
7793  << "finished waiting for the receive from Process "
7794  << (recvRank - 3) << "." << endl;
7795  *err << os.str ();
7796  }
7797  recvSizeReqs[circBufInd] =
7798  ireceive<int, int_type> (recvSizeBufs[circBufInd],
7799  recvRank, sizeTag, comm);
7800  }
7801 
7802  if (p + 1 < numProcs) {
7803  const int recvRank = p + 1;
7804  const int circBufInd = recvRank % 3;
7805 
7806  // Wait on receive-size receive from Process p + 1.
7807  if (debug) {
7808  std::ostringstream os;
7809  os << myRank << ": Wait on receive-size receive from Process "
7810  << recvRank << endl;
7811  *err << os.str ();
7812  }
7813  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7814 
7815  // We received the number of rows of data. (The data
7816  // come in two columns.)
7817  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7818  if (debug && recvNumRows == -1) {
7819  std::ostringstream os;
7820  os << myRank << ": Result of receive-size receive from Process "
7821  << recvRank << " is -1. This should never happen, and "
7822  "suggests that the receive never got posted. Please report "
7823  "this bug to the Tpetra developers." << endl;
7824  *err << os.str ();
7825  }
7826 
7827  // Post receive-data receive from Process p + 1.
7828  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7829  if (debug) {
7830  std::ostringstream os;
7831  os << myRank << ": Post receive-data receive from Process "
7832  << recvRank << ": tag = " << dataTag << ", buffer size = "
7833  << recvDataBufs[circBufInd].size () << endl;
7834  *err << os.str ();
7835  }
7836  if (! recvDataReqs[circBufInd].is_null ()) {
7837  std::ostringstream os;
7838  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7839  << "null, for the receive-data receive from Process "
7840  << recvRank << "! This may mean that this process never "
7841  << "finished waiting for the receive from Process "
7842  << (recvRank - 3) << "." << endl;
7843  *err << os.str ();
7844  }
7845  recvDataReqs[circBufInd] =
7846  ireceive<int, int_type> (recvDataBufs[circBufInd],
7847  recvRank, dataTag, comm);
7848  }
7849 
7850  // Wait on receive-data receive from Process p.
7851  const int recvRank = p;
7852  const int circBufInd = recvRank % 3;
7853  if (debug) {
7854  std::ostringstream os;
7855  os << myRank << ": Wait on receive-data receive from Process "
7856  << recvRank << endl;
7857  *err << os.str ();
7858  }
7859  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7860 
7861  // Write Process p's data. Number of rows lives in
7862  // recvSizeBufs[circBufInd], and the actual data live in
7863  // recvDataBufs[circBufInd]. Do this after posting receives,
7864  // in order to expose overlap of comm. with file I/O.
7865  if (debug) {
7866  std::ostringstream os;
7867  os << myRank << ": Write GIDs and PIDs from Process "
7868  << recvRank << endl;
7869  *err << os.str () << endl;
7870  }
7871  const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
7872  if (debug && printNumRows == -1) {
7873  std::ostringstream os;
7874  os << myRank << ": Result of receive-size receive from Process "
7875  << recvRank << " was -1. This should never happen, and "
7876  "suggests that its receive-size receive was never posted. "
7877  "Please report this bug to the Tpetra developers." << endl;
7878  *err << os.str ();
7879  }
7880  if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7881  std::ostringstream os;
7882  os << myRank << ": Result of receive-size receive from Proc "
7883  << recvRank << " was " << printNumRows << " > 0, but "
7884  "recvDataBufs[" << circBufInd << "] is null. This should "
7885  "never happen. Please report this bug to the Tpetra "
7886  "developers." << endl;
7887  *err << os.str ();
7888  }
7889  ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
7890  for (int_type k = 0; k < printNumRows; ++k) {
7891  const int_type gid = printData[2*k];
7892  const int_type pid = printData[2*k+1];
7893  out << gid << endl << pid << endl;
7894  }
7895  }
7896  else if (myRank == p) { // Process p
7897  // Wait on my send-data send.
7898  if (debug) {
7899  std::ostringstream os;
7900  os << myRank << ": Wait on my send-data send" << endl;
7901  *err << os.str ();
7902  }
7903  wait<int> (comm, outArg (sendReqData));
7904  }
7905  else if (myRank == p + 1) { // Process p + 1
7906  // Post send-data send to Process 0.
7907  if (debug) {
7908  std::ostringstream os;
7909  os << myRank << ": Post send-data send: tag = " << dataTag
7910  << endl;
7911  *err << os.str ();
7912  }
7913  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7914  // Wait on my send-size send.
7915  if (debug) {
7916  std::ostringstream os;
7917  os << myRank << ": Wait on my send-size send" << endl;
7918  *err << os.str ();
7919  }
7920  wait<int> (comm, outArg (sendReqSize));
7921  }
7922  else if (myRank == p + 2) { // Process p + 2
7923  // Post send-size send to Process 0.
7924  if (debug) {
7925  std::ostringstream os;
7926  os << myRank << ": Post send-size send: size = "
7927  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7928  *err << os.str ();
7929  }
7930  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7931  }
7932  }
7933 
7934  if (! err.is_null ()) {
7935  err->popTab ();
7936  }
7937  if (debug) {
7938  *err << myRank << ": writeMap: Done" << endl;
7939  }
7940  if (! err.is_null ()) {
7941  err->popTab ();
7942  }
7943  }
7944 
7946  static void
7947  writeMapFile (const std::string& filename,
7948  const map_type& map)
7949  {
7950  const int myRank = map.getComm ()->getRank ();
7951  std::ofstream out;
7952  if (myRank == 0) { // Only open the file on Proc 0.
7953  out.open (filename.c_str());
7954  }
7955  writeMap (out, map);
7956  // We can rely on the destructor of the output stream to close
7957  // the file on scope exit, even if writeDense() throws an
7958  // exception.
7959  }
7960 
7961  private:
7985  static void
7986  printAsComment (std::ostream& out, const std::string& str)
7987  {
7988  using std::endl;
7989  std::istringstream inpstream (str);
7990  std::string line;
7991 
7992  while (getline (inpstream, line)) {
7993  if (! line.empty()) {
7994  // Note that getline() doesn't store '\n', so we have to
7995  // append the endline ourselves.
7996  if (line[0] == '%') { // Line starts with a comment character.
7997  out << line << endl;
7998  }
7999  else { // Line doesn't start with a comment character.
8000  out << "%% " << line << endl;
8001  }
8002  }
8003  }
8004  }
8005 
8006  public:
8007 
8026  static void
8027  writeOperator(const std::string& fileName, operator_type const &A) {
8028  Teuchos::ParameterList pl;
8029  writeOperator(fileName, A, pl);
8030  }
8031 
8052  static void
8053  writeOperator (std::ostream& out, const operator_type& A) {
8054  Teuchos::ParameterList pl;
8055  writeOperator (out, A, pl);
8056  }
8057 
8094  static void
8095  writeOperator (const std::string& fileName,
8096  const operator_type& A,
8097  const Teuchos::ParameterList& params)
8098  {
8099  std::ofstream out;
8100  std::string tmpFile = "__TMP__" + fileName;
8101  const int myRank = A.getDomainMap()->getComm()->getRank();
8102  bool precisionChanged=false;
8103  int oldPrecision;
8104  // The number of nonzero entries in a Tpetra::Operator is
8105  // unknown until probing is completed. In order to write a
8106  // MatrixMarket header, we write the matrix to a temporary
8107  // file.
8108  //
8109  // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8110  // TEMPORARY FILE.
8111  if (myRank==0) {
8112  if (std::ifstream(tmpFile))
8113  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8114  "writeOperator: temporary file " << tmpFile << " already exists");
8115  out.open(tmpFile.c_str());
8116  if (params.isParameter("precision")) {
8117  oldPrecision = out.precision(params.get<int>("precision"));
8118  precisionChanged=true;
8119  }
8120  }
8121 
8122  const std::string header = writeOperatorImpl(out, A, params);
8123 
8124  if (myRank==0) {
8125  if (precisionChanged)
8126  out.precision(oldPrecision);
8127  out.close();
8128  out.open(fileName.c_str(), std::ios::binary);
8129  bool printMatrixMarketHeader = true;
8130  if (params.isParameter("print MatrixMarket header"))
8131  printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8132  if (printMatrixMarketHeader && myRank == 0) {
8133  // Write header to final file.
8134  out << header;
8135  }
8136  // Append matrix from temporary to final file.
8137  std::ifstream src(tmpFile, std::ios_base::binary);
8138  out << src.rdbuf();
8139  src.close();
8140  // Delete the temporary file.
8141  remove(tmpFile.c_str());
8142  }
8143  }
8144 
8183  static void
8184  writeOperator (std::ostream& out,
8185  const operator_type& A,
8186  const Teuchos::ParameterList& params)
8187  {
8188  const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8189 
8190  // The number of nonzero entries in a Tpetra::Operator is
8191  // unknown until probing is completed. In order to write a
8192  // MatrixMarket header, we write the matrix to a temporary
8193  // output stream.
8194  //
8195  // NOTE (mfh 23 May 2015): Writing to a temporary output
8196  // stream may double the memory usage, depending on whether
8197  // 'out' is a file stream or an in-memory output stream (e.g.,
8198  // std::ostringstream). It might be wise to use a temporary
8199  // file instead. However, please look carefully at POSIX
8200  // functions for safe creation of temporary files. Don't just
8201  // prepend "__TMP__" to the filename and hope for the best.
8202  // Furthermore, it should be valid to call the std::ostream
8203  // overload of this method even when Process 0 does not have
8204  // access to a file system.
8205  std::ostringstream tmpOut;
8206  if (myRank == 0) {
8207  if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8208  (void) tmpOut.precision (params.get<int> ("precision"));
8209  }
8210  }
8211 
8212  const std::string header = writeOperatorImpl (tmpOut, A, params);
8213 
8214  if (myRank == 0) {
8215  bool printMatrixMarketHeader = true;
8216  if (params.isParameter ("print MatrixMarket header") &&
8217  params.isType<bool> ("print MatrixMarket header")) {
8218  printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8219  }
8220  if (printMatrixMarketHeader && myRank == 0) {
8221  out << header; // write header to final output stream
8222  }
8223  // Append matrix from temporary output stream to final output stream.
8224  //
8225  // NOTE (mfh 23 May 2015) This might use a lot of memory.
8226  // However, we should not use temporary files in this
8227  // method. Since it does not access the file system (unlike
8228  // the overload that takes a file name), it should not
8229  // require the file system at all.
8230  //
8231  // If memory usage becomes a problem, one thing we could do
8232  // is write the entries of the Operator one column (or a few
8233  // columns) at a time. The Matrix Market sparse format does
8234  // not impose an order on its entries, so it would be OK to
8235  // write them in that order.
8236  out << tmpOut.str ();
8237  }
8238  }
8239 
8240  private:
8241 
8249  static std::string
8250  writeOperatorImpl (std::ostream& os,
8251  const operator_type& A,
8252  const Teuchos::ParameterList& params)
8253  {
8254  using Teuchos::RCP;
8255  using Teuchos::rcp;
8256  using Teuchos::ArrayRCP;
8257  using Teuchos::Array;
8258 
8259  typedef local_ordinal_type LO;
8260  typedef global_ordinal_type GO;
8261  typedef scalar_type Scalar;
8262  typedef Teuchos::OrdinalTraits<LO> TLOT;
8263  typedef Teuchos::OrdinalTraits<GO> TGOT;
8264  typedef Tpetra::Import<LO, GO, node_type> import_type;
8265  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
8266 
8267  const map_type& domainMap = *(A.getDomainMap());
8268  RCP<const map_type> rangeMap = A.getRangeMap();
8269  RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8270  const int myRank = comm->getRank();
8271  const size_t numProcs = comm->getSize();
8272 
8273  size_t numMVs = 10;
8274  if (params.isParameter("probing size"))
8275  numMVs = params.get<int>("probing size");
8276 
8277  GO globalNnz = 0;
8278  GO minColGid = domainMap.getMinAllGlobalIndex();
8279  GO maxColGid = domainMap.getMaxAllGlobalIndex();
8280  // Rather than replicating the domainMap on all processors, we instead
8281  // iterate from the min GID to the max GID. If the map is gappy,
8282  // there will be invalid GIDs, i.e., GIDs no one has. This will require
8283  // unnecessary matvecs against potentially zero vectors.
8284  GO numGlobElts = maxColGid - minColGid + TGOT::one();
8285  GO numChunks = numGlobElts / numMVs;
8286  GO rem = numGlobElts % numMVs;
8287  GO indexBase = rangeMap->getIndexBase();
8288 
8289  int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8290  if (params.isParameter("zero-based indexing")) {
8291  if (params.get<bool>("zero-based indexing") == true)
8292  offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8293  }
8294 
8295  // Create map that replicates the range map on pid 0 and is empty for all other pids
8296  size_t numLocalRangeEntries = rangeMap->getNodeNumElements();
8297 
8298  // Create contiguous source map
8299  RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8300  indexBase, comm));
8301  // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8302  mv_type_go allGids(allGidsMap,1);
8303  Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8304 
8305  for (size_t i=0; i<numLocalRangeEntries; i++)
8306  allGidsData[i] = rangeMap->getGlobalElement(i);
8307  allGidsData = Teuchos::null;
8308 
8309  // Create target map that is nontrivial only on pid 0
8310  GO numTargetMapEntries=TGOT::zero();
8311  Teuchos::Array<GO> importGidList;
8312  if (myRank==0) {
8313  numTargetMapEntries = rangeMap->getGlobalNumElements();
8314  importGidList.reserve(numTargetMapEntries);
8315  for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8316  } else {
8317  importGidList.reserve(numTargetMapEntries);
8318  }
8319  RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8320 
8321  // Import all rangeMap GIDs to pid 0
8322  import_type gidImporter(allGidsMap, importGidMap);
8323  mv_type_go importedGids(importGidMap, 1);
8324  importedGids.doImport(allGids, gidImporter, INSERT);
8325 
8326  // The following import map will be non-trivial only on pid 0.
8327  ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8328  RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8329 
8330  // Importer from original range map to pid 0
8331  import_type importer(rangeMap, importMap);
8332  // Target vector on pid 0
8333  RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8334 
8335  RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8336  RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8337 
8338  Array<GO> globalColsArray, localColsArray;
8339  globalColsArray.reserve(numMVs);
8340  localColsArray.reserve(numMVs);
8341 
8342  ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8343  for (size_t i=0; i<numMVs; ++i)
8344  eiData[i] = ei->getDataNonConst(i);
8345 
8346  // //////////////////////////////////////
8347  // Discover A by chunks
8348  // //////////////////////////////////////
8349  for (GO k=0; k<numChunks; ++k) {
8350  for (size_t j=0; j<numMVs; ++j ) {
8351  //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8352  GO curGlobalCol = minColGid + k*numMVs + j;
8353  globalColsArray.push_back(curGlobalCol);
8354  //TODO extract the g2l map outside of this loop loop
8355  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8356  if (curLocalCol != TLOT::invalid()) {
8357  eiData[j][curLocalCol] = TGOT::one();
8358  localColsArray.push_back(curLocalCol);
8359  }
8360  }
8361  //TODO Do the views eiData need to be released prior to the matvec?
8362 
8363  // probe
8364  A.apply(*ei,*colsA);
8365 
8366  colsOnPid0->doImport(*colsA,importer,INSERT);
8367 
8368  if (myRank==0)
8369  globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8370  globalColsArray, offsetToUseInPrinting);
8371 
8372  //zero out the ei's
8373  for (size_t j=0; j<numMVs; ++j ) {
8374  for (int i=0; i<localColsArray.size(); ++i)
8375  eiData[j][localColsArray[i]] = TGOT::zero();
8376  }
8377  globalColsArray.clear();
8378  localColsArray.clear();
8379 
8380  }
8381 
8382  // //////////////////////////////////////
8383  // Handle leftover part of A
8384  // //////////////////////////////////////
8385  if (rem > 0) {
8386  for (int j=0; j<rem; ++j ) {
8387  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8388  globalColsArray.push_back(curGlobalCol);
8389  //TODO extract the g2l map outside of this loop loop
8390  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8391  if (curLocalCol != TLOT::invalid()) {
8392  eiData[j][curLocalCol] = TGOT::one();
8393  localColsArray.push_back(curLocalCol);
8394  }
8395  }
8396  //TODO Do the views eiData need to be released prior to the matvec?
8397 
8398  // probe
8399  A.apply(*ei,*colsA);
8400 
8401  colsOnPid0->doImport(*colsA,importer,INSERT);
8402  if (myRank==0)
8403  globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8404  globalColsArray, offsetToUseInPrinting);
8405 
8406  //zero out the ei's
8407  for (int j=0; j<rem; ++j ) {
8408  for (int i=0; i<localColsArray.size(); ++i)
8409  eiData[j][localColsArray[i]] = TGOT::zero();
8410  }
8411  globalColsArray.clear();
8412  localColsArray.clear();
8413 
8414  }
8415 
8416  // Return the Matrix Market header. It includes the header
8417  // line (that starts with "%%"), some comments, and the triple
8418  // of matrix dimensions and number of nonzero entries. We
8419  // don't actually print this here, because we don't know the
8420  // number of nonzero entries until after probing.
8421  std::ostringstream oss;
8422  if (myRank == 0) {
8423  oss << "%%MatrixMarket matrix coordinate ";
8424  if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8425  oss << "complex";
8426  } else {
8427  oss << "real";
8428  }
8429  oss << " general" << std::endl;
8430  oss << "% Tpetra::Operator" << std::endl;
8431  std::time_t now = std::time(NULL);
8432  oss << "% time stamp: " << ctime(&now);
8433  oss << "% written from " << numProcs << " processes" << std::endl;
8434  size_t numRows = rangeMap->getGlobalNumElements();
8435  size_t numCols = domainMap.getGlobalNumElements();
8436  oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8437  }
8438 
8439  return oss.str ();
8440  }
8441 
8442  static global_ordinal_type
8443  writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8444  Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8445  Teuchos::Array<global_ordinal_type> const &colsArray,
8446  global_ordinal_type const & indexBase) {
8447 
8448  typedef global_ordinal_type GO;
8449  typedef scalar_type Scalar;
8450  typedef Teuchos::ScalarTraits<Scalar> STS;
8451 
8452  GO nnz=0;
8453  const Scalar zero = STS::zero();
8454  const size_t numRows = colsA.getGlobalLength();
8455  for (size_t j=0; j<numCols; ++j) {
8456  Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8457  const GO J = colsArray[j];
8458  for (size_t i=0; i<numRows; ++i) {
8459  const Scalar val = curCol[i];
8460  if (val!=zero) {
8461  os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8462  ++nnz;
8463  }
8464  }
8465  }
8466 
8467  return nnz;
8468 
8469  }
8470 
8471  public:
8472 
8473  }; // class Writer
8474 
8475  } // namespace MatrixMarket
8476 } // namespace Tpetra
8477 
8478 #endif // __MatrixMarket_Tpetra_hpp
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.
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
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 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...
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
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.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
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 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.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
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 (&quot;forward mode&quot;).
size_t getNumVectors() const
Number of columns in the multivector.
Declaration of a function that prints strings from each process.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
One or more distributed dense vectors.
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.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
void getLocalRowView(const local_ordinal_type lclRow, Teuchos::ArrayView< const local_ordinal_type > &lclColInds) const override
Get a const, non-persisting view of the given local row&#39;s local column indices, as a Teuchos::ArrayVi...
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.
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.
SparseMatrixType::scalar_type scalar_type
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
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.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
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.
bool isGloballyIndexed() const override
Whether the graph&#39;s column indices are stored as global indices.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
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 writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
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.
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.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
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< 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.
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, in rank order.
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...
size_t global_size_t
Global size_t object.
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.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
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.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
Insert new values that don&#39;t currently exist.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
Abstract interface for operators (e.g., matrices and preconditioners).
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 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.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
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.
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.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
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.
From a distributed map build a map with all GIDs on the root node.
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...
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 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 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 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...
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 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...
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
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.
void getGlobalRowView(const global_ordinal_type gblRow, Teuchos::ArrayView< const global_ordinal_type > &gblColInds) const override
Get a const, non-persisting view of the given global row&#39;s global column indices, as a Teuchos::Array...
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.
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.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
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).
Teuchos::ArrayView< const global_ordinal_type > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
A parallel distribution of indices over processes.
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.
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.
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.
A distributed dense vector.
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.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
SparseMatrixType sparse_matrix_type
This class&#39; template parameter; a specialization of CrsMatrix.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
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 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 writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Matrix Market file reader for CrsMatrix and MultiVector.
Matrix Market file writer for CrsMatrix and MultiVector.
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 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.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.