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 // Tpetra: Templated Linear Algebra Services Package
4 //
5 // Copyright 2008 NTESS and the Tpetra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef __MatrixMarket_Tpetra_hpp
11 #define __MatrixMarket_Tpetra_hpp
12 
25 #include "Tpetra_CrsMatrix.hpp"
26 #include "Tpetra_Operator.hpp"
27 #include "Tpetra_Vector.hpp"
29 #include "Teuchos_MatrixMarket_Raw_Adder.hpp"
30 #include "Teuchos_MatrixMarket_Raw_Graph_Adder.hpp"
31 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
32 #include "Teuchos_MatrixMarket_SymmetrizingGraphAdder.hpp"
33 #include "Teuchos_MatrixMarket_assignScalar.hpp"
34 #include "Teuchos_MatrixMarket_Banner.hpp"
35 #include "Teuchos_MatrixMarket_CoordDataReader.hpp"
36 #include "Teuchos_SetScientific.hpp"
37 #include "Teuchos_TimeMonitor.hpp"
38 
39 extern "C" {
40 #include "mmio_Tpetra.h"
41 }
42 #include "Tpetra_Distribution.hpp"
43 
44 
45 #include <algorithm>
46 #include <fstream>
47 #include <iostream>
48 #include <iterator>
49 #include <vector>
50 #include <stdexcept>
51 #include <numeric>
52 
53 namespace Tpetra {
83  namespace MatrixMarket {
139  template<class SparseMatrixType>
140  class Reader {
141  public:
143  typedef SparseMatrixType sparse_matrix_type;
144  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
145 
148  typedef typename SparseMatrixType::scalar_type scalar_type;
151  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
159  typedef typename SparseMatrixType::global_ordinal_type
162  typedef typename SparseMatrixType::node_type node_type;
163 
168 
170  typedef MultiVector<scalar_type,
174 
176  typedef Vector<scalar_type,
180 
182 
184  using trcp_tcomm_t = Teuchos::RCP<const Teuchos::Comm<int>>;
185 
186  private:
192  typedef Teuchos::ArrayRCP<int>::size_type size_type;
193 
204  static Teuchos::RCP<const map_type>
205  makeRangeMap (const trcp_tcomm_t& pComm,
206  const global_ordinal_type numRows)
207  {
208  // Return a conventional, uniformly partitioned, contiguous map.
209  return rcp (new map_type (static_cast<global_size_t> (numRows),
210  static_cast<global_ordinal_type> (0),
211  pComm, GloballyDistributed));
212  }
213 
241  static Teuchos::RCP<const map_type>
242  makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
243  const trcp_tcomm_t& pComm,
244  const global_ordinal_type numRows)
245  {
246  // If the caller didn't provide a map, return a conventional,
247  // uniformly partitioned, contiguous map.
248  if (pRowMap.is_null ()) {
249  return rcp (new map_type (static_cast<global_size_t> (numRows),
250  static_cast<global_ordinal_type> (0),
251  pComm, GloballyDistributed));
252  }
253  else {
254  TEUCHOS_TEST_FOR_EXCEPTION
255  (! pRowMap->isDistributed () && pComm->getSize () > 1,
256  std::invalid_argument, "The specified row map is not distributed, "
257  "but the given communicator includes more than one process (in "
258  "fact, there are " << pComm->getSize () << " processes).");
259  TEUCHOS_TEST_FOR_EXCEPTION
260  (pRowMap->getComm () != pComm, std::invalid_argument,
261  "The specified row Map's communicator (pRowMap->getComm()) "
262  "differs from the given separately supplied communicator pComm.");
263  return pRowMap;
264  }
265  }
266 
281  static Teuchos::RCP<const map_type>
282  makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
283  const global_ordinal_type numRows,
284  const global_ordinal_type numCols)
285  {
286  // Abbreviations so that the map creation call isn't too long.
287  typedef local_ordinal_type LO;
288  typedef global_ordinal_type GO;
289  typedef node_type NT;
290 
291  if (numRows == numCols) {
292  return pRangeMap;
293  } else {
294  return createUniformContigMapWithNode<LO,GO,NT> (numCols,
295  pRangeMap->getComm ());
296  }
297  }
298 
371  static void
372  distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
373  Teuchos::ArrayRCP<size_t>& myRowPtr,
374  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
375  Teuchos::ArrayRCP<scalar_type>& myValues,
376  const Teuchos::RCP<const map_type>& pRowMap,
377  Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
378  Teuchos::ArrayRCP<size_t>& rowPtr,
379  Teuchos::ArrayRCP<global_ordinal_type>& colInd,
380  Teuchos::ArrayRCP<scalar_type>& values,
381  const bool debug=false)
382  {
383  using Teuchos::arcp;
384  using Teuchos::ArrayRCP;
385  using Teuchos::ArrayView;
386  using Teuchos::as;
387  using Teuchos::Comm;
388  using Teuchos::CommRequest;
389  using Teuchos::null;
390  using Teuchos::RCP;
391  using Teuchos::receive;
392  using Teuchos::send;
393  using std::cerr;
394  using std::endl;
395 
396  const bool extraDebug = false;
397  trcp_tcomm_t pComm = pRowMap->getComm ();
398  const int numProcs = pComm->getSize ();
399  const int myRank = pComm->getRank ();
400  const int rootRank = 0;
401 
402  // Type abbreviations to make the code more concise.
403  typedef global_ordinal_type GO;
404 
405  // List of the global indices of my rows. They may or may
406  // not be contiguous, and the row map need not be one-to-one.
407  ArrayView<const GO> myRows = pRowMap->getLocalElementList();
408  const size_type myNumRows = myRows.size();
409  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
410  pRowMap->getLocalNumElements(),
411  std::logic_error,
412  "pRowMap->getLocalElementList().size() = "
413  << myNumRows
414  << " != pRowMap->getLocalNumElements() = "
415  << pRowMap->getLocalNumElements() << ". "
416  "Please report this bug to the Tpetra developers.");
417  TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
418  std::logic_error,
419  "On Proc 0: numEntriesPerRow.size() = "
420  << numEntriesPerRow.size()
421  << " != pRowMap->getLocalElementList().size() = "
422  << myNumRows << ". Please report this bug to the "
423  "Tpetra developers.");
424 
425  // Space for my proc's number of entries per row. Will be
426  // filled in below.
427  myNumEntriesPerRow = arcp<size_t> (myNumRows);
428 
429  if (myRank != rootRank) {
430  // Tell the root how many rows we have. If we're sending
431  // none, then we don't have anything else to send, nor does
432  // the root have to receive anything else.
433  send (*pComm, myNumRows, rootRank);
434  if (myNumRows != 0) {
435  // Now send my rows' global indices. Hopefully the cast
436  // to int doesn't overflow. This is unlikely, since it
437  // should fit in a LO, even though it is a GO.
438  send (*pComm, static_cast<int> (myNumRows),
439  myRows.getRawPtr(), rootRank);
440 
441  // I (this proc) don't care if my global row indices are
442  // contiguous, though the root proc does (since otherwise
443  // it needs to pack noncontiguous data into contiguous
444  // storage before sending). That's why we don't check
445  // for contiguousness here.
446 
447  // Ask the root process for my part of the array of the
448  // number of entries per row.
449  receive (*pComm, rootRank,
450  static_cast<int> (myNumRows),
451  myNumEntriesPerRow.getRawPtr());
452 
453  // Use the resulting array to figure out how many column
454  // indices and values I should ask from the root process.
455  const local_ordinal_type myNumEntries =
456  std::accumulate (myNumEntriesPerRow.begin(),
457  myNumEntriesPerRow.end(), 0);
458 
459  // Make space for my entries of the sparse matrix. Note
460  // that they don't have to be sorted by row index.
461  // Iterating through all my rows requires computing a
462  // running sum over myNumEntriesPerRow.
463  myColInd = arcp<GO> (myNumEntries);
464  myValues = arcp<scalar_type> (myNumEntries);
465  if (myNumEntries > 0) {
466  // Ask for that many column indices and values, if
467  // there are any.
468  receive (*pComm, rootRank,
469  static_cast<int> (myNumEntries),
470  myColInd.getRawPtr());
471  receive (*pComm, rootRank,
472  static_cast<int> (myNumEntries),
473  myValues.getRawPtr());
474  }
475  } // If I own at least one row
476  } // If I am not the root processor
477  else { // I _am_ the root processor
478  if (debug) {
479  cerr << "-- Proc 0: Copying my data from global arrays" << endl;
480  }
481  // Proc 0 still needs to (allocate, if not done already)
482  // and fill its part of the matrix (my*).
483  for (size_type k = 0; k < myNumRows; ++k) {
484  const GO myCurRow = myRows[k];
485  const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
486  myNumEntriesPerRow[k] = numEntriesInThisRow;
487  }
488  if (extraDebug && debug) {
489  cerr << "Proc " << pRowMap->getComm ()->getRank ()
490  << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
491  for (size_type k = 0; k < myNumRows; ++k) {
492  cerr << myNumEntriesPerRow[k];
493  if (k < myNumRows-1) {
494  cerr << " ";
495  }
496  }
497  cerr << "]" << endl;
498  }
499  // The total number of matrix entries that my proc owns.
500  const local_ordinal_type myNumEntries =
501  std::accumulate (myNumEntriesPerRow.begin(),
502  myNumEntriesPerRow.end(), 0);
503  if (debug) {
504  cerr << "-- Proc 0: I own " << myNumRows << " rows and "
505  << myNumEntries << " entries" << endl;
506  }
507  myColInd = arcp<GO> (myNumEntries);
508  myValues = arcp<scalar_type> (myNumEntries);
509 
510  // Copy Proc 0's part of the matrix into the my* arrays.
511  // It's important that myCurPos be updated _before_ k,
512  // otherwise myCurPos will get the wrong number of entries
513  // per row (it should be for the row in the just-completed
514  // iteration, not for the next iteration's row).
515  local_ordinal_type myCurPos = 0;
516  for (size_type k = 0; k < myNumRows;
517  myCurPos += myNumEntriesPerRow[k], ++k) {
518  const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
519  const GO myRow = myRows[k];
520  const size_t curPos = rowPtr[myRow];
521  // Only copy if there are entries to copy, in order not
522  // to construct empty ranges for the ArrayRCP views.
523  if (curNumEntries > 0) {
524  ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
525  ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
526  std::copy (colIndView.begin(), colIndView.end(),
527  myColIndView.begin());
528 
529  ArrayView<scalar_type> valuesView =
530  values (curPos, curNumEntries);
531  ArrayView<scalar_type> myValuesView =
532  myValues (myCurPos, curNumEntries);
533  std::copy (valuesView.begin(), valuesView.end(),
534  myValuesView.begin());
535  }
536  }
537 
538  // Proc 0 processes each other proc p in turn.
539  for (int p = 1; p < numProcs; ++p) {
540  if (debug) {
541  cerr << "-- Proc 0: Processing proc " << p << endl;
542  }
543 
544  size_type theirNumRows = 0;
545  // Ask Proc p how many rows it has. If it doesn't
546  // have any, we can move on to the next proc. This
547  // has to be a standard receive so that we can avoid
548  // the degenerate case of sending zero data.
549  receive (*pComm, p, &theirNumRows);
550  if (debug) {
551  cerr << "-- Proc 0: Proc " << p << " owns "
552  << theirNumRows << " rows" << endl;
553  }
554  if (theirNumRows != 0) {
555  // Ask Proc p which rows it owns. The resulting global
556  // row indices are not guaranteed to be contiguous or
557  // sorted. Global row indices are themselves indices
558  // into the numEntriesPerRow array.
559  ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
560  receive (*pComm, p, as<int> (theirNumRows),
561  theirRows.getRawPtr ());
562  // Extra test to make sure that the rows we received
563  // are all sensible. This is a good idea since we are
564  // going to use the global row indices we've received
565  // to index into the numEntriesPerRow array. Better to
566  // catch any bugs here and print a sensible error
567  // message, rather than segfault and print a cryptic
568  // error message.
569  {
570  const global_size_t numRows = pRowMap->getGlobalNumElements ();
571  const GO indexBase = pRowMap->getIndexBase ();
572  bool theirRowsValid = true;
573  for (size_type k = 0; k < theirNumRows; ++k) {
574  if (theirRows[k] < indexBase ||
575  as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
576  theirRowsValid = false;
577  }
578  }
579  if (! theirRowsValid) {
580  TEUCHOS_TEST_FOR_EXCEPTION(
581  ! theirRowsValid, std::logic_error,
582  "Proc " << p << " has at least one invalid row index. "
583  "Here are all of them: " <<
584  Teuchos::toString (theirRows ()) << ". Valid row index "
585  "range (zero-based): [0, " << (numRows - 1) << "].");
586  }
587  }
588 
589  // Perhaps we could save a little work if we check
590  // whether Proc p's row indices are contiguous. That
591  // would make lookups in the global data arrays
592  // faster. For now, we just implement the general
593  // case and don't prematurely optimize. (Remember
594  // that you're making Proc 0 read the whole file, so
595  // you've already lost scalability.)
596 
597  // Compute the number of entries in each of Proc p's
598  // rows. (Proc p will compute its row pointer array
599  // on its own, after it gets the data from Proc 0.)
600  ArrayRCP<size_t> theirNumEntriesPerRow;
601  theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
602  for (size_type k = 0; k < theirNumRows; ++k) {
603  theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
604  }
605 
606  // Tell Proc p the number of entries in each of its
607  // rows. Hopefully the cast to int doesn't overflow.
608  // This is unlikely, since it should fit in a LO,
609  // even though it is a GO.
610  send (*pComm, static_cast<int> (theirNumRows),
611  theirNumEntriesPerRow.getRawPtr(), p);
612 
613  // Figure out how many entries Proc p owns.
614  const local_ordinal_type theirNumEntries =
615  std::accumulate (theirNumEntriesPerRow.begin(),
616  theirNumEntriesPerRow.end(), 0);
617 
618  if (debug) {
619  cerr << "-- Proc 0: Proc " << p << " owns "
620  << theirNumEntries << " entries" << endl;
621  }
622 
623  // If there are no entries to send, then we're done
624  // with Proc p.
625  if (theirNumEntries == 0) {
626  continue;
627  }
628 
629  // Construct (views of) proc p's column indices and
630  // values. Later, we might like to optimize for the
631  // (common) contiguous case, for which we don't need to
632  // copy data into separate "their*" arrays (we can just
633  // use contiguous views of the global arrays).
634  ArrayRCP<GO> theirColInd (theirNumEntries);
635  ArrayRCP<scalar_type> theirValues (theirNumEntries);
636  // Copy Proc p's part of the matrix into the their*
637  // arrays. It's important that theirCurPos be updated
638  // _before_ k, otherwise theirCurPos will get the wrong
639  // number of entries per row (it should be for the row
640  // in the just-completed iteration, not for the next
641  // iteration's row).
642  local_ordinal_type theirCurPos = 0;
643  for (size_type k = 0; k < theirNumRows;
644  theirCurPos += theirNumEntriesPerRow[k], k++) {
645  const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
646  const GO theirRow = theirRows[k];
647  const local_ordinal_type curPos = rowPtr[theirRow];
648 
649  // Only copy if there are entries to copy, in order
650  // not to construct empty ranges for the ArrayRCP
651  // views.
652  if (curNumEntries > 0) {
653  ArrayView<GO> colIndView =
654  colInd (curPos, curNumEntries);
655  ArrayView<GO> theirColIndView =
656  theirColInd (theirCurPos, curNumEntries);
657  std::copy (colIndView.begin(), colIndView.end(),
658  theirColIndView.begin());
659 
660  ArrayView<scalar_type> valuesView =
661  values (curPos, curNumEntries);
662  ArrayView<scalar_type> theirValuesView =
663  theirValues (theirCurPos, curNumEntries);
664  std::copy (valuesView.begin(), valuesView.end(),
665  theirValuesView.begin());
666  }
667  }
668  // Send Proc p its column indices and values.
669  // Hopefully the cast to int doesn't overflow. This
670  // is unlikely, since it should fit in a LO, even
671  // though it is a GO.
672  send (*pComm, static_cast<int> (theirNumEntries),
673  theirColInd.getRawPtr(), p);
674  send (*pComm, static_cast<int> (theirNumEntries),
675  theirValues.getRawPtr(), p);
676 
677  if (debug) {
678  cerr << "-- Proc 0: Finished with proc " << p << endl;
679  }
680  } // If proc p owns at least one row
681  } // For each proc p not the root proc 0
682  } // If I'm (not) the root proc 0
683 
684  // Invalidate the input data to save space, since we don't
685  // need it anymore.
686  numEntriesPerRow = null;
687  rowPtr = null;
688  colInd = null;
689  values = null;
690 
691  if (debug && myRank == 0) {
692  cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
693  }
694 
695  // Allocate and fill in myRowPtr (the row pointer array for
696  // my rank's rows). We delay this until the end because we
697  // don't need it to compute anything else in distribute().
698  // Each proc can do this work for itself, since it only needs
699  // myNumEntriesPerRow to do so.
700  myRowPtr = arcp<size_t> (myNumRows+1);
701  myRowPtr[0] = 0;
702  for (size_type k = 1; k < myNumRows+1; ++k) {
703  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
704  }
705  if (extraDebug && debug) {
706  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
707  << ": myRowPtr[0.." << myNumRows << "] = [";
708  for (size_type k = 0; k < myNumRows+1; ++k) {
709  cerr << myRowPtr[k];
710  if (k < myNumRows) {
711  cerr << " ";
712  }
713  }
714  cerr << "]" << endl << endl;
715  }
716 
717  if (debug && myRank == 0) {
718  cerr << "-- Proc 0: Done with distribute" << endl;
719  }
720  }
721 
735  static Teuchos::RCP<sparse_matrix_type>
736  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
737  Teuchos::ArrayRCP<size_t>& myRowPtr,
738  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
739  Teuchos::ArrayRCP<scalar_type>& myValues,
740  const Teuchos::RCP<const map_type>& pRowMap,
741  const Teuchos::RCP<const map_type>& pRangeMap,
742  const Teuchos::RCP<const map_type>& pDomainMap,
743  const bool callFillComplete = true)
744  {
745  using Teuchos::ArrayView;
746  using Teuchos::null;
747  using Teuchos::RCP;
748  using Teuchos::rcp;
749  using std::cerr;
750  using std::endl;
751  // Typedef to make certain type declarations shorter.
752  typedef global_ordinal_type GO;
753 
754  // The row pointer array always has at least one entry, even
755  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
756  // and myValues would all be empty arrays in that degenerate
757  // case, but the row and domain maps would still be nonnull
758  // (though they would be trivial maps).
759  TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
760  "makeMatrix: myRowPtr array is null. "
761  "Please report this bug to the Tpetra developers.");
762  TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
763  "makeMatrix: domain map is null. "
764  "Please report this bug to the Tpetra developers.");
765  TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
766  "makeMatrix: range map is null. "
767  "Please report this bug to the Tpetra developers.");
768  TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
769  "makeMatrix: row map is null. "
770  "Please report this bug to the Tpetra developers.");
771 
772  // Construct the CrsMatrix, using the row map, with the
773  // constructor specifying the number of nonzeros for each row.
774  RCP<sparse_matrix_type> A =
775  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow ()));
776 
777  // List of the global indices of my rows.
778  // They may or may not be contiguous.
779  ArrayView<const GO> myRows = pRowMap->getLocalElementList ();
780  const size_type myNumRows = myRows.size ();
781 
782  // Add this processor's matrix entries to the CrsMatrix.
783  const GO indexBase = pRowMap->getIndexBase ();
784  for (size_type i = 0; i < myNumRows; ++i) {
785  const size_type myCurPos = myRowPtr[i];
786  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
787  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
788  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
789 
790  // Modify the column indices in place to have the right index base.
791  for (size_type k = 0; k < curNumEntries; ++k) {
792  curColInd[k] += indexBase;
793  }
794  // Avoid constructing empty views of ArrayRCP objects.
795  if (curNumEntries > 0) {
796  A->insertGlobalValues (myRows[i], curColInd, curValues);
797  }
798  }
799  // We've entered in all our matrix entries, so we can delete
800  // the original data. This will save memory when we call
801  // fillComplete(), so that we never keep more than two copies
802  // of the matrix's data in memory at once.
803  myNumEntriesPerRow = null;
804  myRowPtr = null;
805  myColInd = null;
806  myValues = null;
807 
808  if (callFillComplete) {
809  A->fillComplete (pDomainMap, pRangeMap);
810  }
811  return A;
812  }
813 
819  static Teuchos::RCP<sparse_matrix_type>
820  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
821  Teuchos::ArrayRCP<size_t>& myRowPtr,
822  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
823  Teuchos::ArrayRCP<scalar_type>& myValues,
824  const Teuchos::RCP<const map_type>& pRowMap,
825  const Teuchos::RCP<const map_type>& pRangeMap,
826  const Teuchos::RCP<const map_type>& pDomainMap,
827  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
828  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
829  {
830  using Teuchos::ArrayView;
831  using Teuchos::null;
832  using Teuchos::RCP;
833  using Teuchos::rcp;
834  using std::cerr;
835  using std::endl;
836  // Typedef to make certain type declarations shorter.
837  typedef global_ordinal_type GO;
838 
839  // The row pointer array always has at least one entry, even
840  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
841  // and myValues would all be empty arrays in that degenerate
842  // case, but the row and domain maps would still be nonnull
843  // (though they would be trivial maps).
844  TEUCHOS_TEST_FOR_EXCEPTION(
845  myRowPtr.is_null(), std::logic_error,
846  "makeMatrix: myRowPtr array is null. "
847  "Please report this bug to the Tpetra developers.");
848  TEUCHOS_TEST_FOR_EXCEPTION(
849  pDomainMap.is_null(), std::logic_error,
850  "makeMatrix: domain map is null. "
851  "Please report this bug to the Tpetra developers.");
852  TEUCHOS_TEST_FOR_EXCEPTION(
853  pRangeMap.is_null(), std::logic_error,
854  "makeMatrix: range map is null. "
855  "Please report this bug to the Tpetra developers.");
856  TEUCHOS_TEST_FOR_EXCEPTION(
857  pRowMap.is_null(), std::logic_error,
858  "makeMatrix: row map is null. "
859  "Please report this bug to the Tpetra developers.");
860 
861  // Construct the CrsMatrix, using the row map, with the
862  // constructor specifying the number of nonzeros for each row.
863  RCP<sparse_matrix_type> A =
864  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
865  constructorParams));
866 
867  // List of the global indices of my rows.
868  // They may or may not be contiguous.
869  ArrayView<const GO> myRows = pRowMap->getLocalElementList();
870  const size_type myNumRows = myRows.size();
871 
872  // Add this processor's matrix entries to the CrsMatrix.
873  const GO indexBase = pRowMap->getIndexBase ();
874  for (size_type i = 0; i < myNumRows; ++i) {
875  const size_type myCurPos = myRowPtr[i];
876  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
877  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
878  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
879 
880  // Modify the column indices in place to have the right index base.
881  for (size_type k = 0; k < curNumEntries; ++k) {
882  curColInd[k] += indexBase;
883  }
884  if (curNumEntries > 0) {
885  A->insertGlobalValues (myRows[i], curColInd, curValues);
886  }
887  }
888  // We've entered in all our matrix entries, so we can delete
889  // the original data. This will save memory when we call
890  // fillComplete(), so that we never keep more than two copies
891  // of the matrix's data in memory at once.
892  myNumEntriesPerRow = null;
893  myRowPtr = null;
894  myColInd = null;
895  myValues = null;
896 
897  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
898  return A;
899  }
900 
905  static Teuchos::RCP<sparse_matrix_type>
906  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
907  Teuchos::ArrayRCP<size_t>& myRowPtr,
908  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
909  Teuchos::ArrayRCP<scalar_type>& myValues,
910  const Teuchos::RCP<const map_type>& rowMap,
911  Teuchos::RCP<const map_type>& colMap,
912  const Teuchos::RCP<const map_type>& domainMap,
913  const Teuchos::RCP<const map_type>& rangeMap,
914  const bool callFillComplete = true)
915  {
916  using Teuchos::ArrayView;
917  using Teuchos::as;
918  using Teuchos::null;
919  using Teuchos::RCP;
920  using Teuchos::rcp;
921  typedef global_ordinal_type GO;
922 
923  // Construct the CrsMatrix.
924 
925  RCP<sparse_matrix_type> A; // the matrix to return.
926  if (colMap.is_null ()) { // the user didn't provide a column Map
927  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow));
928  } else { // the user provided a column Map
929  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow));
930  }
931 
932  // List of the global indices of my rows.
933  // They may or may not be contiguous.
934  ArrayView<const GO> myRows = rowMap->getLocalElementList ();
935  const size_type myNumRows = myRows.size ();
936 
937  // Add this process' matrix entries to the CrsMatrix.
938  const GO indexBase = rowMap->getIndexBase ();
939  for (size_type i = 0; i < myNumRows; ++i) {
940  const size_type myCurPos = myRowPtr[i];
941  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
942  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
943  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
944 
945  // Modify the column indices in place to have the right index base.
946  for (size_type k = 0; k < curNumEntries; ++k) {
947  curColInd[k] += indexBase;
948  }
949  if (curNumEntries > 0) {
950  A->insertGlobalValues (myRows[i], curColInd, curValues);
951  }
952  }
953  // We've entered in all our matrix entries, so we can delete
954  // the original data. This will save memory when we call
955  // fillComplete(), so that we never keep more than two copies
956  // of the matrix's data in memory at once.
957  myNumEntriesPerRow = null;
958  myRowPtr = null;
959  myColInd = null;
960  myValues = null;
961 
962  if (callFillComplete) {
963  A->fillComplete (domainMap, rangeMap);
964  if (colMap.is_null ()) {
965  colMap = A->getColMap ();
966  }
967  }
968  return A;
969  }
970 
971  private:
972 
989  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
990  readBanner (std::istream& in,
991  size_t& lineNumber,
992  const bool tolerant=false,
993  const bool /* debug */=false,
994  const bool isGraph=false)
995  {
996  using Teuchos::MatrixMarket::Banner;
997  using Teuchos::RCP;
998  using Teuchos::rcp;
999  using std::cerr;
1000  using std::endl;
1001  typedef Teuchos::ScalarTraits<scalar_type> STS;
1002 
1003  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1004  std::string line; // If read from stream successful: the Banner line
1005 
1006  // Try to read a line from the input stream.
1007  const bool readFailed = ! getline(in, line);
1008  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1009  "Failed to get Matrix Market banner line from input.");
1010 
1011  // We read a line from the input stream.
1012  lineNumber++;
1013 
1014  // Assume that the line we found is the Banner line.
1015  try {
1016  pBanner = rcp (new Banner (line, tolerant));
1017  } catch (std::exception& e) {
1018 
1019  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1020  "Matrix Market banner line contains syntax error(s): "
1021  << e.what());
1022  }
1023 
1024  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1025  std::invalid_argument, "The Matrix Market file does not contain "
1026  "matrix data. Its Banner (first) line says that its object type is \""
1027  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1028 
1029  // Validate the data type of the matrix, with respect to the
1030  // Scalar type of the CrsMatrix entries.
1031  TEUCHOS_TEST_FOR_EXCEPTION(
1032  ! STS::isComplex && pBanner->dataType() == "complex",
1033  std::invalid_argument,
1034  "The Matrix Market file contains complex-valued data, but you are "
1035  "trying to read it into a matrix containing entries of the real-"
1036  "valued Scalar type \""
1037  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1038  TEUCHOS_TEST_FOR_EXCEPTION(
1039  !isGraph &&
1040  pBanner->dataType() != "real" &&
1041  pBanner->dataType() != "complex" &&
1042  pBanner->dataType() != "integer",
1043  std::invalid_argument,
1044  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1045  "Matrix Market file may not contain a \"pattern\" matrix. A "
1046  "pattern matrix is really just a graph with no weights. It "
1047  "should be stored in a CrsGraph, not a CrsMatrix.");
1048 
1049  TEUCHOS_TEST_FOR_EXCEPTION(
1050  isGraph &&
1051  pBanner->dataType() != "pattern",
1052  std::invalid_argument,
1053  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1054  "Matrix Market file must contain a \"pattern\" matrix.");
1055 
1056  return pBanner;
1057  }
1058 
1081  static Teuchos::Tuple<global_ordinal_type, 3>
1082  readCoordDims (std::istream& in,
1083  size_t& lineNumber,
1084  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1085  const trcp_tcomm_t& pComm,
1086  const bool tolerant = false,
1087  const bool /* debug */ = false)
1088  {
1089  using Teuchos::MatrixMarket::readCoordinateDimensions;
1090  using Teuchos::Tuple;
1091 
1092  // Packed coordinate matrix dimensions (numRows, numCols,
1093  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1094  // ranks.
1095  Tuple<global_ordinal_type, 3> dims;
1096 
1097  // Read in the coordinate matrix dimensions from the input
1098  // stream. "success" tells us whether reading in the
1099  // coordinate matrix dimensions succeeded ("Guilty unless
1100  // proven innocent").
1101  bool success = false;
1102  if (pComm->getRank() == 0) {
1103  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1104  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1105  "only accepts \"coordinate\" (sparse) matrix data.");
1106  // Unpacked coordinate matrix dimensions
1107  global_ordinal_type numRows, numCols, numNonzeros;
1108  // Only MPI Rank 0 reads from the input stream
1109  success = readCoordinateDimensions (in, numRows, numCols,
1110  numNonzeros, lineNumber,
1111  tolerant);
1112  // Pack up the data into a Tuple so we can send them with
1113  // one broadcast instead of three.
1114  dims[0] = numRows;
1115  dims[1] = numCols;
1116  dims[2] = numNonzeros;
1117  }
1118  // Only Rank 0 did the reading, so it decides success.
1119  //
1120  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1121  // to send bools. For now, we convert to/from int instead,
1122  // using the usual "true is 1, false is 0" encoding.
1123  {
1124  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1125  Teuchos::broadcast (*pComm, 0, &the_success);
1126  success = (the_success == 1);
1127  }
1128  if (success) {
1129  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1130  // to all the other MPI ranks.
1131  Teuchos::broadcast (*pComm, 0, dims);
1132  }
1133  else {
1134  // Perhaps in tolerant mode, we could set all the
1135  // dimensions to zero for now, and deduce correct
1136  // dimensions by reading all of the file's entries and
1137  // computing the max(row index) and max(column index).
1138  // However, for now we just error out in that case.
1139  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1140  "Error reading Matrix Market sparse matrix: failed to read "
1141  "coordinate matrix dimensions.");
1142  }
1143  return dims;
1144  }
1145 
1156  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1157 
1158  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1159 
1185  static Teuchos::RCP<adder_type>
1186  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1187  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1188  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1189  const bool tolerant=false,
1190  const bool debug=false)
1191  {
1192  if (pComm->getRank () == 0) {
1193  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1195  raw_adder_type;
1196  Teuchos::RCP<raw_adder_type> pRaw =
1197  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1198  tolerant, debug));
1199  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1200  }
1201  else {
1202  return Teuchos::null;
1203  }
1204  }
1205 
1231  static Teuchos::RCP<graph_adder_type>
1232  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1233  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1234  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1235  const bool tolerant=false,
1236  const bool debug=false)
1237  {
1238  if (pComm->getRank () == 0) {
1239  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1240  Teuchos::RCP<raw_adder_type> pRaw =
1241  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1242  tolerant, debug));
1243  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1244  }
1245  else {
1246  return Teuchos::null;
1247  }
1248  }
1249 
1251  static Teuchos::RCP<sparse_graph_type>
1252  readSparseGraphHelper (std::istream& in,
1253  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1254  const Teuchos::RCP<const map_type>& rowMap,
1255  Teuchos::RCP<const map_type>& colMap,
1256  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1257  const bool tolerant,
1258  const bool debug)
1259  {
1260  using Teuchos::MatrixMarket::Banner;
1261  using Teuchos::RCP;
1262  using Teuchos::ptr;
1263  using Teuchos::Tuple;
1264  using std::cerr;
1265  using std::endl;
1266 
1267  const int myRank = pComm->getRank ();
1268  const int rootRank = 0;
1269 
1270  // Current line number in the input stream. Various calls
1271  // will modify this depending on the number of lines that are
1272  // read from the input stream. Only Rank 0 modifies this.
1273  size_t lineNumber = 1;
1274 
1275  if (debug && myRank == rootRank) {
1276  cerr << "Matrix Market reader: readGraph:" << endl
1277  << "-- Reading banner line" << endl;
1278  }
1279 
1280  // The "Banner" tells you whether the input stream represents
1281  // a sparse matrix, the symmetry type of the matrix, and the
1282  // type of the data it contains.
1283  //
1284  // pBanner will only be nonnull on MPI Rank 0. It will be
1285  // null on all other MPI processes.
1286  RCP<const Banner> pBanner;
1287  {
1288  // We read and validate the Banner on Proc 0, but broadcast
1289  // the validation result to all processes.
1290  // Teuchos::broadcast doesn't currently work with bool, so
1291  // we use int (true -> 1, false -> 0).
1292  int bannerIsCorrect = 1;
1293  std::ostringstream errMsg;
1294 
1295  if (myRank == rootRank) {
1296  // Read the Banner line from the input stream.
1297  try {
1298  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1299  }
1300  catch (std::exception& e) {
1301  errMsg << "Attempt to read the Matrix Market file's Banner line "
1302  "threw an exception: " << e.what();
1303  bannerIsCorrect = 0;
1304  }
1305 
1306  if (bannerIsCorrect) {
1307  // Validate the Banner for the case of a sparse graph.
1308  // We validate on Proc 0, since it reads the Banner.
1309 
1310  // In intolerant mode, the matrix type must be "coordinate".
1311  if (! tolerant && pBanner->matrixType() != "coordinate") {
1312  bannerIsCorrect = 0;
1313  errMsg << "The Matrix Market input file must contain a "
1314  "\"coordinate\"-format sparse graph in order to create a "
1315  "Tpetra::CrsGraph object from it, but the file's matrix "
1316  "type is \"" << pBanner->matrixType() << "\" instead.";
1317  }
1318  // In tolerant mode, we allow the matrix type to be
1319  // anything other than "array" (which would mean that
1320  // the file contains a dense matrix).
1321  if (tolerant && pBanner->matrixType() == "array") {
1322  bannerIsCorrect = 0;
1323  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1324  "format sparse graph in order to create a Tpetra::CrsGraph "
1325  "object from it, but the file's matrix type is \"array\" "
1326  "instead. That probably means the file contains dense matrix "
1327  "data.";
1328  }
1329  }
1330  } // Proc 0: Done reading the Banner, hopefully successfully.
1331 
1332  // Broadcast from Proc 0 whether the Banner was read correctly.
1333  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1334 
1335  // If the Banner is invalid, all processes throw an
1336  // exception. Only Proc 0 gets the exception message, but
1337  // that's OK, since the main point is to "stop the world"
1338  // (rather than throw an exception on one process and leave
1339  // the others hanging).
1340  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1341  std::invalid_argument, errMsg.str ());
1342  } // Done reading the Banner line and broadcasting success.
1343  if (debug && myRank == rootRank) {
1344  cerr << "-- Reading dimensions line" << endl;
1345  }
1346 
1347  // Read the graph dimensions from the Matrix Market metadata.
1348  // dims = (numRows, numCols, numEntries). Proc 0 does the
1349  // reading, but it broadcasts the results to all MPI
1350  // processes. Thus, readCoordDims() is a collective
1351  // operation. It does a collective check for correctness too.
1352  Tuple<global_ordinal_type, 3> dims =
1353  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1354 
1355  if (debug && myRank == rootRank) {
1356  cerr << "-- Making Adder for collecting graph data" << endl;
1357  }
1358 
1359  // "Adder" object for collecting all the sparse graph entries
1360  // from the input stream. This is only nonnull on Proc 0.
1361  // The Adder internally converts the one-based indices (native
1362  // Matrix Market format) into zero-based indices.
1363  RCP<graph_adder_type> pAdder =
1364  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1365 
1366  if (debug && myRank == rootRank) {
1367  cerr << "-- Reading graph data" << endl;
1368  }
1369  //
1370  // Read the graph entries from the input stream on Proc 0.
1371  //
1372  {
1373  // We use readSuccess to broadcast the results of the read
1374  // (succeeded or not) to all MPI processes. Since
1375  // Teuchos::broadcast doesn't currently know how to send
1376  // bools, we convert to int (true -> 1, false -> 0).
1377  int readSuccess = 1;
1378  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1379  if (myRank == rootRank) {
1380  try {
1381  // Reader for "coordinate" format sparse graph data.
1382  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1383  global_ordinal_type> reader_type;
1384  reader_type reader (pAdder);
1385 
1386  // Read the sparse graph entries.
1387  std::pair<bool, std::vector<size_t> > results =
1388  reader.read (in, lineNumber, tolerant, debug);
1389  readSuccess = results.first ? 1 : 0;
1390  }
1391  catch (std::exception& e) {
1392  readSuccess = 0;
1393  errMsg << e.what();
1394  }
1395  }
1396  broadcast (*pComm, rootRank, ptr (&readSuccess));
1397 
1398  // It would be nice to add a "verbose" flag, so that in
1399  // tolerant mode, we could log any bad line number(s) on
1400  // Proc 0. For now, we just throw if the read fails to
1401  // succeed.
1402  //
1403  // Question: If we're in tolerant mode, and if the read did
1404  // not succeed, should we attempt to call fillComplete()?
1405  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1406  "Failed to read the Matrix Market sparse graph file: "
1407  << errMsg.str());
1408  } // Done reading the graph entries (stored on Proc 0 for now)
1409 
1410  if (debug && myRank == rootRank) {
1411  cerr << "-- Successfully read the Matrix Market data" << endl;
1412  }
1413 
1414  // In tolerant mode, we need to rebroadcast the graph
1415  // dimensions, since they may be different after reading the
1416  // actual graph data. We only need to broadcast the number
1417  // of rows and columns. Only Rank 0 needs to know the actual
1418  // global number of entries, since (a) we need to merge
1419  // duplicates on Rank 0 first anyway, and (b) when we
1420  // distribute the entries, each rank other than Rank 0 will
1421  // only need to know how many entries it owns, not the total
1422  // number of entries.
1423  if (tolerant) {
1424  if (debug && myRank == rootRank) {
1425  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1426  << endl
1427  << "----- Dimensions before: "
1428  << dims[0] << " x " << dims[1]
1429  << endl;
1430  }
1431  // Packed coordinate graph dimensions (numRows, numCols).
1432  Tuple<global_ordinal_type, 2> updatedDims;
1433  if (myRank == rootRank) {
1434  // If one or more bottom rows of the graph contain no
1435  // entries, then the Adder will report that the number
1436  // of rows is less than that specified in the
1437  // metadata. We allow this case, and favor the
1438  // metadata so that the zero row(s) will be included.
1439  updatedDims[0] =
1440  std::max (dims[0], pAdder->getAdder()->numRows());
1441  updatedDims[1] = pAdder->getAdder()->numCols();
1442  }
1443  broadcast (*pComm, rootRank, updatedDims);
1444  dims[0] = updatedDims[0];
1445  dims[1] = updatedDims[1];
1446  if (debug && myRank == rootRank) {
1447  cerr << "----- Dimensions after: " << dims[0] << " x "
1448  << dims[1] << endl;
1449  }
1450  }
1451  else {
1452  // In strict mode, we require that the graph's metadata and
1453  // its actual data agree, at least somewhat. In particular,
1454  // the number of rows must agree, since otherwise we cannot
1455  // distribute the graph correctly.
1456 
1457  // Teuchos::broadcast() doesn't know how to broadcast bools,
1458  // so we use an int with the standard 1 == true, 0 == false
1459  // encoding.
1460  int dimsMatch = 1;
1461  if (myRank == rootRank) {
1462  // If one or more bottom rows of the graph contain no
1463  // entries, then the Adder will report that the number of
1464  // rows is less than that specified in the metadata. We
1465  // allow this case, and favor the metadata, but do not
1466  // allow the Adder to think there are more rows in the
1467  // graph than the metadata says.
1468  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1469  dimsMatch = 0;
1470  }
1471  }
1472  broadcast (*pComm, 0, ptr (&dimsMatch));
1473  if (dimsMatch == 0) {
1474  // We're in an error state anyway, so we might as well
1475  // work a little harder to print an informative error
1476  // message.
1477  //
1478  // Broadcast the Adder's idea of the graph dimensions
1479  // from Proc 0 to all processes.
1480  Tuple<global_ordinal_type, 2> addersDims;
1481  if (myRank == rootRank) {
1482  addersDims[0] = pAdder->getAdder()->numRows();
1483  addersDims[1] = pAdder->getAdder()->numCols();
1484  }
1485  broadcast (*pComm, 0, addersDims);
1486  TEUCHOS_TEST_FOR_EXCEPTION(
1487  dimsMatch == 0, std::runtime_error,
1488  "The graph metadata says that the graph is " << dims[0] << " x "
1489  << dims[1] << ", but the actual data says that the graph is "
1490  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1491  "data includes more rows than reported in the metadata. This "
1492  "is not allowed when parsing in strict mode. Parse the graph in "
1493  "tolerant mode to ignore the metadata when it disagrees with the "
1494  "data.");
1495  }
1496  } // Matrix dimensions (# rows, # cols, # entries) agree.
1497 
1498  // Create a map describing a distribution where the root owns EVERYTHING
1499  RCP<map_type> proc0Map;
1500  global_ordinal_type indexBase;
1501  if(Teuchos::is_null(rowMap)) {
1502  indexBase = 0;
1503  }
1504  else {
1505  indexBase = rowMap->getIndexBase();
1506  }
1507  if(myRank == rootRank) {
1508  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1509  }
1510  else {
1511  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1512  }
1513 
1514  // Create the graph where the root owns EVERYTHING
1515  std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1516  if (myRank == rootRank) {
1517  const auto& entries = pAdder()->getAdder()->getEntries();
1518  // This will count duplicates, but it's better than dense.
1519  // An even better approach would use a classic algorithm,
1520  // likely in Saad's old textbook, for converting COO (entries)
1521  // to CSR (the local part of the sparse matrix data structure).
1522  for (const auto& entry : entries) {
1523  const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1524  ++numEntriesPerRow_map[gblRow];
1525  }
1526  }
1527 
1528  Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getLocalNumElements ());
1529  for (const auto& ent : numEntriesPerRow_map) {
1530  const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1531  numEntriesPerRow[lclRow] = ent.second;
1532  }
1533  // Free anything we don't need before allocating the graph.
1534  // Swapping with an empty data structure is the standard idiom
1535  // for freeing memory used by Standard Library containers.
1536  // (Just resizing to 0 doesn't promise to free memory.)
1537  {
1538  std::map<global_ordinal_type, size_t> empty_map;
1539  std::swap (numEntriesPerRow_map, empty_map);
1540  }
1541 
1542  RCP<sparse_graph_type> proc0Graph =
1543  rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1544  constructorParams));
1545  if(myRank == rootRank) {
1546  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1547 
1548  // Get the entries
1549  const std::vector<element_type>& entries =
1550  pAdder->getAdder()->getEntries();
1551 
1552  // Insert them one at a time
1553  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1554  const element_type& curEntry = entries[curPos];
1555  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1556  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1557  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1558  proc0Graph->insertGlobalIndices(curRow,colView);
1559  }
1560  }
1561  proc0Graph->fillComplete();
1562 
1563  RCP<sparse_graph_type> distGraph;
1564  if(Teuchos::is_null(rowMap))
1565  {
1566  // Create a map describing the distribution we actually want
1567  RCP<map_type> distMap =
1568  rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1569 
1570  // Create the graph with that distribution too
1571  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,constructorParams));
1572 
1573  // Create an importer/exporter/vandelay to redistribute the graph
1574  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1575  import_type importer (proc0Map, distMap);
1576 
1577  // Import the data
1578  distGraph->doImport(*proc0Graph,importer,INSERT);
1579  }
1580  else {
1581  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,constructorParams));
1582 
1583  // Create an importer/exporter/vandelay to redistribute the graph
1584  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1585  import_type importer (proc0Map, rowMap);
1586 
1587  // Import the data
1588  distGraph->doImport(*proc0Graph,importer,INSERT);
1589  }
1590 
1591  return distGraph;
1592  }
1593 
1594  public:
1618  static Teuchos::RCP<sparse_graph_type>
1619  readSparseGraphFile (const std::string& filename,
1620  const trcp_tcomm_t& comm,
1621  const bool callFillComplete=true,
1622  const bool tolerant=false,
1623  const bool debug=false)
1624  {
1625  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
1626 
1627  return readSparseGraph (in, comm,
1628  callFillComplete,
1629  tolerant, debug);
1630  // We can rely on the destructor of the input stream to close
1631  // the file on scope exit, even if readSparseGraph() throws an
1632  // exception.
1633  }
1634 
1635 
1664  static Teuchos::RCP<sparse_graph_type>
1665  readSparseGraphFile (const std::string& filename,
1666  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1667  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1668  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1669  const bool tolerant=false,
1670  const bool debug=false)
1671  {
1672  std::ifstream in = Reader::openInFileOnRankZero(pComm, filename, true);
1673 
1674  return readSparseGraph (in, pComm,
1675  constructorParams,
1676  fillCompleteParams, tolerant, debug);
1677  // We can rely on the destructor of the input stream to close
1678  // the file on scope exit, even if readSparseGraph() throws an
1679  // exception.
1680  }
1681 
1682 
1720  static Teuchos::RCP<sparse_graph_type>
1721  readSparseGraphFile (const std::string& filename,
1722  const Teuchos::RCP<const map_type>& rowMap,
1723  Teuchos::RCP<const map_type>& colMap,
1724  const Teuchos::RCP<const map_type>& domainMap,
1725  const Teuchos::RCP<const map_type>& rangeMap,
1726  const bool callFillComplete=true,
1727  const bool tolerant=false,
1728  const bool debug=false)
1729  {
1730  TEUCHOS_TEST_FOR_EXCEPTION
1731  (rowMap.is_null (), std::invalid_argument,
1732  "Input rowMap must be nonnull.");
1733  trcp_tcomm_t comm = rowMap->getComm ();
1734  if (comm.is_null ()) {
1735  // If the input communicator is null on some process, then
1736  // that process does not participate in the collective.
1737  return Teuchos::null;
1738  }
1739 
1740  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
1741 
1742  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1743  callFillComplete, tolerant, debug);
1744  }
1745 
1771  static Teuchos::RCP<sparse_graph_type>
1772  readSparseGraph (std::istream& in,
1773  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1774  const bool callFillComplete=true,
1775  const bool tolerant=false,
1776  const bool debug=false)
1777  {
1778  Teuchos::RCP<const map_type> fakeRowMap;
1779  Teuchos::RCP<const map_type> fakeColMap;
1780  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1781 
1782  Teuchos::RCP<sparse_graph_type> graph =
1783  readSparseGraphHelper (in, pComm,
1784  fakeRowMap, fakeColMap,
1785  fakeCtorParams, tolerant, debug);
1786  if (callFillComplete) {
1787  graph->fillComplete ();
1788  }
1789  return graph;
1790  }
1791 
1792 
1822  static Teuchos::RCP<sparse_graph_type>
1823  readSparseGraph (std::istream& in,
1824  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1825  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1826  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1827  const bool tolerant=false,
1828  const bool debug=false)
1829  {
1830  Teuchos::RCP<const map_type> fakeRowMap;
1831  Teuchos::RCP<const map_type> fakeColMap;
1832  Teuchos::RCP<sparse_graph_type> graph =
1833  readSparseGraphHelper (in, pComm,
1834  fakeRowMap, fakeColMap,
1835  constructorParams, tolerant, debug);
1836  graph->fillComplete (fillCompleteParams);
1837  return graph;
1838  }
1839 
1840 
1881  static Teuchos::RCP<sparse_graph_type>
1882  readSparseGraph (std::istream& in,
1883  const Teuchos::RCP<const map_type>& rowMap,
1884  Teuchos::RCP<const map_type>& colMap,
1885  const Teuchos::RCP<const map_type>& domainMap,
1886  const Teuchos::RCP<const map_type>& rangeMap,
1887  const bool callFillComplete=true,
1888  const bool tolerant=false,
1889  const bool debug=false)
1890  {
1891  Teuchos::RCP<sparse_graph_type> graph =
1892  readSparseGraphHelper (in, rowMap->getComm (),
1893  rowMap, colMap, Teuchos::null, tolerant,
1894  debug);
1895  if (callFillComplete) {
1896  graph->fillComplete (domainMap, rangeMap);
1897  }
1898  return graph;
1899  }
1900 
1901 #include "MatrixMarket_TpetraNew.hpp"
1902 
1926  static Teuchos::RCP<sparse_matrix_type>
1927  readSparseFile (const std::string& filename,
1928  const trcp_tcomm_t& comm,
1929  const bool callFillComplete=true,
1930  const bool tolerant=false,
1931  const bool debug=false)
1932  {
1933  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
1934 
1935  return readSparse (in, comm, callFillComplete, tolerant, debug);
1936  // We can rely on the destructor of the input stream to close
1937  // the file on scope exit, even if readSparse() throws an
1938  // exception.
1939  }
1940 
1941 
1970  static Teuchos::RCP<sparse_matrix_type>
1971  readSparseFile (const std::string& filename,
1972  const trcp_tcomm_t& comm,
1973  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1974  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1975  const bool tolerant=false,
1976  const bool debug=false)
1977  {
1978  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
1979 
1980  return readSparse (in, comm, constructorParams,
1981  fillCompleteParams, tolerant, debug);
1982  }
1983 
1984 
2022  static Teuchos::RCP<sparse_matrix_type>
2023  readSparseFile (const std::string& filename,
2024  const Teuchos::RCP<const map_type>& rowMap,
2025  Teuchos::RCP<const map_type>& colMap,
2026  const Teuchos::RCP<const map_type>& domainMap,
2027  const Teuchos::RCP<const map_type>& rangeMap,
2028  const bool callFillComplete=true,
2029  const bool tolerant=false,
2030  const bool debug=false)
2031  {
2032  TEUCHOS_TEST_FOR_EXCEPTION(
2033  rowMap.is_null (), std::invalid_argument,
2034  "Row Map must be nonnull.");
2035 
2036  trcp_tcomm_t comm = rowMap->getComm ();
2037 
2038  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
2039 
2040  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2041  callFillComplete, tolerant, debug);
2042  }
2043 
2069  static Teuchos::RCP<sparse_matrix_type>
2070  readSparse (std::istream& in,
2071  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2072  const bool callFillComplete=true,
2073  const bool tolerant=false,
2074  const bool debug=false)
2075  {
2076  using Teuchos::MatrixMarket::Banner;
2077  using Teuchos::arcp;
2078  using Teuchos::ArrayRCP;
2079  using Teuchos::broadcast;
2080  using Teuchos::null;
2081  using Teuchos::ptr;
2082  using Teuchos::RCP;
2083  using Teuchos::REDUCE_MAX;
2084  using Teuchos::reduceAll;
2085  using Teuchos::Tuple;
2086  using std::cerr;
2087  using std::endl;
2088  typedef Teuchos::ScalarTraits<scalar_type> STS;
2089 
2090  const bool extraDebug = false;
2091  const int myRank = pComm->getRank ();
2092  const int rootRank = 0;
2093 
2094  // Current line number in the input stream. Various calls
2095  // will modify this depending on the number of lines that are
2096  // read from the input stream. Only Rank 0 modifies this.
2097  size_t lineNumber = 1;
2098 
2099  if (debug && myRank == rootRank) {
2100  cerr << "Matrix Market reader: readSparse:" << endl
2101  << "-- Reading banner line" << endl;
2102  }
2103 
2104  // The "Banner" tells you whether the input stream represents
2105  // a sparse matrix, the symmetry type of the matrix, and the
2106  // type of the data it contains.
2107  //
2108  // pBanner will only be nonnull on MPI Rank 0. It will be
2109  // null on all other MPI processes.
2110  RCP<const Banner> pBanner;
2111  {
2112  // We read and validate the Banner on Proc 0, but broadcast
2113  // the validation result to all processes.
2114  // Teuchos::broadcast doesn't currently work with bool, so
2115  // we use int (true -> 1, false -> 0).
2116  int bannerIsCorrect = 1;
2117  std::ostringstream errMsg;
2118 
2119  if (myRank == rootRank) {
2120  // Read the Banner line from the input stream.
2121  try {
2122  pBanner = readBanner (in, lineNumber, tolerant, debug);
2123  }
2124  catch (std::exception& e) {
2125  errMsg << "Attempt to read the Matrix Market file's Banner line "
2126  "threw an exception: " << e.what();
2127  bannerIsCorrect = 0;
2128  }
2129 
2130  if (bannerIsCorrect) {
2131  // Validate the Banner for the case of a sparse matrix.
2132  // We validate on Proc 0, since it reads the Banner.
2133 
2134  // In intolerant mode, the matrix type must be "coordinate".
2135  if (! tolerant && pBanner->matrixType() != "coordinate") {
2136  bannerIsCorrect = 0;
2137  errMsg << "The Matrix Market input file must contain a "
2138  "\"coordinate\"-format sparse matrix in order to create a "
2139  "Tpetra::CrsMatrix object from it, but the file's matrix "
2140  "type is \"" << pBanner->matrixType() << "\" instead.";
2141  }
2142  // In tolerant mode, we allow the matrix type to be
2143  // anything other than "array" (which would mean that
2144  // the file contains a dense matrix).
2145  if (tolerant && pBanner->matrixType() == "array") {
2146  bannerIsCorrect = 0;
2147  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2148  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2149  "object from it, but the file's matrix type is \"array\" "
2150  "instead. That probably means the file contains dense matrix "
2151  "data.";
2152  }
2153  }
2154  } // Proc 0: Done reading the Banner, hopefully successfully.
2155 
2156  // Broadcast from Proc 0 whether the Banner was read correctly.
2157  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2158 
2159  // If the Banner is invalid, all processes throw an
2160  // exception. Only Proc 0 gets the exception message, but
2161  // that's OK, since the main point is to "stop the world"
2162  // (rather than throw an exception on one process and leave
2163  // the others hanging).
2164  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2165  std::invalid_argument, errMsg.str ());
2166  } // Done reading the Banner line and broadcasting success.
2167  if (debug && myRank == rootRank) {
2168  cerr << "-- Reading dimensions line" << endl;
2169  }
2170 
2171  // Read the matrix dimensions from the Matrix Market metadata.
2172  // dims = (numRows, numCols, numEntries). Proc 0 does the
2173  // reading, but it broadcasts the results to all MPI
2174  // processes. Thus, readCoordDims() is a collective
2175  // operation. It does a collective check for correctness too.
2176  Tuple<global_ordinal_type, 3> dims =
2177  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2178 
2179  if (debug && myRank == rootRank) {
2180  cerr << "-- Making Adder for collecting matrix data" << endl;
2181  }
2182 
2183  // "Adder" object for collecting all the sparse matrix entries
2184  // from the input stream. This is only nonnull on Proc 0.
2185  RCP<adder_type> pAdder =
2186  makeAdder (pComm, pBanner, dims, tolerant, debug);
2187 
2188  if (debug && myRank == rootRank) {
2189  cerr << "-- Reading matrix data" << endl;
2190  }
2191  //
2192  // Read the matrix entries from the input stream on Proc 0.
2193  //
2194  {
2195  // We use readSuccess to broadcast the results of the read
2196  // (succeeded or not) to all MPI processes. Since
2197  // Teuchos::broadcast doesn't currently know how to send
2198  // bools, we convert to int (true -> 1, false -> 0).
2199  int readSuccess = 1;
2200  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2201  if (myRank == rootRank) {
2202  try {
2203  // Reader for "coordinate" format sparse matrix data.
2204  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2205  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2206  reader_type reader (pAdder);
2207 
2208  // Read the sparse matrix entries.
2209  std::pair<bool, std::vector<size_t> > results =
2210  reader.read (in, lineNumber, tolerant, debug);
2211  readSuccess = results.first ? 1 : 0;
2212  }
2213  catch (std::exception& e) {
2214  readSuccess = 0;
2215  errMsg << e.what();
2216  }
2217  }
2218  broadcast (*pComm, rootRank, ptr (&readSuccess));
2219 
2220  // It would be nice to add a "verbose" flag, so that in
2221  // tolerant mode, we could log any bad line number(s) on
2222  // Proc 0. For now, we just throw if the read fails to
2223  // succeed.
2224  //
2225  // Question: If we're in tolerant mode, and if the read did
2226  // not succeed, should we attempt to call fillComplete()?
2227  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2228  "Failed to read the Matrix Market sparse matrix file: "
2229  << errMsg.str());
2230  } // Done reading the matrix entries (stored on Proc 0 for now)
2231 
2232  if (debug && myRank == rootRank) {
2233  cerr << "-- Successfully read the Matrix Market data" << endl;
2234  }
2235 
2236  // In tolerant mode, we need to rebroadcast the matrix
2237  // dimensions, since they may be different after reading the
2238  // actual matrix data. We only need to broadcast the number
2239  // of rows and columns. Only Rank 0 needs to know the actual
2240  // global number of entries, since (a) we need to merge
2241  // duplicates on Rank 0 first anyway, and (b) when we
2242  // distribute the entries, each rank other than Rank 0 will
2243  // only need to know how many entries it owns, not the total
2244  // number of entries.
2245  if (tolerant) {
2246  if (debug && myRank == rootRank) {
2247  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2248  << endl
2249  << "----- Dimensions before: "
2250  << dims[0] << " x " << dims[1]
2251  << endl;
2252  }
2253  // Packed coordinate matrix dimensions (numRows, numCols).
2254  Tuple<global_ordinal_type, 2> updatedDims;
2255  if (myRank == rootRank) {
2256  // If one or more bottom rows of the matrix contain no
2257  // entries, then the Adder will report that the number
2258  // of rows is less than that specified in the
2259  // metadata. We allow this case, and favor the
2260  // metadata so that the zero row(s) will be included.
2261  updatedDims[0] =
2262  std::max (dims[0], pAdder->getAdder()->numRows());
2263  updatedDims[1] = pAdder->getAdder()->numCols();
2264  }
2265  broadcast (*pComm, rootRank, updatedDims);
2266  dims[0] = updatedDims[0];
2267  dims[1] = updatedDims[1];
2268  if (debug && myRank == rootRank) {
2269  cerr << "----- Dimensions after: " << dims[0] << " x "
2270  << dims[1] << endl;
2271  }
2272  }
2273  else {
2274  // In strict mode, we require that the matrix's metadata and
2275  // its actual data agree, at least somewhat. In particular,
2276  // the number of rows must agree, since otherwise we cannot
2277  // distribute the matrix correctly.
2278 
2279  // Teuchos::broadcast() doesn't know how to broadcast bools,
2280  // so we use an int with the standard 1 == true, 0 == false
2281  // encoding.
2282  int dimsMatch = 1;
2283  if (myRank == rootRank) {
2284  // If one or more bottom rows of the matrix contain no
2285  // entries, then the Adder will report that the number of
2286  // rows is less than that specified in the metadata. We
2287  // allow this case, and favor the metadata, but do not
2288  // allow the Adder to think there are more rows in the
2289  // matrix than the metadata says.
2290  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2291  dimsMatch = 0;
2292  }
2293  }
2294  broadcast (*pComm, 0, ptr (&dimsMatch));
2295  if (dimsMatch == 0) {
2296  // We're in an error state anyway, so we might as well
2297  // work a little harder to print an informative error
2298  // message.
2299  //
2300  // Broadcast the Adder's idea of the matrix dimensions
2301  // from Proc 0 to all processes.
2302  Tuple<global_ordinal_type, 2> addersDims;
2303  if (myRank == rootRank) {
2304  addersDims[0] = pAdder->getAdder()->numRows();
2305  addersDims[1] = pAdder->getAdder()->numCols();
2306  }
2307  broadcast (*pComm, 0, addersDims);
2308  TEUCHOS_TEST_FOR_EXCEPTION(
2309  dimsMatch == 0, std::runtime_error,
2310  "The matrix metadata says that the matrix is " << dims[0] << " x "
2311  << dims[1] << ", but the actual data says that the matrix is "
2312  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2313  "data includes more rows than reported in the metadata. This "
2314  "is not allowed when parsing in strict mode. Parse the matrix in "
2315  "tolerant mode to ignore the metadata when it disagrees with the "
2316  "data.");
2317  }
2318  } // Matrix dimensions (# rows, # cols, # entries) agree.
2319 
2320  if (debug && myRank == rootRank) {
2321  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2322  }
2323 
2324  // Now that we've read in all the matrix entries from the
2325  // input stream into the adder on Proc 0, post-process them
2326  // into CSR format (still on Proc 0). This will facilitate
2327  // distributing them to all the processors.
2328  //
2329  // These arrays represent the global matrix data as a CSR
2330  // matrix (with numEntriesPerRow as redundant but convenient
2331  // metadata, since it's computable from rowPtr and vice
2332  // versa). They are valid only on Proc 0.
2333  ArrayRCP<size_t> numEntriesPerRow;
2334  ArrayRCP<size_t> rowPtr;
2335  ArrayRCP<global_ordinal_type> colInd;
2336  ArrayRCP<scalar_type> values;
2337 
2338  // Proc 0 first merges duplicate entries, and then converts
2339  // the coordinate-format matrix data to CSR.
2340  {
2341  int mergeAndConvertSucceeded = 1;
2342  std::ostringstream errMsg;
2343 
2344  if (myRank == rootRank) {
2345  try {
2346  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2347  global_ordinal_type> element_type;
2348 
2349  // Number of rows in the matrix. If we are in tolerant
2350  // mode, we've already synchronized dims with the actual
2351  // matrix data. If in strict mode, we should use dims
2352  // (as read from the file's metadata) rather than the
2353  // matrix data to determine the dimensions. (The matrix
2354  // data will claim fewer rows than the metadata, if one
2355  // or more rows have no entries stored in the file.)
2356  const size_type numRows = dims[0];
2357 
2358  // Additively merge duplicate matrix entries.
2359  pAdder->getAdder()->merge ();
2360 
2361  // Get a temporary const view of the merged matrix entries.
2362  const std::vector<element_type>& entries =
2363  pAdder->getAdder()->getEntries();
2364 
2365  // Number of matrix entries (after merging).
2366  const size_t numEntries = (size_t)entries.size();
2367 
2368  if (debug) {
2369  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2370  << " rows and numEntries=" << numEntries
2371  << " entries." << endl;
2372  }
2373 
2374  // Make space for the CSR matrix data. Converting to
2375  // CSR is easier if we fill numEntriesPerRow with zeros
2376  // at first.
2377  numEntriesPerRow = arcp<size_t> (numRows);
2378  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2379  rowPtr = arcp<size_t> (numRows+1);
2380  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2381  colInd = arcp<global_ordinal_type> (numEntries);
2382  values = arcp<scalar_type> (numEntries);
2383 
2384  // Convert from array-of-structs coordinate format to CSR
2385  // (compressed sparse row) format.
2386  global_ordinal_type prvRow = 0;
2387  size_t curPos = 0;
2388  rowPtr[0] = 0;
2389  for (curPos = 0; curPos < numEntries; ++curPos) {
2390  const element_type& curEntry = entries[curPos];
2391  const global_ordinal_type curRow = curEntry.rowIndex();
2392  TEUCHOS_TEST_FOR_EXCEPTION(
2393  curRow < prvRow, std::logic_error,
2394  "Row indices are out of order, even though they are supposed "
2395  "to be sorted. curRow = " << curRow << ", prvRow = "
2396  << prvRow << ", at curPos = " << curPos << ". Please report "
2397  "this bug to the Tpetra developers.");
2398  if (curRow > prvRow) {
2399  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2400  rowPtr[r] = curPos;
2401  }
2402  prvRow = curRow;
2403  }
2404  numEntriesPerRow[curRow]++;
2405  colInd[curPos] = curEntry.colIndex();
2406  values[curPos] = curEntry.value();
2407  }
2408  // rowPtr has one more entry than numEntriesPerRow. The
2409  // last entry of rowPtr is the number of entries in
2410  // colInd and values.
2411  rowPtr[numRows] = numEntries;
2412  } // Finished conversion to CSR format
2413  catch (std::exception& e) {
2414  mergeAndConvertSucceeded = 0;
2415  errMsg << "Failed to merge sparse matrix entries and convert to "
2416  "CSR format: " << e.what();
2417  }
2418 
2419  if (debug && mergeAndConvertSucceeded) {
2420  // Number of rows in the matrix.
2421  const size_type numRows = dims[0];
2422  const size_type maxToDisplay = 100;
2423 
2424  cerr << "----- Proc 0: numEntriesPerRow[0.."
2425  << (numEntriesPerRow.size()-1) << "] ";
2426  if (numRows > maxToDisplay) {
2427  cerr << "(only showing first and last few entries) ";
2428  }
2429  cerr << "= [";
2430  if (numRows > 0) {
2431  if (numRows > maxToDisplay) {
2432  for (size_type k = 0; k < 2; ++k) {
2433  cerr << numEntriesPerRow[k] << " ";
2434  }
2435  cerr << "... ";
2436  for (size_type k = numRows-2; k < numRows-1; ++k) {
2437  cerr << numEntriesPerRow[k] << " ";
2438  }
2439  }
2440  else {
2441  for (size_type k = 0; k < numRows-1; ++k) {
2442  cerr << numEntriesPerRow[k] << " ";
2443  }
2444  }
2445  cerr << numEntriesPerRow[numRows-1];
2446  } // numRows > 0
2447  cerr << "]" << endl;
2448 
2449  cerr << "----- Proc 0: rowPtr ";
2450  if (numRows > maxToDisplay) {
2451  cerr << "(only showing first and last few entries) ";
2452  }
2453  cerr << "= [";
2454  if (numRows > maxToDisplay) {
2455  for (size_type k = 0; k < 2; ++k) {
2456  cerr << rowPtr[k] << " ";
2457  }
2458  cerr << "... ";
2459  for (size_type k = numRows-2; k < numRows; ++k) {
2460  cerr << rowPtr[k] << " ";
2461  }
2462  }
2463  else {
2464  for (size_type k = 0; k < numRows; ++k) {
2465  cerr << rowPtr[k] << " ";
2466  }
2467  }
2468  cerr << rowPtr[numRows] << "]" << endl;
2469  }
2470  } // if myRank == rootRank
2471  } // Done converting sparse matrix data to CSR format
2472 
2473  // Now we're done with the Adder, so we can release the
2474  // reference ("free" it) to save space. This only actually
2475  // does anything on Rank 0, since pAdder is null on all the
2476  // other MPI processes.
2477  pAdder = null;
2478 
2479  if (debug && myRank == rootRank) {
2480  cerr << "-- Making range, domain, and row maps" << endl;
2481  }
2482 
2483  // Make the maps that describe the matrix's range and domain,
2484  // and the distribution of its rows. Creating a Map is a
2485  // collective operation, so we don't have to do a broadcast of
2486  // a success Boolean.
2487  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2488  RCP<const map_type> pDomainMap =
2489  makeDomainMap (pRangeMap, dims[0], dims[1]);
2490  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2491 
2492  if (debug && myRank == rootRank) {
2493  cerr << "-- Distributing the matrix data" << endl;
2494  }
2495 
2496  // Distribute the matrix data. Each processor has to add the
2497  // rows that it owns. If you try to make Proc 0 call
2498  // insertGlobalValues() for _all_ the rows, not just those it
2499  // owns, then fillComplete() will compute the number of
2500  // columns incorrectly. That's why Proc 0 has to distribute
2501  // the matrix data and why we make all the processors (not
2502  // just Proc 0) call insertGlobalValues() on their own data.
2503  //
2504  // These arrays represent each processor's part of the matrix
2505  // data, in "CSR" format (sort of, since the row indices might
2506  // not be contiguous).
2507  ArrayRCP<size_t> myNumEntriesPerRow;
2508  ArrayRCP<size_t> myRowPtr;
2509  ArrayRCP<global_ordinal_type> myColInd;
2510  ArrayRCP<scalar_type> myValues;
2511  // Distribute the matrix data. This is a collective operation.
2512  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2513  numEntriesPerRow, rowPtr, colInd, values, debug);
2514 
2515  if (debug && myRank == rootRank) {
2516  cerr << "-- Inserting matrix entries on each processor";
2517  if (callFillComplete) {
2518  cerr << " and calling fillComplete()";
2519  }
2520  cerr << endl;
2521  }
2522  // Each processor inserts its part of the matrix data, and
2523  // then they all call fillComplete(). This method invalidates
2524  // the my* distributed matrix data before calling
2525  // fillComplete(), in order to save space. In general, we
2526  // never store more than two copies of the matrix's entries in
2527  // memory at once, which is no worse than what Tpetra
2528  // promises.
2529  RCP<sparse_matrix_type> pMatrix =
2530  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2531  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2532  // Only use a reduce-all in debug mode to check if pMatrix is
2533  // null. Otherwise, just throw an exception. We never expect
2534  // a null pointer here, so we can save a communication.
2535  if (debug) {
2536  int localIsNull = pMatrix.is_null () ? 1 : 0;
2537  int globalIsNull = 0;
2538  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2539  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2540  "Reader::makeMatrix() returned a null pointer on at least one "
2541  "process. Please report this bug to the Tpetra developers.");
2542  }
2543  else {
2544  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2545  "Reader::makeMatrix() returned a null pointer. "
2546  "Please report this bug to the Tpetra developers.");
2547  }
2548 
2549  // We can't get the dimensions of the matrix until after
2550  // fillComplete() is called. Thus, we can't do the sanity
2551  // check (dimensions read from the Matrix Market data,
2552  // vs. dimensions reported by the CrsMatrix) unless the user
2553  // asked makeMatrix() to call fillComplete().
2554  //
2555  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2556  // what one might think it does, so you have to ask the range
2557  // resp. domain map for the number of rows resp. columns.
2558  if (callFillComplete) {
2559  const int numProcs = pComm->getSize ();
2560 
2561  if (extraDebug && debug) {
2562  const global_size_t globalNumRows =
2563  pRangeMap->getGlobalNumElements ();
2564  const global_size_t globalNumCols =
2565  pDomainMap->getGlobalNumElements ();
2566  if (myRank == rootRank) {
2567  cerr << "-- Matrix is "
2568  << globalNumRows << " x " << globalNumCols
2569  << " with " << pMatrix->getGlobalNumEntries()
2570  << " entries, and index base "
2571  << pMatrix->getIndexBase() << "." << endl;
2572  }
2573  pComm->barrier ();
2574  for (int p = 0; p < numProcs; ++p) {
2575  if (myRank == p) {
2576  cerr << "-- Proc " << p << " owns "
2577  << pMatrix->getLocalNumCols() << " columns, and "
2578  << pMatrix->getLocalNumEntries() << " entries." << endl;
2579  }
2580  pComm->barrier ();
2581  }
2582  } // if (extraDebug && debug)
2583  } // if (callFillComplete)
2584 
2585  if (debug && myRank == rootRank) {
2586  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2587  << endl;
2588  }
2589  return pMatrix;
2590  }
2591 
2592 
2621  static Teuchos::RCP<sparse_matrix_type>
2622  readSparse (std::istream& in,
2623  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2624  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2625  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2626  const bool tolerant=false,
2627  const bool debug=false)
2628  {
2629  using Teuchos::MatrixMarket::Banner;
2630  using Teuchos::arcp;
2631  using Teuchos::ArrayRCP;
2632  using Teuchos::broadcast;
2633  using Teuchos::null;
2634  using Teuchos::ptr;
2635  using Teuchos::RCP;
2636  using Teuchos::reduceAll;
2637  using Teuchos::Tuple;
2638  using std::cerr;
2639  using std::endl;
2640  typedef Teuchos::ScalarTraits<scalar_type> STS;
2641 
2642  const bool extraDebug = false;
2643  const int myRank = pComm->getRank ();
2644  const int rootRank = 0;
2645 
2646  // Current line number in the input stream. Various calls
2647  // will modify this depending on the number of lines that are
2648  // read from the input stream. Only Rank 0 modifies this.
2649  size_t lineNumber = 1;
2650 
2651  if (debug && myRank == rootRank) {
2652  cerr << "Matrix Market reader: readSparse:" << endl
2653  << "-- Reading banner line" << endl;
2654  }
2655 
2656  // The "Banner" tells you whether the input stream represents
2657  // a sparse matrix, the symmetry type of the matrix, and the
2658  // type of the data it contains.
2659  //
2660  // pBanner will only be nonnull on MPI Rank 0. It will be
2661  // null on all other MPI processes.
2662  RCP<const Banner> pBanner;
2663  {
2664  // We read and validate the Banner on Proc 0, but broadcast
2665  // the validation result to all processes.
2666  // Teuchos::broadcast doesn't currently work with bool, so
2667  // we use int (true -> 1, false -> 0).
2668  int bannerIsCorrect = 1;
2669  std::ostringstream errMsg;
2670 
2671  if (myRank == rootRank) {
2672  // Read the Banner line from the input stream.
2673  try {
2674  pBanner = readBanner (in, lineNumber, tolerant, debug);
2675  }
2676  catch (std::exception& e) {
2677  errMsg << "Attempt to read the Matrix Market file's Banner line "
2678  "threw an exception: " << e.what();
2679  bannerIsCorrect = 0;
2680  }
2681 
2682  if (bannerIsCorrect) {
2683  // Validate the Banner for the case of a sparse matrix.
2684  // We validate on Proc 0, since it reads the Banner.
2685 
2686  // In intolerant mode, the matrix type must be "coordinate".
2687  if (! tolerant && pBanner->matrixType() != "coordinate") {
2688  bannerIsCorrect = 0;
2689  errMsg << "The Matrix Market input file must contain a "
2690  "\"coordinate\"-format sparse matrix in order to create a "
2691  "Tpetra::CrsMatrix object from it, but the file's matrix "
2692  "type is \"" << pBanner->matrixType() << "\" instead.";
2693  }
2694  // In tolerant mode, we allow the matrix type to be
2695  // anything other than "array" (which would mean that
2696  // the file contains a dense matrix).
2697  if (tolerant && pBanner->matrixType() == "array") {
2698  bannerIsCorrect = 0;
2699  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2700  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2701  "object from it, but the file's matrix type is \"array\" "
2702  "instead. That probably means the file contains dense matrix "
2703  "data.";
2704  }
2705  }
2706  } // Proc 0: Done reading the Banner, hopefully successfully.
2707 
2708  // Broadcast from Proc 0 whether the Banner was read correctly.
2709  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2710 
2711  // If the Banner is invalid, all processes throw an
2712  // exception. Only Proc 0 gets the exception message, but
2713  // that's OK, since the main point is to "stop the world"
2714  // (rather than throw an exception on one process and leave
2715  // the others hanging).
2716  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2717  std::invalid_argument, errMsg.str ());
2718  } // Done reading the Banner line and broadcasting success.
2719  if (debug && myRank == rootRank) {
2720  cerr << "-- Reading dimensions line" << endl;
2721  }
2722 
2723  // Read the matrix dimensions from the Matrix Market metadata.
2724  // dims = (numRows, numCols, numEntries). Proc 0 does the
2725  // reading, but it broadcasts the results to all MPI
2726  // processes. Thus, readCoordDims() is a collective
2727  // operation. It does a collective check for correctness too.
2728  Tuple<global_ordinal_type, 3> dims =
2729  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2730 
2731  if (debug && myRank == rootRank) {
2732  cerr << "-- Making Adder for collecting matrix data" << endl;
2733  }
2734 
2735  // "Adder" object for collecting all the sparse matrix entries
2736  // from the input stream. This is only nonnull on Proc 0.
2737  RCP<adder_type> pAdder =
2738  makeAdder (pComm, pBanner, dims, tolerant, debug);
2739 
2740  if (debug && myRank == rootRank) {
2741  cerr << "-- Reading matrix data" << endl;
2742  }
2743  //
2744  // Read the matrix entries from the input stream on Proc 0.
2745  //
2746  {
2747  // We use readSuccess to broadcast the results of the read
2748  // (succeeded or not) to all MPI processes. Since
2749  // Teuchos::broadcast doesn't currently know how to send
2750  // bools, we convert to int (true -> 1, false -> 0).
2751  int readSuccess = 1;
2752  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2753  if (myRank == rootRank) {
2754  try {
2755  // Reader for "coordinate" format sparse matrix data.
2756  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2757  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2758  reader_type reader (pAdder);
2759 
2760  // Read the sparse matrix entries.
2761  std::pair<bool, std::vector<size_t> > results =
2762  reader.read (in, lineNumber, tolerant, debug);
2763  readSuccess = results.first ? 1 : 0;
2764  }
2765  catch (std::exception& e) {
2766  readSuccess = 0;
2767  errMsg << e.what();
2768  }
2769  }
2770  broadcast (*pComm, rootRank, ptr (&readSuccess));
2771 
2772  // It would be nice to add a "verbose" flag, so that in
2773  // tolerant mode, we could log any bad line number(s) on
2774  // Proc 0. For now, we just throw if the read fails to
2775  // succeed.
2776  //
2777  // Question: If we're in tolerant mode, and if the read did
2778  // not succeed, should we attempt to call fillComplete()?
2779  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2780  "Failed to read the Matrix Market sparse matrix file: "
2781  << errMsg.str());
2782  } // Done reading the matrix entries (stored on Proc 0 for now)
2783 
2784  if (debug && myRank == rootRank) {
2785  cerr << "-- Successfully read the Matrix Market data" << endl;
2786  }
2787 
2788  // In tolerant mode, we need to rebroadcast the matrix
2789  // dimensions, since they may be different after reading the
2790  // actual matrix data. We only need to broadcast the number
2791  // of rows and columns. Only Rank 0 needs to know the actual
2792  // global number of entries, since (a) we need to merge
2793  // duplicates on Rank 0 first anyway, and (b) when we
2794  // distribute the entries, each rank other than Rank 0 will
2795  // only need to know how many entries it owns, not the total
2796  // number of entries.
2797  if (tolerant) {
2798  if (debug && myRank == rootRank) {
2799  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2800  << endl
2801  << "----- Dimensions before: "
2802  << dims[0] << " x " << dims[1]
2803  << endl;
2804  }
2805  // Packed coordinate matrix dimensions (numRows, numCols).
2806  Tuple<global_ordinal_type, 2> updatedDims;
2807  if (myRank == rootRank) {
2808  // If one or more bottom rows of the matrix contain no
2809  // entries, then the Adder will report that the number
2810  // of rows is less than that specified in the
2811  // metadata. We allow this case, and favor the
2812  // metadata so that the zero row(s) will be included.
2813  updatedDims[0] =
2814  std::max (dims[0], pAdder->getAdder()->numRows());
2815  updatedDims[1] = pAdder->getAdder()->numCols();
2816  }
2817  broadcast (*pComm, rootRank, updatedDims);
2818  dims[0] = updatedDims[0];
2819  dims[1] = updatedDims[1];
2820  if (debug && myRank == rootRank) {
2821  cerr << "----- Dimensions after: " << dims[0] << " x "
2822  << dims[1] << endl;
2823  }
2824  }
2825  else {
2826  // In strict mode, we require that the matrix's metadata and
2827  // its actual data agree, at least somewhat. In particular,
2828  // the number of rows must agree, since otherwise we cannot
2829  // distribute the matrix correctly.
2830 
2831  // Teuchos::broadcast() doesn't know how to broadcast bools,
2832  // so we use an int with the standard 1 == true, 0 == false
2833  // encoding.
2834  int dimsMatch = 1;
2835  if (myRank == rootRank) {
2836  // If one or more bottom rows of the matrix contain no
2837  // entries, then the Adder will report that the number of
2838  // rows is less than that specified in the metadata. We
2839  // allow this case, and favor the metadata, but do not
2840  // allow the Adder to think there are more rows in the
2841  // matrix than the metadata says.
2842  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2843  dimsMatch = 0;
2844  }
2845  }
2846  broadcast (*pComm, 0, ptr (&dimsMatch));
2847  if (dimsMatch == 0) {
2848  // We're in an error state anyway, so we might as well
2849  // work a little harder to print an informative error
2850  // message.
2851  //
2852  // Broadcast the Adder's idea of the matrix dimensions
2853  // from Proc 0 to all processes.
2854  Tuple<global_ordinal_type, 2> addersDims;
2855  if (myRank == rootRank) {
2856  addersDims[0] = pAdder->getAdder()->numRows();
2857  addersDims[1] = pAdder->getAdder()->numCols();
2858  }
2859  broadcast (*pComm, 0, addersDims);
2860  TEUCHOS_TEST_FOR_EXCEPTION(
2861  dimsMatch == 0, std::runtime_error,
2862  "The matrix metadata says that the matrix is " << dims[0] << " x "
2863  << dims[1] << ", but the actual data says that the matrix is "
2864  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2865  "data includes more rows than reported in the metadata. This "
2866  "is not allowed when parsing in strict mode. Parse the matrix in "
2867  "tolerant mode to ignore the metadata when it disagrees with the "
2868  "data.");
2869  }
2870  } // Matrix dimensions (# rows, # cols, # entries) agree.
2871 
2872  if (debug && myRank == rootRank) {
2873  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2874  }
2875 
2876  // Now that we've read in all the matrix entries from the
2877  // input stream into the adder on Proc 0, post-process them
2878  // into CSR format (still on Proc 0). This will facilitate
2879  // distributing them to all the processors.
2880  //
2881  // These arrays represent the global matrix data as a CSR
2882  // matrix (with numEntriesPerRow as redundant but convenient
2883  // metadata, since it's computable from rowPtr and vice
2884  // versa). They are valid only on Proc 0.
2885  ArrayRCP<size_t> numEntriesPerRow;
2886  ArrayRCP<size_t> rowPtr;
2887  ArrayRCP<global_ordinal_type> colInd;
2888  ArrayRCP<scalar_type> values;
2889 
2890  // Proc 0 first merges duplicate entries, and then converts
2891  // the coordinate-format matrix data to CSR.
2892  {
2893  int mergeAndConvertSucceeded = 1;
2894  std::ostringstream errMsg;
2895 
2896  if (myRank == rootRank) {
2897  try {
2898  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2899  global_ordinal_type> element_type;
2900 
2901  // Number of rows in the matrix. If we are in tolerant
2902  // mode, we've already synchronized dims with the actual
2903  // matrix data. If in strict mode, we should use dims
2904  // (as read from the file's metadata) rather than the
2905  // matrix data to determine the dimensions. (The matrix
2906  // data will claim fewer rows than the metadata, if one
2907  // or more rows have no entries stored in the file.)
2908  const size_type numRows = dims[0];
2909 
2910  // Additively merge duplicate matrix entries.
2911  pAdder->getAdder()->merge ();
2912 
2913  // Get a temporary const view of the merged matrix entries.
2914  const std::vector<element_type>& entries =
2915  pAdder->getAdder()->getEntries();
2916 
2917  // Number of matrix entries (after merging).
2918  const size_t numEntries = (size_t)entries.size();
2919 
2920  if (debug) {
2921  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2922  << " rows and numEntries=" << numEntries
2923  << " entries." << endl;
2924  }
2925 
2926  // Make space for the CSR matrix data. Converting to
2927  // CSR is easier if we fill numEntriesPerRow with zeros
2928  // at first.
2929  numEntriesPerRow = arcp<size_t> (numRows);
2930  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2931  rowPtr = arcp<size_t> (numRows+1);
2932  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2933  colInd = arcp<global_ordinal_type> (numEntries);
2934  values = arcp<scalar_type> (numEntries);
2935 
2936  // Convert from array-of-structs coordinate format to CSR
2937  // (compressed sparse row) format.
2938  global_ordinal_type prvRow = 0;
2939  size_t curPos = 0;
2940  rowPtr[0] = 0;
2941  for (curPos = 0; curPos < numEntries; ++curPos) {
2942  const element_type& curEntry = entries[curPos];
2943  const global_ordinal_type curRow = curEntry.rowIndex();
2944  TEUCHOS_TEST_FOR_EXCEPTION(
2945  curRow < prvRow, std::logic_error,
2946  "Row indices are out of order, even though they are supposed "
2947  "to be sorted. curRow = " << curRow << ", prvRow = "
2948  << prvRow << ", at curPos = " << curPos << ". Please report "
2949  "this bug to the Tpetra developers.");
2950  if (curRow > prvRow) {
2951  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2952  rowPtr[r] = curPos;
2953  }
2954  prvRow = curRow;
2955  }
2956  numEntriesPerRow[curRow]++;
2957  colInd[curPos] = curEntry.colIndex();
2958  values[curPos] = curEntry.value();
2959  }
2960  // rowPtr has one more entry than numEntriesPerRow. The
2961  // last entry of rowPtr is the number of entries in
2962  // colInd and values.
2963  rowPtr[numRows] = numEntries;
2964  } // Finished conversion to CSR format
2965  catch (std::exception& e) {
2966  mergeAndConvertSucceeded = 0;
2967  errMsg << "Failed to merge sparse matrix entries and convert to "
2968  "CSR format: " << e.what();
2969  }
2970 
2971  if (debug && mergeAndConvertSucceeded) {
2972  // Number of rows in the matrix.
2973  const size_type numRows = dims[0];
2974  const size_type maxToDisplay = 100;
2975 
2976  cerr << "----- Proc 0: numEntriesPerRow[0.."
2977  << (numEntriesPerRow.size()-1) << "] ";
2978  if (numRows > maxToDisplay) {
2979  cerr << "(only showing first and last few entries) ";
2980  }
2981  cerr << "= [";
2982  if (numRows > 0) {
2983  if (numRows > maxToDisplay) {
2984  for (size_type k = 0; k < 2; ++k) {
2985  cerr << numEntriesPerRow[k] << " ";
2986  }
2987  cerr << "... ";
2988  for (size_type k = numRows-2; k < numRows-1; ++k) {
2989  cerr << numEntriesPerRow[k] << " ";
2990  }
2991  }
2992  else {
2993  for (size_type k = 0; k < numRows-1; ++k) {
2994  cerr << numEntriesPerRow[k] << " ";
2995  }
2996  }
2997  cerr << numEntriesPerRow[numRows-1];
2998  } // numRows > 0
2999  cerr << "]" << endl;
3000 
3001  cerr << "----- Proc 0: rowPtr ";
3002  if (numRows > maxToDisplay) {
3003  cerr << "(only showing first and last few entries) ";
3004  }
3005  cerr << "= [";
3006  if (numRows > maxToDisplay) {
3007  for (size_type k = 0; k < 2; ++k) {
3008  cerr << rowPtr[k] << " ";
3009  }
3010  cerr << "... ";
3011  for (size_type k = numRows-2; k < numRows; ++k) {
3012  cerr << rowPtr[k] << " ";
3013  }
3014  }
3015  else {
3016  for (size_type k = 0; k < numRows; ++k) {
3017  cerr << rowPtr[k] << " ";
3018  }
3019  }
3020  cerr << rowPtr[numRows] << "]" << endl;
3021  }
3022  } // if myRank == rootRank
3023  } // Done converting sparse matrix data to CSR format
3024 
3025  // Now we're done with the Adder, so we can release the
3026  // reference ("free" it) to save space. This only actually
3027  // does anything on Rank 0, since pAdder is null on all the
3028  // other MPI processes.
3029  pAdder = null;
3030 
3031  if (debug && myRank == rootRank) {
3032  cerr << "-- Making range, domain, and row maps" << endl;
3033  }
3034 
3035  // Make the maps that describe the matrix's range and domain,
3036  // and the distribution of its rows. Creating a Map is a
3037  // collective operation, so we don't have to do a broadcast of
3038  // a success Boolean.
3039  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3040  RCP<const map_type> pDomainMap =
3041  makeDomainMap (pRangeMap, dims[0], dims[1]);
3042  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3043 
3044  if (debug && myRank == rootRank) {
3045  cerr << "-- Distributing the matrix data" << endl;
3046  }
3047 
3048  // Distribute the matrix data. Each processor has to add the
3049  // rows that it owns. If you try to make Proc 0 call
3050  // insertGlobalValues() for _all_ the rows, not just those it
3051  // owns, then fillComplete() will compute the number of
3052  // columns incorrectly. That's why Proc 0 has to distribute
3053  // the matrix data and why we make all the processors (not
3054  // just Proc 0) call insertGlobalValues() on their own data.
3055  //
3056  // These arrays represent each processor's part of the matrix
3057  // data, in "CSR" format (sort of, since the row indices might
3058  // not be contiguous).
3059  ArrayRCP<size_t> myNumEntriesPerRow;
3060  ArrayRCP<size_t> myRowPtr;
3061  ArrayRCP<global_ordinal_type> myColInd;
3062  ArrayRCP<scalar_type> myValues;
3063  // Distribute the matrix data. This is a collective operation.
3064  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3065  numEntriesPerRow, rowPtr, colInd, values, debug);
3066 
3067  if (debug && myRank == rootRank) {
3068  cerr << "-- Inserting matrix entries on each process "
3069  "and calling fillComplete()" << endl;
3070  }
3071  // Each processor inserts its part of the matrix data, and
3072  // then they all call fillComplete(). This method invalidates
3073  // the my* distributed matrix data before calling
3074  // fillComplete(), in order to save space. In general, we
3075  // never store more than two copies of the matrix's entries in
3076  // memory at once, which is no worse than what Tpetra
3077  // promises.
3078  Teuchos::RCP<sparse_matrix_type> pMatrix =
3079  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3080  pRowMap, pRangeMap, pDomainMap, constructorParams,
3081  fillCompleteParams);
3082  // Only use a reduce-all in debug mode to check if pMatrix is
3083  // null. Otherwise, just throw an exception. We never expect
3084  // a null pointer here, so we can save a communication.
3085  if (debug) {
3086  int localIsNull = pMatrix.is_null () ? 1 : 0;
3087  int globalIsNull = 0;
3088  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3089  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3090  "Reader::makeMatrix() returned a null pointer on at least one "
3091  "process. Please report this bug to the Tpetra developers.");
3092  }
3093  else {
3094  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3095  "Reader::makeMatrix() returned a null pointer. "
3096  "Please report this bug to the Tpetra developers.");
3097  }
3098 
3099  // Sanity check for dimensions (read from the Matrix Market
3100  // data, vs. dimensions reported by the CrsMatrix).
3101  //
3102  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3103  // what one might think it does, so you have to ask the range
3104  // resp. domain map for the number of rows resp. columns.
3105  if (extraDebug && debug) {
3106  const int numProcs = pComm->getSize ();
3107  const global_size_t globalNumRows =
3108  pRangeMap->getGlobalNumElements();
3109  const global_size_t globalNumCols =
3110  pDomainMap->getGlobalNumElements();
3111  if (myRank == rootRank) {
3112  cerr << "-- Matrix is "
3113  << globalNumRows << " x " << globalNumCols
3114  << " with " << pMatrix->getGlobalNumEntries()
3115  << " entries, and index base "
3116  << pMatrix->getIndexBase() << "." << endl;
3117  }
3118  pComm->barrier ();
3119  for (int p = 0; p < numProcs; ++p) {
3120  if (myRank == p) {
3121  cerr << "-- Proc " << p << " owns "
3122  << pMatrix->getLocalNumCols() << " columns, and "
3123  << pMatrix->getLocalNumEntries() << " entries." << endl;
3124  }
3125  pComm->barrier ();
3126  }
3127  } // if (extraDebug && debug)
3128 
3129  if (debug && myRank == rootRank) {
3130  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3131  << endl;
3132  }
3133  return pMatrix;
3134  }
3135 
3136 
3177  static Teuchos::RCP<sparse_matrix_type>
3178  readSparse (std::istream& in,
3179  const Teuchos::RCP<const map_type>& rowMap,
3180  Teuchos::RCP<const map_type>& colMap,
3181  const Teuchos::RCP<const map_type>& domainMap,
3182  const Teuchos::RCP<const map_type>& rangeMap,
3183  const bool callFillComplete=true,
3184  const bool tolerant=false,
3185  const bool debug=false)
3186  {
3187  using Teuchos::MatrixMarket::Banner;
3188  using Teuchos::arcp;
3189  using Teuchos::ArrayRCP;
3190  using Teuchos::ArrayView;
3191  using Teuchos::as;
3192  using Teuchos::broadcast;
3193  using Teuchos::Comm;
3194  using Teuchos::null;
3195  using Teuchos::ptr;
3196  using Teuchos::RCP;
3197  using Teuchos::reduceAll;
3198  using Teuchos::Tuple;
3199  using std::cerr;
3200  using std::endl;
3201  typedef Teuchos::ScalarTraits<scalar_type> STS;
3202 
3203  RCP<const Comm<int> > pComm = rowMap->getComm ();
3204  const int myRank = pComm->getRank ();
3205  const int rootRank = 0;
3206  const bool extraDebug = false;
3207 
3208  // Fast checks for invalid input. We can't check other
3209  // attributes of the Maps until we've read in the matrix
3210  // dimensions.
3211  TEUCHOS_TEST_FOR_EXCEPTION(
3212  rowMap.is_null (), std::invalid_argument,
3213  "Row Map must be nonnull.");
3214  TEUCHOS_TEST_FOR_EXCEPTION(
3215  rangeMap.is_null (), std::invalid_argument,
3216  "Range Map must be nonnull.");
3217  TEUCHOS_TEST_FOR_EXCEPTION(
3218  domainMap.is_null (), std::invalid_argument,
3219  "Domain Map must be nonnull.");
3220  TEUCHOS_TEST_FOR_EXCEPTION(
3221  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3222  std::invalid_argument,
3223  "The specified row Map's communicator (rowMap->getComm())"
3224  "differs from the given separately supplied communicator pComm.");
3225  TEUCHOS_TEST_FOR_EXCEPTION(
3226  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3227  std::invalid_argument,
3228  "The specified domain Map's communicator (domainMap->getComm())"
3229  "differs from the given separately supplied communicator pComm.");
3230  TEUCHOS_TEST_FOR_EXCEPTION(
3231  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3232  std::invalid_argument,
3233  "The specified range Map's communicator (rangeMap->getComm())"
3234  "differs from the given separately supplied communicator pComm.");
3235 
3236  // Current line number in the input stream. Various calls
3237  // will modify this depending on the number of lines that are
3238  // read from the input stream. Only Rank 0 modifies this.
3239  size_t lineNumber = 1;
3240 
3241  if (debug && myRank == rootRank) {
3242  cerr << "Matrix Market reader: readSparse:" << endl
3243  << "-- Reading banner line" << endl;
3244  }
3245 
3246  // The "Banner" tells you whether the input stream represents
3247  // a sparse matrix, the symmetry type of the matrix, and the
3248  // type of the data it contains.
3249  //
3250  // pBanner will only be nonnull on MPI Rank 0. It will be
3251  // null on all other MPI processes.
3252  RCP<const Banner> pBanner;
3253  {
3254  // We read and validate the Banner on Proc 0, but broadcast
3255  // the validation result to all processes.
3256  // Teuchos::broadcast doesn't currently work with bool, so
3257  // we use int (true -> 1, false -> 0).
3258  int bannerIsCorrect = 1;
3259  std::ostringstream errMsg;
3260 
3261  if (myRank == rootRank) {
3262  // Read the Banner line from the input stream.
3263  try {
3264  pBanner = readBanner (in, lineNumber, tolerant, debug);
3265  }
3266  catch (std::exception& e) {
3267  errMsg << "Attempt to read the Matrix Market file's Banner line "
3268  "threw an exception: " << e.what();
3269  bannerIsCorrect = 0;
3270  }
3271 
3272  if (bannerIsCorrect) {
3273  // Validate the Banner for the case of a sparse matrix.
3274  // We validate on Proc 0, since it reads the Banner.
3275 
3276  // In intolerant mode, the matrix type must be "coordinate".
3277  if (! tolerant && pBanner->matrixType() != "coordinate") {
3278  bannerIsCorrect = 0;
3279  errMsg << "The Matrix Market input file must contain a "
3280  "\"coordinate\"-format sparse matrix in order to create a "
3281  "Tpetra::CrsMatrix object from it, but the file's matrix "
3282  "type is \"" << pBanner->matrixType() << "\" instead.";
3283  }
3284  // In tolerant mode, we allow the matrix type to be
3285  // anything other than "array" (which would mean that
3286  // the file contains a dense matrix).
3287  if (tolerant && pBanner->matrixType() == "array") {
3288  bannerIsCorrect = 0;
3289  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3290  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3291  "object from it, but the file's matrix type is \"array\" "
3292  "instead. That probably means the file contains dense matrix "
3293  "data.";
3294  }
3295  }
3296  } // Proc 0: Done reading the Banner, hopefully successfully.
3297 
3298  // Broadcast from Proc 0 whether the Banner was read correctly.
3299  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3300 
3301  // If the Banner is invalid, all processes throw an
3302  // exception. Only Proc 0 gets the exception message, but
3303  // that's OK, since the main point is to "stop the world"
3304  // (rather than throw an exception on one process and leave
3305  // the others hanging).
3306  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3307  std::invalid_argument, errMsg.str ());
3308  } // Done reading the Banner line and broadcasting success.
3309  if (debug && myRank == rootRank) {
3310  cerr << "-- Reading dimensions line" << endl;
3311  }
3312 
3313  // Read the matrix dimensions from the Matrix Market metadata.
3314  // dims = (numRows, numCols, numEntries). Proc 0 does the
3315  // reading, but it broadcasts the results to all MPI
3316  // processes. Thus, readCoordDims() is a collective
3317  // operation. It does a collective check for correctness too.
3318  Tuple<global_ordinal_type, 3> dims =
3319  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3320 
3321  if (debug && myRank == rootRank) {
3322  cerr << "-- Making Adder for collecting matrix data" << endl;
3323  }
3324 
3325  // "Adder" object for collecting all the sparse matrix entries
3326  // from the input stream. This is only nonnull on Proc 0.
3327  // The Adder internally converts the one-based indices (native
3328  // Matrix Market format) into zero-based indices.
3329  RCP<adder_type> pAdder =
3330  makeAdder (pComm, pBanner, dims, tolerant, debug);
3331 
3332  if (debug && myRank == rootRank) {
3333  cerr << "-- Reading matrix data" << endl;
3334  }
3335  //
3336  // Read the matrix entries from the input stream on Proc 0.
3337  //
3338  {
3339  // We use readSuccess to broadcast the results of the read
3340  // (succeeded or not) to all MPI processes. Since
3341  // Teuchos::broadcast doesn't currently know how to send
3342  // bools, we convert to int (true -> 1, false -> 0).
3343  int readSuccess = 1;
3344  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3345  if (myRank == rootRank) {
3346  try {
3347  // Reader for "coordinate" format sparse matrix data.
3348  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3349  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3350  reader_type reader (pAdder);
3351 
3352  // Read the sparse matrix entries.
3353  std::pair<bool, std::vector<size_t> > results =
3354  reader.read (in, lineNumber, tolerant, debug);
3355  readSuccess = results.first ? 1 : 0;
3356  }
3357  catch (std::exception& e) {
3358  readSuccess = 0;
3359  errMsg << e.what();
3360  }
3361  }
3362  broadcast (*pComm, rootRank, ptr (&readSuccess));
3363 
3364  // It would be nice to add a "verbose" flag, so that in
3365  // tolerant mode, we could log any bad line number(s) on
3366  // Proc 0. For now, we just throw if the read fails to
3367  // succeed.
3368  //
3369  // Question: If we're in tolerant mode, and if the read did
3370  // not succeed, should we attempt to call fillComplete()?
3371  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3372  "Failed to read the Matrix Market sparse matrix file: "
3373  << errMsg.str());
3374  } // Done reading the matrix entries (stored on Proc 0 for now)
3375 
3376  if (debug && myRank == rootRank) {
3377  cerr << "-- Successfully read the Matrix Market data" << endl;
3378  }
3379 
3380  // In tolerant mode, we need to rebroadcast the matrix
3381  // dimensions, since they may be different after reading the
3382  // actual matrix data. We only need to broadcast the number
3383  // of rows and columns. Only Rank 0 needs to know the actual
3384  // global number of entries, since (a) we need to merge
3385  // duplicates on Rank 0 first anyway, and (b) when we
3386  // distribute the entries, each rank other than Rank 0 will
3387  // only need to know how many entries it owns, not the total
3388  // number of entries.
3389  if (tolerant) {
3390  if (debug && myRank == rootRank) {
3391  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3392  << endl
3393  << "----- Dimensions before: "
3394  << dims[0] << " x " << dims[1]
3395  << endl;
3396  }
3397  // Packed coordinate matrix dimensions (numRows, numCols).
3398  Tuple<global_ordinal_type, 2> updatedDims;
3399  if (myRank == rootRank) {
3400  // If one or more bottom rows of the matrix contain no
3401  // entries, then the Adder will report that the number
3402  // of rows is less than that specified in the
3403  // metadata. We allow this case, and favor the
3404  // metadata so that the zero row(s) will be included.
3405  updatedDims[0] =
3406  std::max (dims[0], pAdder->getAdder()->numRows());
3407  updatedDims[1] = pAdder->getAdder()->numCols();
3408  }
3409  broadcast (*pComm, rootRank, updatedDims);
3410  dims[0] = updatedDims[0];
3411  dims[1] = updatedDims[1];
3412  if (debug && myRank == rootRank) {
3413  cerr << "----- Dimensions after: " << dims[0] << " x "
3414  << dims[1] << endl;
3415  }
3416  }
3417  else {
3418  // In strict mode, we require that the matrix's metadata and
3419  // its actual data agree, at least somewhat. In particular,
3420  // the number of rows must agree, since otherwise we cannot
3421  // distribute the matrix correctly.
3422 
3423  // Teuchos::broadcast() doesn't know how to broadcast bools,
3424  // so we use an int with the standard 1 == true, 0 == false
3425  // encoding.
3426  int dimsMatch = 1;
3427  if (myRank == rootRank) {
3428  // If one or more bottom rows of the matrix contain no
3429  // entries, then the Adder will report that the number of
3430  // rows is less than that specified in the metadata. We
3431  // allow this case, and favor the metadata, but do not
3432  // allow the Adder to think there are more rows in the
3433  // matrix than the metadata says.
3434  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3435  dimsMatch = 0;
3436  }
3437  }
3438  broadcast (*pComm, 0, ptr (&dimsMatch));
3439  if (dimsMatch == 0) {
3440  // We're in an error state anyway, so we might as well
3441  // work a little harder to print an informative error
3442  // message.
3443  //
3444  // Broadcast the Adder's idea of the matrix dimensions
3445  // from Proc 0 to all processes.
3446  Tuple<global_ordinal_type, 2> addersDims;
3447  if (myRank == rootRank) {
3448  addersDims[0] = pAdder->getAdder()->numRows();
3449  addersDims[1] = pAdder->getAdder()->numCols();
3450  }
3451  broadcast (*pComm, 0, addersDims);
3452  TEUCHOS_TEST_FOR_EXCEPTION(
3453  dimsMatch == 0, std::runtime_error,
3454  "The matrix metadata says that the matrix is " << dims[0] << " x "
3455  << dims[1] << ", but the actual data says that the matrix is "
3456  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3457  "data includes more rows than reported in the metadata. This "
3458  "is not allowed when parsing in strict mode. Parse the matrix in "
3459  "tolerant mode to ignore the metadata when it disagrees with the "
3460  "data.");
3461  }
3462  } // Matrix dimensions (# rows, # cols, # entries) agree.
3463 
3464  if (debug && myRank == rootRank) {
3465  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3466  }
3467 
3468  // Now that we've read in all the matrix entries from the
3469  // input stream into the adder on Proc 0, post-process them
3470  // into CSR format (still on Proc 0). This will facilitate
3471  // distributing them to all the processors.
3472  //
3473  // These arrays represent the global matrix data as a CSR
3474  // matrix (with numEntriesPerRow as redundant but convenient
3475  // metadata, since it's computable from rowPtr and vice
3476  // versa). They are valid only on Proc 0.
3477  ArrayRCP<size_t> numEntriesPerRow;
3478  ArrayRCP<size_t> rowPtr;
3479  ArrayRCP<global_ordinal_type> colInd;
3480  ArrayRCP<scalar_type> values;
3481 
3482  // Proc 0 first merges duplicate entries, and then converts
3483  // the coordinate-format matrix data to CSR.
3484  {
3485  int mergeAndConvertSucceeded = 1;
3486  std::ostringstream errMsg;
3487 
3488  if (myRank == rootRank) {
3489  try {
3490  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3491  global_ordinal_type> element_type;
3492 
3493  // Number of rows in the matrix. If we are in tolerant
3494  // mode, we've already synchronized dims with the actual
3495  // matrix data. If in strict mode, we should use dims
3496  // (as read from the file's metadata) rather than the
3497  // matrix data to determine the dimensions. (The matrix
3498  // data will claim fewer rows than the metadata, if one
3499  // or more rows have no entries stored in the file.)
3500  const size_type numRows = dims[0];
3501 
3502  // Additively merge duplicate matrix entries.
3503  pAdder->getAdder()->merge ();
3504 
3505  // Get a temporary const view of the merged matrix entries.
3506  const std::vector<element_type>& entries =
3507  pAdder->getAdder()->getEntries();
3508 
3509  // Number of matrix entries (after merging).
3510  const size_t numEntries = (size_t)entries.size();
3511 
3512  if (debug) {
3513  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3514  << " rows and numEntries=" << numEntries
3515  << " entries." << endl;
3516  }
3517 
3518  // Make space for the CSR matrix data. Converting to
3519  // CSR is easier if we fill numEntriesPerRow with zeros
3520  // at first.
3521  numEntriesPerRow = arcp<size_t> (numRows);
3522  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3523  rowPtr = arcp<size_t> (numRows+1);
3524  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3525  colInd = arcp<global_ordinal_type> (numEntries);
3526  values = arcp<scalar_type> (numEntries);
3527 
3528  // Convert from array-of-structs coordinate format to CSR
3529  // (compressed sparse row) format.
3530  global_ordinal_type prvRow = 0;
3531  size_t curPos = 0;
3532  rowPtr[0] = 0;
3533  for (curPos = 0; curPos < numEntries; ++curPos) {
3534  const element_type& curEntry = entries[curPos];
3535  const global_ordinal_type curRow = curEntry.rowIndex();
3536  TEUCHOS_TEST_FOR_EXCEPTION(
3537  curRow < prvRow, std::logic_error,
3538  "Row indices are out of order, even though they are supposed "
3539  "to be sorted. curRow = " << curRow << ", prvRow = "
3540  << prvRow << ", at curPos = " << curPos << ". Please report "
3541  "this bug to the Tpetra developers.");
3542  if (curRow > prvRow) {
3543  prvRow = curRow;
3544  }
3545  numEntriesPerRow[curRow]++;
3546  colInd[curPos] = curEntry.colIndex();
3547  values[curPos] = curEntry.value();
3548  }
3549 
3550  rowPtr[0] = 0;
3551  for (global_ordinal_type row = 1; row <= numRows; ++row) {
3552  rowPtr[row] = numEntriesPerRow[row-1] + rowPtr[row-1];
3553  }
3554  } // Finished conversion to CSR format
3555  catch (std::exception& e) {
3556  mergeAndConvertSucceeded = 0;
3557  errMsg << "Failed to merge sparse matrix entries and convert to "
3558  "CSR format: " << e.what();
3559  }
3560 
3561  if (debug && mergeAndConvertSucceeded) {
3562  // Number of rows in the matrix.
3563  const size_type numRows = dims[0];
3564  const size_type maxToDisplay = 100;
3565 
3566  cerr << "----- Proc 0: numEntriesPerRow[0.."
3567  << (numEntriesPerRow.size()-1) << "] ";
3568  if (numRows > maxToDisplay) {
3569  cerr << "(only showing first and last few entries) ";
3570  }
3571  cerr << "= [";
3572  if (numRows > 0) {
3573  if (numRows > maxToDisplay) {
3574  for (size_type k = 0; k < 2; ++k) {
3575  cerr << numEntriesPerRow[k] << " ";
3576  }
3577  cerr << "... ";
3578  for (size_type k = numRows-2; k < numRows-1; ++k) {
3579  cerr << numEntriesPerRow[k] << " ";
3580  }
3581  }
3582  else {
3583  for (size_type k = 0; k < numRows-1; ++k) {
3584  cerr << numEntriesPerRow[k] << " ";
3585  }
3586  }
3587  cerr << numEntriesPerRow[numRows-1];
3588  } // numRows > 0
3589  cerr << "]" << endl;
3590 
3591  cerr << "----- Proc 0: rowPtr ";
3592  if (numRows > maxToDisplay) {
3593  cerr << "(only showing first and last few entries) ";
3594  }
3595  cerr << "= [";
3596  if (numRows > maxToDisplay) {
3597  for (size_type k = 0; k < 2; ++k) {
3598  cerr << rowPtr[k] << " ";
3599  }
3600  cerr << "... ";
3601  for (size_type k = numRows-2; k < numRows; ++k) {
3602  cerr << rowPtr[k] << " ";
3603  }
3604  }
3605  else {
3606  for (size_type k = 0; k < numRows; ++k) {
3607  cerr << rowPtr[k] << " ";
3608  }
3609  }
3610  cerr << rowPtr[numRows] << "]" << endl;
3611 
3612  cerr << "----- Proc 0: colInd = [";
3613  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3614  cerr << colInd[k] << " ";
3615  }
3616  cerr << "]" << endl;
3617  }
3618  } // if myRank == rootRank
3619  } // Done converting sparse matrix data to CSR format
3620 
3621  // Now we're done with the Adder, so we can release the
3622  // reference ("free" it) to save space. This only actually
3623  // does anything on Rank 0, since pAdder is null on all the
3624  // other MPI processes.
3625  pAdder = null;
3626 
3627  // Verify details of the Maps. Don't count the global number
3628  // of entries in the row Map, since that number doesn't
3629  // correctly count overlap.
3630  if (debug && myRank == rootRank) {
3631  cerr << "-- Verifying Maps" << endl;
3632  }
3633  TEUCHOS_TEST_FOR_EXCEPTION(
3634  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3635  std::invalid_argument,
3636  "The range Map has " << rangeMap->getGlobalNumElements ()
3637  << " entries, but the matrix has a global number of rows " << dims[0]
3638  << ".");
3639  TEUCHOS_TEST_FOR_EXCEPTION(
3640  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3641  std::invalid_argument,
3642  "The domain Map has " << domainMap->getGlobalNumElements ()
3643  << " entries, but the matrix has a global number of columns "
3644  << dims[1] << ".");
3645 
3646  // Create a row Map which is entirely owned on Proc 0.
3647  RCP<Teuchos::FancyOStream> err = debug ?
3648  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3649 
3650  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3651  ArrayView<const global_ordinal_type> myRows =
3652  gatherRowMap->getLocalElementList ();
3653  const size_type myNumRows = myRows.size ();
3654  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3655 
3656  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3657  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3658  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3659  }
3660 
3661  // Create a matrix using this Map, and fill in on Proc 0. We
3662  // know how many entries there are in each row, so we can use
3663  // static profile.
3664  RCP<sparse_matrix_type> A_proc0 =
3665  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow()));
3666  if (myRank == rootRank) {
3667  if (debug) {
3668  cerr << "-- Proc 0: Filling gather matrix" << endl;
3669  }
3670  if (debug) {
3671  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3672  }
3673 
3674  // Add Proc 0's matrix entries to the CrsMatrix.
3675  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3676  size_type i = myRows[i_] - indexBase;
3677 
3678  const size_type curPos = as<size_type> (rowPtr[i]);
3679  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3680  ArrayView<global_ordinal_type> curColInd =
3681  colInd.view (curPos, curNumEntries);
3682  ArrayView<scalar_type> curValues =
3683  values.view (curPos, curNumEntries);
3684 
3685  // Modify the column indices in place to have the right index base.
3686  for (size_type k = 0; k < curNumEntries; ++k) {
3687  curColInd[k] += indexBase;
3688  }
3689  if (debug) {
3690  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3691  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3692  }
3693  // Avoid constructing empty views of ArrayRCP objects.
3694  if (curNumEntries > 0) {
3695  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3696  }
3697  }
3698  // Now we can save space by deallocating numEntriesPerRow,
3699  // rowPtr, colInd, and values, since we've already put those
3700  // data in the matrix.
3701  numEntriesPerRow = null;
3702  rowPtr = null;
3703  colInd = null;
3704  values = null;
3705  } // if myRank == rootRank
3706 
3707  RCP<sparse_matrix_type> A;
3709  export_type exp (gatherRowMap, rowMap);
3710 
3711  // Communicate the precise number of nonzeros per row, which was already
3712  // calculated above.
3713  typedef local_ordinal_type LO;
3714  typedef global_ordinal_type GO;
3715  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
3716  mv_type_go target_nnzPerRow(rowMap,1);
3717  mv_type_go source_nnzPerRow(gatherRowMap,1);
3718  Teuchos::ArrayRCP<GO> srcData = source_nnzPerRow.getDataNonConst(0);
3719  for (int i=0; i<myNumRows; i++)
3720  srcData[i] = gatherNumEntriesPerRow[i];
3721  srcData = Teuchos::null;
3722  target_nnzPerRow.doExport(source_nnzPerRow,exp,Tpetra::INSERT);
3723  Teuchos::ArrayRCP<GO> targetData = target_nnzPerRow.getDataNonConst(0);
3724  ArrayRCP<size_t> targetData_size_t = arcp<size_t>(targetData.size());
3725  for (int i=0; i<targetData.size(); i++)
3726  targetData_size_t[i] = targetData[i];
3727 
3728  if (colMap.is_null ()) {
3729  A = rcp (new sparse_matrix_type (rowMap, targetData_size_t()));
3730  } else {
3731  A = rcp (new sparse_matrix_type (rowMap, colMap, targetData_size_t()));
3732  }
3733  A->doExport (*A_proc0, exp, INSERT);
3734  if (callFillComplete) {
3735  A->fillComplete (domainMap, rangeMap);
3736  }
3737 
3738  // We can't get the dimensions of the matrix until after
3739  // fillComplete() is called. Thus, we can't do the sanity
3740  // check (dimensions read from the Matrix Market data,
3741  // vs. dimensions reported by the CrsMatrix) unless the user
3742  // asked us to call fillComplete().
3743  //
3744  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3745  // what one might think it does, so you have to ask the range
3746  // resp. domain map for the number of rows resp. columns.
3747  if (callFillComplete) {
3748  const int numProcs = pComm->getSize ();
3749 
3750  if (extraDebug && debug) {
3751  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3752  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3753  if (myRank == rootRank) {
3754  cerr << "-- Matrix is "
3755  << globalNumRows << " x " << globalNumCols
3756  << " with " << A->getGlobalNumEntries()
3757  << " entries, and index base "
3758  << A->getIndexBase() << "." << endl;
3759  }
3760  pComm->barrier ();
3761  for (int p = 0; p < numProcs; ++p) {
3762  if (myRank == p) {
3763  cerr << "-- Proc " << p << " owns "
3764  << A->getLocalNumCols() << " columns, and "
3765  << A->getLocalNumEntries() << " entries." << endl;
3766  }
3767  pComm->barrier ();
3768  }
3769  } // if (extraDebug && debug)
3770  } // if (callFillComplete)
3771 
3772  if (debug && myRank == rootRank) {
3773  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3774  << endl;
3775  }
3776  return A;
3777  }
3778 
3808  static Teuchos::RCP<multivector_type>
3809  readDenseFile (const std::string& filename,
3810  const trcp_tcomm_t& comm,
3811  Teuchos::RCP<const map_type>& map,
3812  const bool tolerant=false,
3813  const bool debug=false,
3814  const bool binary=false)
3815  {
3816  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true, binary ? std::ios::binary : std::ios::in);
3817 
3818  return readDense (in, comm, map, tolerant, debug, binary);
3819  }
3820 
3831  static std::ifstream openInFileOnRankZero(
3832  const trcp_tcomm_t& comm,
3833  const std::string& filename, const bool safe = true,
3834  std::ios_base::openmode mode = std::ios_base::in
3835  ){
3836  // Input stream.
3837  std::ifstream in;
3838 
3839  // Placeholder for broadcasting in-stream state.
3840  int all_should_stop = false;
3841 
3842  // Try to open the in-stream on root rank.
3843  if (comm->getRank() == 0) {
3844  in.open(filename, mode);
3845  all_should_stop = !in && safe;
3846  }
3847 
3848  // Broadcast state and possibly throw.
3849  if(comm) Teuchos::broadcast(*comm, 0, &all_should_stop);
3850 
3851  TEUCHOS_TEST_FOR_EXCEPTION(
3852  all_should_stop,
3853  std::runtime_error,
3854  "Could not open input file '" + filename + "' on root rank 0."
3855  );
3856 
3857  return in;
3858  }
3859 
3860 
3890  static Teuchos::RCP<vector_type>
3891  readVectorFile (const std::string& filename,
3892  const trcp_tcomm_t& comm,
3893  Teuchos::RCP<const map_type>& map,
3894  const bool tolerant=false,
3895  const bool debug=false)
3896  {
3897  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true);
3898 
3899  return readVector (in, comm, map, tolerant, debug);
3900  }
3901 
3902 
3970 
3971  static Teuchos::RCP<multivector_type>
3972  readDense (std::istream& in,
3973  const trcp_tcomm_t& comm,
3974  Teuchos::RCP<const map_type>& map,
3975  const bool tolerant=false,
3976  const bool debug=false,
3977  const bool binary=false)
3978  {
3979  Teuchos::RCP<Teuchos::FancyOStream> err =
3980  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
3981  return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug, binary);
3982  }
3983 
3984 
3986  static Teuchos::RCP<vector_type>
3987  readVector (std::istream& in,
3988  const trcp_tcomm_t& comm,
3989  Teuchos::RCP<const map_type>& map,
3990  const bool tolerant=false,
3991  const bool debug=false)
3992  {
3993  Teuchos::RCP<Teuchos::FancyOStream> err =
3994  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
3995  return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
3996  }
3997 
3998 
4020  static Teuchos::RCP<const map_type>
4021  readMapFile (const std::string& filename,
4022  const trcp_tcomm_t& comm,
4023  const bool tolerant=false,
4024  const bool debug=false,
4025  const bool binary=false)
4026  {
4027  std::ifstream in = Reader::openInFileOnRankZero(comm, filename, true, binary ? std::ios::binary : std::ios::in);
4028 
4029  return readMap (in, comm, tolerant, debug, binary);
4030  }
4031 
4032 
4033  private:
4034  template<class MultiVectorScalarType>
4035  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4038  node_type> >
4039  readDenseImpl (std::istream& in,
4040  const trcp_tcomm_t& comm,
4041  Teuchos::RCP<const map_type>& map,
4042  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4043  const bool tolerant=false,
4044  const bool debug=false,
4045  const bool binary=false)
4046  {
4047  using Teuchos::MatrixMarket::Banner;
4048  using Teuchos::MatrixMarket::checkCommentLine;
4049  using Teuchos::ArrayRCP;
4050  using Teuchos::as;
4051  using Teuchos::broadcast;
4052  using Teuchos::outArg;
4053  using Teuchos::RCP;
4054  using Teuchos::Tuple;
4055  using std::endl;
4056  typedef MultiVectorScalarType ST;
4057  typedef local_ordinal_type LO;
4058  typedef global_ordinal_type GO;
4059  typedef node_type NT;
4060  typedef Teuchos::ScalarTraits<ST> STS;
4061  typedef typename STS::magnitudeType MT;
4062  typedef Teuchos::ScalarTraits<MT> STM;
4064 
4065  // Rank 0 is the only (MPI) process allowed to read from the
4066  // input stream.
4067  const int myRank = comm->getRank ();
4068 
4069  if (! err.is_null ()) {
4070  err->pushTab ();
4071  }
4072  if (debug) {
4073  *err << myRank << ": readDenseImpl" << endl;
4074  }
4075  if (! err.is_null ()) {
4076  err->pushTab ();
4077  }
4078 
4079  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4080  // instances be identical and that the Node instances be
4081  // identical. The essential condition is more complicated to
4082  // test and isn't the same for all Node types. Thus, we just
4083  // leave it up to the user.
4084 
4085  // // If map is nonnull, check the precondition that its
4086  // // communicator resp. node equal comm resp. node. Checking
4087  // // now avoids doing a lot of file reading before we detect the
4088  // // violated precondition.
4089  // TEUCHOS_TEST_FOR_EXCEPTION(
4090  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4091  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4092  // "communicator and node must equal the supplied communicator resp. "
4093  // "node.");
4094 
4095  // Process 0 will read in the matrix dimensions from the file,
4096  // and broadcast them to all ranks in the given communicator.
4097  // There are only 2 dimensions in the matrix, but we use the
4098  // third element of the Tuple to encode the banner's reported
4099  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4100  // (same as "real"). We don't allow pattern matrices (i.e.,
4101  // graphs) since they only make sense for sparse data.
4102  Tuple<GO, 3> dims;
4103  dims[0] = 0;
4104  dims[1] = 0;
4105  dims[2] = 0;
4106 
4107  // Current line number in the input stream. Only valid on
4108  // Proc 0. Various calls will modify this depending on the
4109  // number of lines that are read from the input stream.
4110  size_t lineNumber = 1;
4111 
4112  // Capture errors and their messages on Proc 0.
4113  std::ostringstream exMsg;
4114  int localBannerReadSuccess = 1;
4115  int localDimsReadSuccess = 1;
4116 
4117  // Only Proc 0 gets to read matrix data from the input stream.
4118  if (myRank == 0) {
4119  if (! binary) {
4120  if (debug) {
4121  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4122  }
4123 
4124  // The "Banner" tells you whether the input stream
4125  // represents a dense matrix, the symmetry type of the
4126  // matrix, and the type of the data it contains.
4127  RCP<const Banner> pBanner;
4128  try {
4129  pBanner = readBanner (in, lineNumber, tolerant, debug);
4130  } catch (std::exception& e) {
4131  exMsg << e.what ();
4132  localBannerReadSuccess = 0;
4133  }
4134  // Make sure the input stream is the right kind of data.
4135  if (localBannerReadSuccess) {
4136  if (pBanner->matrixType () != "array") {
4137  exMsg << "The Matrix Market file does not contain dense matrix "
4138  "data. Its banner (first) line says that its matrix type is \""
4139  << pBanner->matrixType () << "\", rather that the required "
4140  "\"array\".";
4141  localBannerReadSuccess = 0;
4142  } else if (pBanner->dataType() == "pattern") {
4143  exMsg << "The Matrix Market file's banner (first) "
4144  "line claims that the matrix's data type is \"pattern\". This does "
4145  "not make sense for a dense matrix, yet the file reports the matrix "
4146  "as dense. The only valid data types for a dense matrix are "
4147  "\"real\", \"complex\", and \"integer\".";
4148  localBannerReadSuccess = 0;
4149  } else {
4150  // Encode the data type reported by the Banner as the
4151  // third element of the dimensions Tuple.
4152  dims[2] = encodeDataType (pBanner->dataType ());
4153  }
4154  } // if we successfully read the banner line
4155 
4156  // At this point, we've successfully read the banner line.
4157  // Now read the dimensions line.
4158  if (localBannerReadSuccess) {
4159  if (debug) {
4160  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4161  }
4162  // Keep reading lines from the input stream until we find
4163  // a non-comment line, or until we run out of lines. The
4164  // latter is an error, since every "array" format Matrix
4165  // Market file must have a dimensions line after the
4166  // banner (even if the matrix has zero rows or columns, or
4167  // zero entries).
4168  std::string line;
4169  bool commentLine = true;
4170 
4171  while (commentLine) {
4172  // Test whether it is even valid to read from the input
4173  // stream wrapping the line.
4174  if (in.eof () || in.fail ()) {
4175  exMsg << "Unable to get array dimensions line (at all) from line "
4176  << lineNumber << " of input stream. The input stream "
4177  << "claims that it is "
4178  << (in.eof() ? "at end-of-file." : "in a failed state.");
4179  localDimsReadSuccess = 0;
4180  } else {
4181  // Try to get the next line from the input stream.
4182  if (getline (in, line)) {
4183  ++lineNumber; // We did actually read a line.
4184  }
4185  // Is the current line a comment line? Ignore start
4186  // and size; they are only useful for reading the
4187  // actual matrix entries. (We could use them here as
4188  // an optimization, but we've chosen not to.)
4189  size_t start = 0, size = 0;
4190  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4191  } // whether we failed to read the line at all
4192  } // while the line we just read is a comment line
4193 
4194  //
4195  // Get <numRows> <numCols> from the line we just read.
4196  //
4197  std::istringstream istr (line);
4198 
4199  // Test whether it is even valid to read from the input
4200  // stream wrapping the line.
4201  if (istr.eof () || istr.fail ()) {
4202  exMsg << "Unable to read any data from line " << lineNumber
4203  << " of input; the line should contain the matrix dimensions "
4204  << "\"<numRows> <numCols>\".";
4205  localDimsReadSuccess = 0;
4206  } else { // It's valid to read from the line.
4207  GO theNumRows = 0;
4208  istr >> theNumRows; // Read in the number of rows.
4209  if (istr.fail ()) {
4210  exMsg << "Failed to get number of rows from line "
4211  << lineNumber << " of input; the line should contains the "
4212  << "matrix dimensions \"<numRows> <numCols>\".";
4213  localDimsReadSuccess = 0;
4214  } else { // We successfully read the number of rows
4215  dims[0] = theNumRows; // Save the number of rows
4216  if (istr.eof ()) { // Do we still have data to read?
4217  exMsg << "No more data after number of rows on line "
4218  << lineNumber << " of input; the line should contain the "
4219  << "matrix dimensions \"<numRows> <numCols>\".";
4220  localDimsReadSuccess = 0;
4221  } else { // Still data left to read; read in number of columns.
4222  GO theNumCols = 0;
4223  istr >> theNumCols; // Read in the number of columns
4224  if (istr.fail ()) {
4225  exMsg << "Failed to get number of columns from line "
4226  << lineNumber << " of input; the line should contain "
4227  << "the matrix dimensions \"<numRows> <numCols>\".";
4228  localDimsReadSuccess = 0;
4229  } else { // We successfully read the number of columns
4230  dims[1] = theNumCols; // Save the number of columns
4231  } // if istr.fail ()
4232  } // if istr.eof ()
4233  } // if we read the number of rows
4234  } // if the input stream wrapping the dims line was (in)valid
4235  } // if we successfully read the banner line
4236  } // not in binary format
4237  else { // in binary format
4238  global_size_t numRows, numCols;
4239  in.read(reinterpret_cast<char*>(&numRows), sizeof(numRows));
4240  in.read(reinterpret_cast<char*>(&numCols), sizeof(numCols));
4241  dims[0] = Teuchos::as<GO>(numRows);
4242  dims[1] = Teuchos::as<GO>(numCols);
4243  if ((typeid(ST) == typeid(double)) || Teuchos::ScalarTraits<ST>::isOrdinal) {
4244  dims[2] = 0;
4245  } else if (Teuchos::ScalarTraits<ST>::isComplex) {
4246  dims[2] = 1;
4247  } else {
4248  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
4249  "Unrecognized Matrix Market data type. "
4250  "We should never get here. "
4251  "Please report this bug to the Tpetra developers.");
4252  }
4253  localDimsReadSuccess = true;
4254  localDimsReadSuccess = true;
4255  } // in binary format
4256  } // if (myRank == 0)
4257 
4258  // Broadcast the matrix dimensions, the encoded data type, and
4259  // whether or not Proc 0 succeeded in reading the banner and
4260  // dimensions.
4261  Tuple<GO, 5> bannerDimsReadResult;
4262  if (myRank == 0) {
4263  bannerDimsReadResult[0] = dims[0]; // numRows
4264  bannerDimsReadResult[1] = dims[1]; // numCols
4265  bannerDimsReadResult[2] = dims[2]; // encoded data type
4266  bannerDimsReadResult[3] = localBannerReadSuccess;
4267  bannerDimsReadResult[4] = localDimsReadSuccess;
4268  }
4269  // Broadcast matrix dimensions and the encoded data type from
4270  // Proc 0 to all the MPI processes.
4271  broadcast (*comm, 0, bannerDimsReadResult);
4272 
4273  TEUCHOS_TEST_FOR_EXCEPTION(
4274  bannerDimsReadResult[3] == 0, std::runtime_error,
4275  "Failed to read banner line: " << exMsg.str ());
4276  TEUCHOS_TEST_FOR_EXCEPTION(
4277  bannerDimsReadResult[4] == 0, std::runtime_error,
4278  "Failed to read matrix dimensions line: " << exMsg.str ());
4279  if (myRank != 0) {
4280  dims[0] = bannerDimsReadResult[0];
4281  dims[1] = bannerDimsReadResult[1];
4282  dims[2] = bannerDimsReadResult[2];
4283  }
4284 
4285  // Tpetra objects want the matrix dimensions in these types.
4286  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4287  const size_t numCols = static_cast<size_t> (dims[1]);
4288 
4289  // Make a "Proc 0 owns everything" Map that we will use to
4290  // read in the multivector entries in the correct order on
4291  // Proc 0. This must be a collective
4292  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4293  if (map.is_null ()) {
4294  // The user didn't supply a Map. Make a contiguous
4295  // distributed Map for them, using the read-in multivector
4296  // dimensions.
4297  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4298  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4299  // At this point, map exists and has a nonnull node.
4300  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4301  comm);
4302  }
4303  else { // The user supplied a Map.
4304  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4305  }
4306 
4307  // Make a multivector X owned entirely by Proc 0.
4308  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4309 
4310  //
4311  // On Proc 0, read the Matrix Market data from the input
4312  // stream into the multivector X.
4313  //
4314  int localReadDataSuccess = 1;
4315  if (myRank == 0) {
4316  if (! binary) {
4317  try {
4318  if (debug) {
4319  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4320  << endl;
4321  }
4322 
4323  // Make sure that we can get a 1-D view of X.
4324  TEUCHOS_TEST_FOR_EXCEPTION(
4325  ! X->isConstantStride (), std::logic_error,
4326  "Can't get a 1-D view of the entries of the MultiVector X on "
4327  "Process 0, because the stride between the columns of X is not "
4328  "constant. This shouldn't happen because we just created X and "
4329  "haven't filled it in yet. Please report this bug to the Tpetra "
4330  "developers.");
4331 
4332  // Get a writeable 1-D view of the entries of X. Rank 0
4333  // owns all of them. The view will expire at the end of
4334  // scope, so (if necessary) it will be written back to X
4335  // at this time.
4336  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4337  TEUCHOS_TEST_FOR_EXCEPTION(
4338  as<global_size_t> (X_view.size ()) < numRows * numCols,
4339  std::logic_error,
4340  "The view of X has size " << X_view.size() << " which is not enough to "
4341  "accommodate the expected number of entries numRows*numCols = "
4342  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4343  "Please report this bug to the Tpetra developers.");
4344  const size_t stride = X->getStride ();
4345 
4346  // The third element of the dimensions Tuple encodes the data
4347  // type reported by the Banner: "real" == 0, "complex" == 1,
4348  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4349  // allow dense matrices to be pattern matrices, so dims[2] ==
4350  // 0 or 1. We've already checked for this above.
4351  const bool isComplex = (dims[2] == 1);
4352  size_type count = 0, curRow = 0, curCol = 0;
4353 
4354  std::string line;
4355  while (getline (in, line)) {
4356  ++lineNumber;
4357  // Is the current line a comment line? If it's not,
4358  // line.substr(start,size) contains the data.
4359  size_t start = 0, size = 0;
4360  const bool commentLine =
4361  checkCommentLine (line, start, size, lineNumber, tolerant);
4362  if (! commentLine) {
4363  // Make sure we have room in which to put the new matrix
4364  // entry. We check this only after checking for a
4365  // comment line, because there may be one or more
4366  // comment lines at the end of the file. In tolerant
4367  // mode, we simply ignore any extra data.
4368  if (count >= X_view.size()) {
4369  if (tolerant) {
4370  break;
4371  }
4372  else {
4373  TEUCHOS_TEST_FOR_EXCEPTION(
4374  count >= X_view.size(),
4375  std::runtime_error,
4376  "The Matrix Market input stream has more data in it than "
4377  "its metadata reported. Current line number is "
4378  << lineNumber << ".");
4379  }
4380  }
4381 
4382  // mfh 19 Dec 2012: Ignore everything up to the initial
4383  // colon. writeDense() has the option to print out the
4384  // global row index in front of each entry, followed by
4385  // a colon and space.
4386  {
4387  const size_t pos = line.substr (start, size).find (':');
4388  if (pos != std::string::npos) {
4389  start = pos+1;
4390  }
4391  }
4392  std::istringstream istr (line.substr (start, size));
4393  // Does the line contain anything at all? Can we
4394  // safely read from the input stream wrapping the
4395  // line?
4396  if (istr.eof() || istr.fail()) {
4397  // In tolerant mode, simply ignore the line.
4398  if (tolerant) {
4399  break;
4400  }
4401  // We repeat the full test here so the exception
4402  // message is more informative.
4403  TEUCHOS_TEST_FOR_EXCEPTION(
4404  ! tolerant && (istr.eof() || istr.fail()),
4405  std::runtime_error,
4406  "Line " << lineNumber << " of the Matrix Market file is "
4407  "empty, or we cannot read from it for some other reason.");
4408  }
4409  // Current matrix entry to read in.
4410  ST val = STS::zero();
4411  // Real and imaginary parts of the current matrix entry.
4412  // The imaginary part is zero if the matrix is real-valued.
4413  MT real = STM::zero(), imag = STM::zero();
4414 
4415  // isComplex refers to the input stream's data, not to
4416  // the scalar type S. It's OK to read real-valued
4417  // data into a matrix storing complex-valued data; in
4418  // that case, all entries' imaginary parts are zero.
4419  if (isComplex) {
4420  // STS::real() and STS::imag() return a copy of
4421  // their respective components, not a writeable
4422  // reference. Otherwise we could just assign to
4423  // them using the istream extraction operator (>>).
4424  // That's why we have separate magnitude type "real"
4425  // and "imag" variables.
4426 
4427  // Attempt to read the real part of the current entry.
4428  istr >> real;
4429  if (istr.fail()) {
4430  TEUCHOS_TEST_FOR_EXCEPTION(
4431  ! tolerant && istr.eof(), std::runtime_error,
4432  "Failed to get the real part of a complex-valued matrix "
4433  "entry from line " << lineNumber << " of the Matrix Market "
4434  "file.");
4435  // In tolerant mode, just skip bad lines.
4436  if (tolerant) {
4437  break;
4438  }
4439  } else if (istr.eof()) {
4440  TEUCHOS_TEST_FOR_EXCEPTION(
4441  ! tolerant && istr.eof(), std::runtime_error,
4442  "Missing imaginary part of a complex-valued matrix entry "
4443  "on line " << lineNumber << " of the Matrix Market file.");
4444  // In tolerant mode, let any missing imaginary part be 0.
4445  } else {
4446  // Attempt to read the imaginary part of the current
4447  // matrix entry.
4448  istr >> imag;
4449  TEUCHOS_TEST_FOR_EXCEPTION(
4450  ! tolerant && istr.fail(), std::runtime_error,
4451  "Failed to get the imaginary part of a complex-valued "
4452  "matrix entry from line " << lineNumber << " of the "
4453  "Matrix Market file.");
4454  // In tolerant mode, let any missing or corrupted
4455  // imaginary part be 0.
4456  }
4457  } else { // Matrix Market file contains real-valued data.
4458  // Attempt to read the current matrix entry.
4459  istr >> real;
4460  TEUCHOS_TEST_FOR_EXCEPTION(
4461  ! tolerant && istr.fail(), std::runtime_error,
4462  "Failed to get a real-valued matrix entry from line "
4463  << lineNumber << " of the Matrix Market file.");
4464  // In tolerant mode, simply ignore the line if
4465  // we failed to read a matrix entry.
4466  if (istr.fail() && tolerant) {
4467  break;
4468  }
4469  }
4470  // In tolerant mode, we simply let pass through whatever
4471  // data we got.
4472  TEUCHOS_TEST_FOR_EXCEPTION(
4473  ! tolerant && istr.fail(), std::runtime_error,
4474  "Failed to read matrix data from line " << lineNumber
4475  << " of the Matrix Market file.");
4476 
4477  // Assign val = ST(real, imag).
4478  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4479 
4480  curRow = count % numRows;
4481  curCol = count / numRows;
4482  X_view[curRow + curCol*stride] = val;
4483  ++count;
4484  } // if not a comment line
4485  } // while there are still lines in the file, get the next one
4486 
4487  TEUCHOS_TEST_FOR_EXCEPTION(
4488  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4489  std::runtime_error,
4490  "The Matrix Market metadata reports that the dense matrix is "
4491  << numRows << " x " << numCols << ", and thus has "
4492  << numRows*numCols << " total entries, but we only found " << count
4493  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4494  } catch (std::exception& e) {
4495  exMsg << e.what ();
4496  localReadDataSuccess = 0;
4497  }
4498  } // not binary file
4499  else {
4500  if (debug) {
4501  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4502  << endl;
4503  }
4504 
4505  // Make sure that we can get a 1-D view of X.
4506  TEUCHOS_TEST_FOR_EXCEPTION(
4507  ! X->isConstantStride (), std::logic_error,
4508  "Can't get a 1-D view of the entries of the MultiVector X on "
4509  "Process 0, because the stride between the columns of X is not "
4510  "constant. This shouldn't happen because we just created X and "
4511  "haven't filled it in yet. Please report this bug to the Tpetra "
4512  "developers.");
4513 
4514  // Get a writeable 1-D view of the entries of X. Rank 0
4515  // owns all of them. The view will expire at the end of
4516  // scope, so (if necessary) it will be written back to X
4517  // at this time.
4518  auto X_view = X->getLocalViewHost (Access::OverwriteAll);
4519 
4520  TEUCHOS_TEST_FOR_EXCEPTION(
4521  as<global_size_t> (X_view.extent(0)) < numRows,
4522  std::logic_error,
4523  "The view of X has " << X_view.extent(0) << " rows which is not enough to "
4524  "accommodate the expected number of entries numRows = "
4525  << numRows << ". "
4526  "Please report this bug to the Tpetra developers.");
4527  TEUCHOS_TEST_FOR_EXCEPTION(
4528  as<global_size_t> (X_view.extent(1)) < numCols,
4529  std::logic_error,
4530  "The view of X has " << X_view.extent(1) << " colums which is not enough to "
4531  "accommodate the expected number of entries numRows = "
4532  << numCols << ". "
4533  "Please report this bug to the Tpetra developers.");
4534 
4535  for (size_t curRow = 0; curRow < numRows; ++curRow) {
4536  for (size_t curCol = 0; curCol < numCols; ++curCol) {
4537  if (Teuchos::ScalarTraits<ST>::isOrdinal){
4538  global_size_t val;
4539  in.read(reinterpret_cast<char*>(&val), sizeof(val));
4540  X_view(curRow, curCol) = val;
4541  } else {
4542  double val;
4543  in.read(reinterpret_cast<char*>(&val), sizeof(val));
4544  X_view(curRow, curCol) = val;
4545  }
4546  }
4547  }
4548  } // binary
4549  } // if (myRank == 0)
4550 
4551  if (debug) {
4552  *err << myRank << ": readDenseImpl: done reading data" << endl;
4553  }
4554 
4555  // Synchronize on whether Proc 0 successfully read the data.
4556  int globalReadDataSuccess = localReadDataSuccess;
4557  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4558  TEUCHOS_TEST_FOR_EXCEPTION(
4559  globalReadDataSuccess == 0, std::runtime_error,
4560  "Failed to read the multivector's data: " << exMsg.str ());
4561 
4562  // If there's only one MPI process and the user didn't supply
4563  // a Map (i.e., pMap is null), we're done. Set pMap to the
4564  // Map used to distribute X, and return X.
4565  if (comm->getSize () == 1 && map.is_null ()) {
4566  map = proc0Map;
4567  if (! err.is_null ()) {
4568  err->popTab ();
4569  }
4570  if (debug) {
4571  *err << myRank << ": readDenseImpl: done" << endl;
4572  }
4573  if (! err.is_null ()) {
4574  err->popTab ();
4575  }
4576  return X;
4577  }
4578 
4579  if (debug) {
4580  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4581  }
4582 
4583  // Make a multivector Y with the distributed map pMap.
4584  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4585 
4586  if (debug) {
4587  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4588  }
4589 
4590  // Make an Export object that will export X to Y. First
4591  // argument is the source map, second argument is the target
4592  // map.
4593  Export<LO, GO, NT> exporter (proc0Map, map, err);
4594 
4595  if (debug) {
4596  *err << myRank << ": readDenseImpl: Exporting" << endl;
4597  }
4598  // Export X into Y.
4599  Y->doExport (*X, exporter, INSERT);
4600 
4601  if (! err.is_null ()) {
4602  err->popTab ();
4603  }
4604  if (debug) {
4605  *err << myRank << ": readDenseImpl: done" << endl;
4606  }
4607  if (! err.is_null ()) {
4608  err->popTab ();
4609  }
4610 
4611  // Y is distributed over all process(es) in the communicator.
4612  return Y;
4613  }
4614 
4615 
4616  template<class VectorScalarType>
4617  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4620  node_type> >
4621  readVectorImpl (std::istream& in,
4622  const trcp_tcomm_t& comm,
4623  Teuchos::RCP<const map_type>& map,
4624  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4625  const bool tolerant=false,
4626  const bool debug=false)
4627  {
4628  using Teuchos::MatrixMarket::Banner;
4629  using Teuchos::MatrixMarket::checkCommentLine;
4630  using Teuchos::as;
4631  using Teuchos::broadcast;
4632  using Teuchos::outArg;
4633  using Teuchos::RCP;
4634  using Teuchos::Tuple;
4635  using std::endl;
4636  typedef VectorScalarType ST;
4637  typedef local_ordinal_type LO;
4638  typedef global_ordinal_type GO;
4639  typedef node_type NT;
4640  typedef Teuchos::ScalarTraits<ST> STS;
4641  typedef typename STS::magnitudeType MT;
4642  typedef Teuchos::ScalarTraits<MT> STM;
4643  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4644 
4645  // Rank 0 is the only (MPI) process allowed to read from the
4646  // input stream.
4647  const int myRank = comm->getRank ();
4648 
4649  if (! err.is_null ()) {
4650  err->pushTab ();
4651  }
4652  if (debug) {
4653  *err << myRank << ": readVectorImpl" << endl;
4654  }
4655  if (! err.is_null ()) {
4656  err->pushTab ();
4657  }
4658 
4659  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4660  // instances be identical and that the Node instances be
4661  // identical. The essential condition is more complicated to
4662  // test and isn't the same for all Node types. Thus, we just
4663  // leave it up to the user.
4664 
4665  // // If map is nonnull, check the precondition that its
4666  // // communicator resp. node equal comm resp. node. Checking
4667  // // now avoids doing a lot of file reading before we detect the
4668  // // violated precondition.
4669  // TEUCHOS_TEST_FOR_EXCEPTION(
4670  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4671  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4672  // "communicator and node must equal the supplied communicator resp. "
4673  // "node.");
4674 
4675  // Process 0 will read in the matrix dimensions from the file,
4676  // and broadcast them to all ranks in the given communicator.
4677  // There are only 2 dimensions in the matrix, but we use the
4678  // third element of the Tuple to encode the banner's reported
4679  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4680  // (same as "real"). We don't allow pattern matrices (i.e.,
4681  // graphs) since they only make sense for sparse data.
4682  Tuple<GO, 3> dims;
4683  dims[0] = 0;
4684  dims[1] = 0;
4685 
4686  // Current line number in the input stream. Only valid on
4687  // Proc 0. Various calls will modify this depending on the
4688  // number of lines that are read from the input stream.
4689  size_t lineNumber = 1;
4690 
4691  // Capture errors and their messages on Proc 0.
4692  std::ostringstream exMsg;
4693  int localBannerReadSuccess = 1;
4694  int localDimsReadSuccess = 1;
4695 
4696  // Only Proc 0 gets to read matrix data from the input stream.
4697  if (myRank == 0) {
4698  if (debug) {
4699  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4700  }
4701 
4702  // The "Banner" tells you whether the input stream
4703  // represents a dense matrix, the symmetry type of the
4704  // matrix, and the type of the data it contains.
4705  RCP<const Banner> pBanner;
4706  try {
4707  pBanner = readBanner (in, lineNumber, tolerant, debug);
4708  } catch (std::exception& e) {
4709  exMsg << e.what ();
4710  localBannerReadSuccess = 0;
4711  }
4712  // Make sure the input stream is the right kind of data.
4713  if (localBannerReadSuccess) {
4714  if (pBanner->matrixType () != "array") {
4715  exMsg << "The Matrix Market file does not contain dense matrix "
4716  "data. Its banner (first) line says that its matrix type is \""
4717  << pBanner->matrixType () << "\", rather that the required "
4718  "\"array\".";
4719  localBannerReadSuccess = 0;
4720  } else if (pBanner->dataType() == "pattern") {
4721  exMsg << "The Matrix Market file's banner (first) "
4722  "line claims that the matrix's data type is \"pattern\". This does "
4723  "not make sense for a dense matrix, yet the file reports the matrix "
4724  "as dense. The only valid data types for a dense matrix are "
4725  "\"real\", \"complex\", and \"integer\".";
4726  localBannerReadSuccess = 0;
4727  } else {
4728  // Encode the data type reported by the Banner as the
4729  // third element of the dimensions Tuple.
4730  dims[2] = encodeDataType (pBanner->dataType ());
4731  }
4732  } // if we successfully read the banner line
4733 
4734  // At this point, we've successfully read the banner line.
4735  // Now read the dimensions line.
4736  if (localBannerReadSuccess) {
4737  if (debug) {
4738  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4739  }
4740  // Keep reading lines from the input stream until we find
4741  // a non-comment line, or until we run out of lines. The
4742  // latter is an error, since every "array" format Matrix
4743  // Market file must have a dimensions line after the
4744  // banner (even if the matrix has zero rows or columns, or
4745  // zero entries).
4746  std::string line;
4747  bool commentLine = true;
4748 
4749  while (commentLine) {
4750  // Test whether it is even valid to read from the input
4751  // stream wrapping the line.
4752  if (in.eof () || in.fail ()) {
4753  exMsg << "Unable to get array dimensions line (at all) from line "
4754  << lineNumber << " of input stream. The input stream "
4755  << "claims that it is "
4756  << (in.eof() ? "at end-of-file." : "in a failed state.");
4757  localDimsReadSuccess = 0;
4758  } else {
4759  // Try to get the next line from the input stream.
4760  if (getline (in, line)) {
4761  ++lineNumber; // We did actually read a line.
4762  }
4763  // Is the current line a comment line? Ignore start
4764  // and size; they are only useful for reading the
4765  // actual matrix entries. (We could use them here as
4766  // an optimization, but we've chosen not to.)
4767  size_t start = 0, size = 0;
4768  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4769  } // whether we failed to read the line at all
4770  } // while the line we just read is a comment line
4771 
4772  //
4773  // Get <numRows> <numCols> from the line we just read.
4774  //
4775  std::istringstream istr (line);
4776 
4777  // Test whether it is even valid to read from the input
4778  // stream wrapping the line.
4779  if (istr.eof () || istr.fail ()) {
4780  exMsg << "Unable to read any data from line " << lineNumber
4781  << " of input; the line should contain the matrix dimensions "
4782  << "\"<numRows> <numCols>\".";
4783  localDimsReadSuccess = 0;
4784  } else { // It's valid to read from the line.
4785  GO theNumRows = 0;
4786  istr >> theNumRows; // Read in the number of rows.
4787  if (istr.fail ()) {
4788  exMsg << "Failed to get number of rows from line "
4789  << lineNumber << " of input; the line should contains the "
4790  << "matrix dimensions \"<numRows> <numCols>\".";
4791  localDimsReadSuccess = 0;
4792  } else { // We successfully read the number of rows
4793  dims[0] = theNumRows; // Save the number of rows
4794  if (istr.eof ()) { // Do we still have data to read?
4795  exMsg << "No more data after number of rows on line "
4796  << lineNumber << " of input; the line should contain the "
4797  << "matrix dimensions \"<numRows> <numCols>\".";
4798  localDimsReadSuccess = 0;
4799  } else { // Still data left to read; read in number of columns.
4800  GO theNumCols = 0;
4801  istr >> theNumCols; // Read in the number of columns
4802  if (istr.fail ()) {
4803  exMsg << "Failed to get number of columns from line "
4804  << lineNumber << " of input; the line should contain "
4805  << "the matrix dimensions \"<numRows> <numCols>\".";
4806  localDimsReadSuccess = 0;
4807  } else { // We successfully read the number of columns
4808  dims[1] = theNumCols; // Save the number of columns
4809  } // if istr.fail ()
4810  } // if istr.eof ()
4811  } // if we read the number of rows
4812  } // if the input stream wrapping the dims line was (in)valid
4813  } // if we successfully read the banner line
4814  } // if (myRank == 0)
4815 
4816  // Check if file has a Vector
4817  if (dims[1]!=1) {
4818  exMsg << "File does not contain a 1D Vector";
4819  localDimsReadSuccess = 0;
4820  }
4821 
4822  // Broadcast the matrix dimensions, the encoded data type, and
4823  // whether or not Proc 0 succeeded in reading the banner and
4824  // dimensions.
4825  Tuple<GO, 5> bannerDimsReadResult;
4826  if (myRank == 0) {
4827  bannerDimsReadResult[0] = dims[0]; // numRows
4828  bannerDimsReadResult[1] = dims[1]; // numCols
4829  bannerDimsReadResult[2] = dims[2]; // encoded data type
4830  bannerDimsReadResult[3] = localBannerReadSuccess;
4831  bannerDimsReadResult[4] = localDimsReadSuccess;
4832  }
4833 
4834  // Broadcast matrix dimensions and the encoded data type from
4835  // Proc 0 to all the MPI processes.
4836  broadcast (*comm, 0, bannerDimsReadResult);
4837 
4838  TEUCHOS_TEST_FOR_EXCEPTION(
4839  bannerDimsReadResult[3] == 0, std::runtime_error,
4840  "Failed to read banner line: " << exMsg.str ());
4841  TEUCHOS_TEST_FOR_EXCEPTION(
4842  bannerDimsReadResult[4] == 0, std::runtime_error,
4843  "Failed to read matrix dimensions line: " << exMsg.str ());
4844  if (myRank != 0) {
4845  dims[0] = bannerDimsReadResult[0];
4846  dims[1] = bannerDimsReadResult[1];
4847  dims[2] = bannerDimsReadResult[2];
4848  }
4849 
4850  // Tpetra objects want the matrix dimensions in these types.
4851  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4852  const size_t numCols = static_cast<size_t> (dims[1]);
4853 
4854  // Make a "Proc 0 owns everything" Map that we will use to
4855  // read in the multivector entries in the correct order on
4856  // Proc 0. This must be a collective
4857  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4858  if (map.is_null ()) {
4859  // The user didn't supply a Map. Make a contiguous
4860  // distributed Map for them, using the read-in multivector
4861  // dimensions.
4862  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4863  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4864  // At this point, map exists and has a nonnull node.
4865  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4866  comm);
4867  }
4868  else { // The user supplied a Map.
4869  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4870  }
4871 
4872  // Make a multivector X owned entirely by Proc 0.
4873  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
4874 
4875  //
4876  // On Proc 0, read the Matrix Market data from the input
4877  // stream into the multivector X.
4878  //
4879  int localReadDataSuccess = 1;
4880  if (myRank == 0) {
4881  try {
4882  if (debug) {
4883  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
4884  << endl;
4885  }
4886 
4887  // Make sure that we can get a 1-D view of X.
4888  TEUCHOS_TEST_FOR_EXCEPTION(
4889  ! X->isConstantStride (), std::logic_error,
4890  "Can't get a 1-D view of the entries of the MultiVector X on "
4891  "Process 0, because the stride between the columns of X is not "
4892  "constant. This shouldn't happen because we just created X and "
4893  "haven't filled it in yet. Please report this bug to the Tpetra "
4894  "developers.");
4895 
4896  // Get a writeable 1-D view of the entries of X. Rank 0
4897  // owns all of them. The view will expire at the end of
4898  // scope, so (if necessary) it will be written back to X
4899  // at this time.
4900  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4901  TEUCHOS_TEST_FOR_EXCEPTION(
4902  as<global_size_t> (X_view.size ()) < numRows * numCols,
4903  std::logic_error,
4904  "The view of X has size " << X_view << " which is not enough to "
4905  "accommodate the expected number of entries numRows*numCols = "
4906  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4907  "Please report this bug to the Tpetra developers.");
4908  const size_t stride = X->getStride ();
4909 
4910  // The third element of the dimensions Tuple encodes the data
4911  // type reported by the Banner: "real" == 0, "complex" == 1,
4912  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4913  // allow dense matrices to be pattern matrices, so dims[2] ==
4914  // 0 or 1. We've already checked for this above.
4915  const bool isComplex = (dims[2] == 1);
4916  size_type count = 0, curRow = 0, curCol = 0;
4917 
4918  std::string line;
4919  while (getline (in, line)) {
4920  ++lineNumber;
4921  // Is the current line a comment line? If it's not,
4922  // line.substr(start,size) contains the data.
4923  size_t start = 0, size = 0;
4924  const bool commentLine =
4925  checkCommentLine (line, start, size, lineNumber, tolerant);
4926  if (! commentLine) {
4927  // Make sure we have room in which to put the new matrix
4928  // entry. We check this only after checking for a
4929  // comment line, because there may be one or more
4930  // comment lines at the end of the file. In tolerant
4931  // mode, we simply ignore any extra data.
4932  if (count >= X_view.size()) {
4933  if (tolerant) {
4934  break;
4935  }
4936  else {
4937  TEUCHOS_TEST_FOR_EXCEPTION(
4938  count >= X_view.size(),
4939  std::runtime_error,
4940  "The Matrix Market input stream has more data in it than "
4941  "its metadata reported. Current line number is "
4942  << lineNumber << ".");
4943  }
4944  }
4945 
4946  // mfh 19 Dec 2012: Ignore everything up to the initial
4947  // colon. writeDense() has the option to print out the
4948  // global row index in front of each entry, followed by
4949  // a colon and space.
4950  {
4951  const size_t pos = line.substr (start, size).find (':');
4952  if (pos != std::string::npos) {
4953  start = pos+1;
4954  }
4955  }
4956  std::istringstream istr (line.substr (start, size));
4957  // Does the line contain anything at all? Can we
4958  // safely read from the input stream wrapping the
4959  // line?
4960  if (istr.eof() || istr.fail()) {
4961  // In tolerant mode, simply ignore the line.
4962  if (tolerant) {
4963  break;
4964  }
4965  // We repeat the full test here so the exception
4966  // message is more informative.
4967  TEUCHOS_TEST_FOR_EXCEPTION(
4968  ! tolerant && (istr.eof() || istr.fail()),
4969  std::runtime_error,
4970  "Line " << lineNumber << " of the Matrix Market file is "
4971  "empty, or we cannot read from it for some other reason.");
4972  }
4973  // Current matrix entry to read in.
4974  ST val = STS::zero();
4975  // Real and imaginary parts of the current matrix entry.
4976  // The imaginary part is zero if the matrix is real-valued.
4977  MT real = STM::zero(), imag = STM::zero();
4978 
4979  // isComplex refers to the input stream's data, not to
4980  // the scalar type S. It's OK to read real-valued
4981  // data into a matrix storing complex-valued data; in
4982  // that case, all entries' imaginary parts are zero.
4983  if (isComplex) {
4984  // STS::real() and STS::imag() return a copy of
4985  // their respective components, not a writeable
4986  // reference. Otherwise we could just assign to
4987  // them using the istream extraction operator (>>).
4988  // That's why we have separate magnitude type "real"
4989  // and "imag" variables.
4990 
4991  // Attempt to read the real part of the current entry.
4992  istr >> real;
4993  if (istr.fail()) {
4994  TEUCHOS_TEST_FOR_EXCEPTION(
4995  ! tolerant && istr.eof(), std::runtime_error,
4996  "Failed to get the real part of a complex-valued matrix "
4997  "entry from line " << lineNumber << " of the Matrix Market "
4998  "file.");
4999  // In tolerant mode, just skip bad lines.
5000  if (tolerant) {
5001  break;
5002  }
5003  } else if (istr.eof()) {
5004  TEUCHOS_TEST_FOR_EXCEPTION(
5005  ! tolerant && istr.eof(), std::runtime_error,
5006  "Missing imaginary part of a complex-valued matrix entry "
5007  "on line " << lineNumber << " of the Matrix Market file.");
5008  // In tolerant mode, let any missing imaginary part be 0.
5009  } else {
5010  // Attempt to read the imaginary part of the current
5011  // matrix entry.
5012  istr >> imag;
5013  TEUCHOS_TEST_FOR_EXCEPTION(
5014  ! tolerant && istr.fail(), std::runtime_error,
5015  "Failed to get the imaginary part of a complex-valued "
5016  "matrix entry from line " << lineNumber << " of the "
5017  "Matrix Market file.");
5018  // In tolerant mode, let any missing or corrupted
5019  // imaginary part be 0.
5020  }
5021  } else { // Matrix Market file contains real-valued data.
5022  // Attempt to read the current matrix entry.
5023  istr >> real;
5024  TEUCHOS_TEST_FOR_EXCEPTION(
5025  ! tolerant && istr.fail(), std::runtime_error,
5026  "Failed to get a real-valued matrix entry from line "
5027  << lineNumber << " of the Matrix Market file.");
5028  // In tolerant mode, simply ignore the line if
5029  // we failed to read a matrix entry.
5030  if (istr.fail() && tolerant) {
5031  break;
5032  }
5033  }
5034  // In tolerant mode, we simply let pass through whatever
5035  // data we got.
5036  TEUCHOS_TEST_FOR_EXCEPTION(
5037  ! tolerant && istr.fail(), std::runtime_error,
5038  "Failed to read matrix data from line " << lineNumber
5039  << " of the Matrix Market file.");
5040 
5041  // Assign val = ST(real, imag).
5042  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5043 
5044  curRow = count % numRows;
5045  curCol = count / numRows;
5046  X_view[curRow + curCol*stride] = val;
5047  ++count;
5048  } // if not a comment line
5049  } // while there are still lines in the file, get the next one
5050 
5051  TEUCHOS_TEST_FOR_EXCEPTION(
5052  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5053  std::runtime_error,
5054  "The Matrix Market metadata reports that the dense matrix is "
5055  << numRows << " x " << numCols << ", and thus has "
5056  << numRows*numCols << " total entries, but we only found " << count
5057  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5058  } catch (std::exception& e) {
5059  exMsg << e.what ();
5060  localReadDataSuccess = 0;
5061  }
5062  } // if (myRank == 0)
5063 
5064  if (debug) {
5065  *err << myRank << ": readVectorImpl: done reading data" << endl;
5066  }
5067 
5068  // Synchronize on whether Proc 0 successfully read the data.
5069  int globalReadDataSuccess = localReadDataSuccess;
5070  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5071  TEUCHOS_TEST_FOR_EXCEPTION(
5072  globalReadDataSuccess == 0, std::runtime_error,
5073  "Failed to read the multivector's data: " << exMsg.str ());
5074 
5075  // If there's only one MPI process and the user didn't supply
5076  // a Map (i.e., pMap is null), we're done. Set pMap to the
5077  // Map used to distribute X, and return X.
5078  if (comm->getSize () == 1 && map.is_null ()) {
5079  map = proc0Map;
5080  if (! err.is_null ()) {
5081  err->popTab ();
5082  }
5083  if (debug) {
5084  *err << myRank << ": readVectorImpl: done" << endl;
5085  }
5086  if (! err.is_null ()) {
5087  err->popTab ();
5088  }
5089  return X;
5090  }
5091 
5092  if (debug) {
5093  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5094  }
5095 
5096  // Make a multivector Y with the distributed map pMap.
5097  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5098 
5099  if (debug) {
5100  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5101  }
5102 
5103  // Make an Export object that will export X to Y. First
5104  // argument is the source map, second argument is the target
5105  // map.
5106  Export<LO, GO, NT> exporter (proc0Map, map, err);
5107 
5108  if (debug) {
5109  *err << myRank << ": readVectorImpl: Exporting" << endl;
5110  }
5111  // Export X into Y.
5112  Y->doExport (*X, exporter, INSERT);
5113 
5114  if (! err.is_null ()) {
5115  err->popTab ();
5116  }
5117  if (debug) {
5118  *err << myRank << ": readVectorImpl: done" << endl;
5119  }
5120  if (! err.is_null ()) {
5121  err->popTab ();
5122  }
5123 
5124  // Y is distributed over all process(es) in the communicator.
5125  return Y;
5126  }
5127 
5128  public:
5149  static Teuchos::RCP<const map_type>
5150  readMap (std::istream& in,
5151  const trcp_tcomm_t& comm,
5152  const bool tolerant=false,
5153  const bool debug=false,
5154  const bool binary=false)
5155  {
5156  Teuchos::RCP<Teuchos::FancyOStream> err =
5157  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5158  return readMap (in, comm, err, tolerant, debug, binary);
5159  }
5160 
5161 
5188  static Teuchos::RCP<const map_type>
5189  readMap (std::istream& in,
5190  const trcp_tcomm_t& comm,
5191  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5192  const bool tolerant=false,
5193  const bool debug=false,
5194  const bool binary=false)
5195  {
5196  using Teuchos::arcp;
5197  using Teuchos::Array;
5198  using Teuchos::ArrayRCP;
5199  using Teuchos::as;
5200  using Teuchos::broadcast;
5201  using Teuchos::Comm;
5202  using Teuchos::CommRequest;
5203  using Teuchos::inOutArg;
5204  using Teuchos::ireceive;
5205  using Teuchos::outArg;
5206  using Teuchos::RCP;
5207  using Teuchos::receive;
5208  using Teuchos::reduceAll;
5209  using Teuchos::REDUCE_MIN;
5210  using Teuchos::isend;
5211  using Teuchos::SerialComm;
5212  using Teuchos::toString;
5213  using Teuchos::wait;
5214  using std::endl;
5215  typedef Tpetra::global_size_t GST;
5216  typedef ptrdiff_t int_type; // Can hold int and GO
5217  typedef local_ordinal_type LO;
5218  typedef global_ordinal_type GO;
5219  typedef node_type NT;
5221 
5222  const int numProcs = comm->getSize ();
5223  const int myRank = comm->getRank ();
5224 
5225  if (err.is_null ()) {
5226  err->pushTab ();
5227  }
5228  if (debug) {
5229  std::ostringstream os;
5230  os << myRank << ": readMap: " << endl;
5231  *err << os.str ();
5232  }
5233  if (err.is_null ()) {
5234  err->pushTab ();
5235  }
5236 
5237  // Tag for receive-size / send-size messages. writeMap used
5238  // tags 1337 and 1338; we count up from there.
5239  const int sizeTag = 1339;
5240  // Tag for receive-data / send-data messages.
5241  const int dataTag = 1340;
5242 
5243  // These are for sends on Process 0, and for receives on all
5244  // other processes. sizeReq is for the {receive,send}-size
5245  // message, and dataReq is for the message containing the
5246  // actual GIDs to belong to the receiving process.
5247  RCP<CommRequest<int> > sizeReq;
5248  RCP<CommRequest<int> > dataReq;
5249 
5250  // Each process will have to receive the number of GIDs to
5251  // expect. Thus, we can post the receives now, and cancel
5252  // them if something should go wrong in the meantime.
5253  ArrayRCP<int_type> numGidsToRecv (1);
5254  numGidsToRecv[0] = 0;
5255  if (myRank != 0) {
5256  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5257  }
5258 
5259  int readSuccess = 1;
5260  std::ostringstream exMsg;
5261  RCP<MV> data; // Will only be valid on Proc 0
5262  if (myRank == 0) {
5263  // If we want to reuse readDenseImpl, we have to make a
5264  // communicator that only contains Proc 0. Otherwise,
5265  // readDenseImpl will redistribute the data to all
5266  // processes. While we eventually want that, neither we nor
5267  // readDenseImpl know the correct Map to use at the moment.
5268  // That depends on the second column of the multivector.
5269  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5270  try {
5271  RCP<const map_type> dataMap;
5272  // This is currently the only place where we use the
5273  // 'tolerant' argument. Later, if we want to be clever,
5274  // we could have tolerant mode allow PIDs out of order.
5275  data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug, binary);
5276  (void) dataMap; // Silence "unused" warnings
5277  if (data.is_null ()) {
5278  readSuccess = 0;
5279  exMsg << "readDenseImpl() returned null." << endl;
5280  }
5281  } catch (std::exception& e) {
5282  readSuccess = 0;
5283  exMsg << e.what () << endl;
5284  }
5285  }
5286 
5287  // Map from PID to all the GIDs for that PID.
5288  // Only populated on Process 0.
5289  std::map<int, Array<GO> > pid2gids;
5290 
5291  // The index base must be the global minimum GID.
5292  // We will compute this on Process 0 and broadcast,
5293  // so that all processes can set up the Map.
5294  int_type globalNumGIDs = 0;
5295 
5296  // The index base must be the global minimum GID.
5297  // We will compute this on Process 0 and broadcast,
5298  // so that all processes can set up the Map.
5299  GO indexBase = 0;
5300 
5301  // Process 0: If the above read of the MultiVector succeeded,
5302  // extract the GIDs and PIDs into pid2gids, and find the
5303  // global min GID.
5304  if (myRank == 0 && readSuccess == 1) {
5305  if (data->getNumVectors () == 2) { // Map format 1.0
5306  ArrayRCP<const GO> GIDs = data->getData (0);
5307  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5308  globalNumGIDs = GIDs.size ();
5309 
5310  // Start computing the global min GID, while collecting
5311  // the GIDs for each PID.
5312  if (globalNumGIDs > 0) {
5313  const int pid = static_cast<int> (PIDs[0]);
5314 
5315  if (pid < 0 || pid >= numProcs) {
5316  readSuccess = 0;
5317  exMsg << "Tpetra::MatrixMarket::readMap: "
5318  << "Encountered invalid PID " << pid << "." << endl;
5319  }
5320  else {
5321  const GO gid = GIDs[0];
5322  pid2gids[pid].push_back (gid);
5323  indexBase = gid; // the current min GID
5324  }
5325  }
5326  if (readSuccess == 1) {
5327  // Collect the rest of the GIDs for each PID, and compute
5328  // the global min GID.
5329  for (size_type k = 1; k < globalNumGIDs; ++k) {
5330  const int pid = static_cast<int> (PIDs[k]);
5331  if (pid < 0 || pid >= numProcs) {
5332  readSuccess = 0;
5333  exMsg << "Tpetra::MatrixMarket::readMap: "
5334  << "Encountered invalid PID " << pid << "." << endl;
5335  }
5336  else {
5337  const int_type gid = GIDs[k];
5338  pid2gids[pid].push_back (gid);
5339  if (gid < indexBase) {
5340  indexBase = gid; // the current min GID
5341  }
5342  }
5343  }
5344  }
5345  }
5346  else if (data->getNumVectors () == 1) { // Map format 2.0
5347  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5348  readSuccess = 0;
5349  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5350  "wrong format (for Map format 2.0). The global number of rows "
5351  "in the MultiVector must be even (divisible by 2)." << endl;
5352  }
5353  else {
5354  ArrayRCP<const GO> theData = data->getData (0);
5355  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5356  static_cast<GO> (2);
5357 
5358  // Start computing the global min GID, while
5359  // collecting the GIDs for each PID.
5360  if (globalNumGIDs > 0) {
5361  const int pid = static_cast<int> (theData[1]);
5362  if (pid < 0 || pid >= numProcs) {
5363  readSuccess = 0;
5364  exMsg << "Tpetra::MatrixMarket::readMap: "
5365  << "Encountered invalid PID " << pid << "." << endl;
5366  }
5367  else {
5368  const GO gid = theData[0];
5369  pid2gids[pid].push_back (gid);
5370  indexBase = gid; // the current min GID
5371  }
5372  }
5373  // Collect the rest of the GIDs for each PID, and
5374  // compute the global min GID.
5375  for (int_type k = 1; k < globalNumGIDs; ++k) {
5376  const int pid = static_cast<int> (theData[2*k + 1]);
5377  if (pid < 0 || pid >= numProcs) {
5378  readSuccess = 0;
5379  exMsg << "Tpetra::MatrixMarket::readMap: "
5380  << "Encountered invalid PID " << pid << "." << endl;
5381  }
5382  else {
5383  const GO gid = theData[2*k];
5384  pid2gids[pid].push_back (gid);
5385  if (gid < indexBase) {
5386  indexBase = gid; // the current min GID
5387  }
5388  }
5389  } // for each GID
5390  } // if the amount of data is correct
5391  }
5392  else {
5393  readSuccess = 0;
5394  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5395  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5396  "the old Map format 1.0).";
5397  }
5398  } // myRank is zero
5399 
5400  // Broadcast the indexBase, the global number of GIDs, and the
5401  // current success status. Use int_type for all of these.
5402  {
5403  int_type readResults[3];
5404  readResults[0] = static_cast<int_type> (indexBase);
5405  readResults[1] = static_cast<int_type> (globalNumGIDs);
5406  readResults[2] = static_cast<int_type> (readSuccess);
5407  broadcast<int, int_type> (*comm, 0, 3, readResults);
5408 
5409  indexBase = static_cast<GO> (readResults[0]);
5410  globalNumGIDs = static_cast<int_type> (readResults[1]);
5411  readSuccess = static_cast<int> (readResults[2]);
5412  }
5413 
5414  // Unwinding the stack will invoke sizeReq's destructor, which
5415  // will cancel the receive-size request on all processes that
5416  // posted it.
5417  TEUCHOS_TEST_FOR_EXCEPTION(
5418  readSuccess != 1, std::runtime_error,
5419  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5420  "following exception message: " << exMsg.str ());
5421 
5422  if (myRank == 0) {
5423  // Proc 0: Send each process' number of GIDs to that process.
5424  for (int p = 1; p < numProcs; ++p) {
5425  ArrayRCP<int_type> numGidsToSend (1);
5426 
5427  auto it = pid2gids.find (p);
5428  if (it == pid2gids.end ()) {
5429  numGidsToSend[0] = 0;
5430  } else {
5431  numGidsToSend[0] = it->second.size ();
5432  }
5433  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5434  wait<int> (*comm, outArg (sizeReq));
5435  }
5436  }
5437  else {
5438  // Wait on the receive-size message to finish.
5439  wait<int> (*comm, outArg (sizeReq));
5440  }
5441 
5442  // Allocate / get the array for my GIDs.
5443  // Only Process 0 will have its actual GIDs at this point.
5444  ArrayRCP<GO> myGids;
5445  int_type myNumGids = 0;
5446  if (myRank == 0) {
5447  GO* myGidsRaw = NULL;
5448 
5449  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5450  if (it != pid2gids.end ()) {
5451  myGidsRaw = it->second.getRawPtr ();
5452  myNumGids = it->second.size ();
5453  // Nonowning ArrayRCP just views the Array.
5454  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5455  }
5456  }
5457  else { // myRank != 0
5458  myNumGids = numGidsToRecv[0];
5459  myGids = arcp<GO> (myNumGids);
5460  }
5461 
5462  if (myRank != 0) {
5463  // Post receive for data, now that we know how much data we
5464  // will receive. Only post receive if my process actually
5465  // has nonzero GIDs.
5466  if (myNumGids > 0) {
5467  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5468  }
5469  }
5470 
5471  for (int p = 1; p < numProcs; ++p) {
5472  if (myRank == 0) {
5473  ArrayRCP<GO> sendGids; // to send to Process p
5474  GO* sendGidsRaw = NULL;
5475  int_type numSendGids = 0;
5476 
5477  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5478  if (it != pid2gids.end ()) {
5479  numSendGids = it->second.size ();
5480  sendGidsRaw = it->second.getRawPtr ();
5481  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5482  }
5483  // Only send if that process actually has nonzero GIDs.
5484  if (numSendGids > 0) {
5485  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5486  }
5487  wait<int> (*comm, outArg (dataReq));
5488  }
5489  else if (myRank == p) {
5490  // Wait on my receive of GIDs to finish.
5491  wait<int> (*comm, outArg (dataReq));
5492  }
5493  } // for each process rank p in 1, 2, ..., numProcs-1
5494 
5495  if (debug) {
5496  std::ostringstream os;
5497  os << myRank << ": readMap: creating Map" << endl;
5498  *err << os.str ();
5499  }
5500  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5501  RCP<const map_type> newMap;
5502 
5503  // Create the Map; test whether the constructor threw. This
5504  // avoids deadlock and makes error reporting more readable.
5505 
5506  int lclSuccess = 1;
5507  int gblSuccess = 0; // output argument
5508  std::ostringstream errStrm;
5509  try {
5510  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5511  }
5512  catch (std::exception& e) {
5513  lclSuccess = 0;
5514  errStrm << "Process " << comm->getRank () << " threw an exception: "
5515  << e.what () << std::endl;
5516  }
5517  catch (...) {
5518  lclSuccess = 0;
5519  errStrm << "Process " << comm->getRank () << " threw an exception "
5520  "not a subclass of std::exception" << std::endl;
5521  }
5522  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5523  lclSuccess, Teuchos::outArg (gblSuccess));
5524  if (gblSuccess != 1) {
5525  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5526  }
5527  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5528 
5529  if (err.is_null ()) {
5530  err->popTab ();
5531  }
5532  if (debug) {
5533  std::ostringstream os;
5534  os << myRank << ": readMap: done" << endl;
5535  *err << os.str ();
5536  }
5537  if (err.is_null ()) {
5538  err->popTab ();
5539  }
5540  return newMap;
5541  }
5542 
5543 
5544  private:
5545 
5556  static int
5557  encodeDataType (const std::string& dataType)
5558  {
5559  if (dataType == "real" || dataType == "integer") {
5560  return 0;
5561  } else if (dataType == "complex") {
5562  return 1;
5563  } else if (dataType == "pattern") {
5564  return 2;
5565  } else {
5566  // We should never get here, since Banner validates the
5567  // reported data type and ensures it is one of the accepted
5568  // values.
5569  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5570  "Unrecognized Matrix Market data type \"" << dataType
5571  << "\". We should never get here. "
5572  "Please report this bug to the Tpetra developers.");
5573  }
5574  }
5575 
5576  public:
5577 
5607  static Teuchos::RCP<sparse_matrix_type>
5608  readSparsePerRank (const std::string& filename_prefix,
5609  const std::string& filename_suffix,
5610  const Teuchos::RCP<const map_type>& rowMap,
5611  Teuchos::RCP<const map_type>& colMap,
5612  const Teuchos::RCP<const map_type>& domainMap,
5613  const Teuchos::RCP<const map_type>& rangeMap,
5614  const bool callFillComplete=true,
5615  const bool tolerant=false,
5616  const int ranksToReadAtOnce=8,
5617  const bool debug=false)
5618  {
5619  using ST = scalar_type;
5620  using LO = local_ordinal_type;
5621  using GO = global_ordinal_type;
5622  using STS = typename Teuchos::ScalarTraits<ST>;
5623  using Teuchos::RCP;
5624  using Teuchos::ArrayRCP;
5625  using Teuchos::arcp;
5626  using Teuchos::rcp;
5627 
5628  // Sanity Checks
5629  // Fast checks for invalid input. We can't check other
5630  // attributes of the Maps until we've read in the matrix
5631  // dimensions.
5632  TEUCHOS_TEST_FOR_EXCEPTION(
5633  rowMap.is_null (), std::invalid_argument,
5634  "Row Map must be nonnull.");
5635  Teuchos::RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
5636  TEUCHOS_TEST_FOR_EXCEPTION
5637  (comm.is_null (), std::invalid_argument,
5638  "The input row map's communicator (Teuchos::Comm object) is null.");
5639  TEUCHOS_TEST_FOR_EXCEPTION(
5640  rangeMap.is_null (), std::invalid_argument,
5641  "Range Map must be nonnull.");
5642  TEUCHOS_TEST_FOR_EXCEPTION(
5643  domainMap.is_null (), std::invalid_argument,
5644  "Domain Map must be nonnull.");
5645  TEUCHOS_TEST_FOR_EXCEPTION(
5646  domainMap->getComm().getRawPtr() != comm.getRawPtr(),
5647  std::invalid_argument,
5648  "The specified domain Map's communicator (domainMap->getComm())"
5649  "differs from row Map's communicator");
5650  TEUCHOS_TEST_FOR_EXCEPTION(
5651  rangeMap->getComm().getRawPtr() != comm.getRawPtr(),
5652  std::invalid_argument,
5653  "The specified range Map's communicator (rangeMap->getComm())"
5654  "differs from row Map's communicator");
5655 
5656  // Setup
5657  const int myRank = comm->getRank();
5658  const int numProc = comm->getSize();
5659  std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
5660 
5661  // Bounds check the writing limits
5662  int rank_limit = std::min(std::max(ranksToReadAtOnce,1),numProc);
5663 
5664  // Data structures for constructor
5665  ArrayRCP<size_t> numEntriesPerRow;
5666  ArrayRCP<size_t> rowPtr;
5667  ArrayRCP<global_ordinal_type> colInd;
5668  ArrayRCP<scalar_type> values;
5669  std::ostringstream errMsg;
5670 
5672  // Start the reading of the banners to get
5673  // local row / nnz counts and then read the
5674  // data. We'll pack everything into big ol'
5675  // rowptr/colind/values ArrayRCPs
5676  bool success = true;
5677  int bannerIsCorrect = 1, readSuccess = 1;
5678  LO numRows, numCols, numNonzeros;
5679  for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
5680  int stop = std::min(base_rank+rank_limit,numProc);
5681 
5682  // Is my rank in this batch?
5683  if(base_rank <= myRank && myRank < stop) {
5684  // My turn to read
5685  std::ifstream in(filename);
5686  using Teuchos::MatrixMarket::Banner;
5687  size_t lineNumber = 1;
5688  RCP<const Banner> pBanner;
5689  try {
5690  pBanner = readBanner (in, lineNumber, tolerant, debug);
5691  }
5692  catch (std::exception& e) {
5693  errMsg << "Attempt to read the Matrix Market file's Banner line "
5694  "threw an exception: " << e.what();
5695  bannerIsCorrect = 0;
5696  }
5697  if (bannerIsCorrect) {
5698  // Validate the Banner for the case of a sparse matrix.
5699  // We validate on Proc 0, since it reads the Banner.
5700 
5701  // In intolerant mode, the matrix type must be "coordinate".
5702  if (! tolerant && pBanner->matrixType() != "coordinate") {
5703  bannerIsCorrect = 0;
5704  errMsg << "The Matrix Market input file must contain a "
5705  "\"coordinate\"-format sparse matrix in order to create a "
5706  "Tpetra::CrsMatrix object from it, but the file's matrix "
5707  "type is \"" << pBanner->matrixType() << "\" instead.";
5708  }
5709  // In tolerant mode, we allow the matrix type to be
5710  // anything other than "array" (which would mean that
5711  // the file contains a dense matrix).
5712  if (tolerant && pBanner->matrixType() == "array") {
5713  bannerIsCorrect = 0;
5714  errMsg << "Matrix Market file must contain a \"coordinate\"-"
5715  "format sparse matrix in order to create a Tpetra::CrsMatrix "
5716  "object from it, but the file's matrix type is \"array\" "
5717  "instead. That probably means the file contains dense matrix "
5718  "data.";
5719  }
5720  }
5721 
5722  // Unpacked coordinate matrix dimensions
5723  using Teuchos::MatrixMarket::readCoordinateDimensions;
5724  success = readCoordinateDimensions (in, numRows, numCols,
5725  numNonzeros, lineNumber,
5726  tolerant);
5727 
5728  // Sanity checking of headers
5729  TEUCHOS_TEST_FOR_EXCEPTION(numRows != (LO)rowMap->getLocalNumElements(), std::invalid_argument,
5730  "# rows in file does not match rowmap.");
5731  TEUCHOS_TEST_FOR_EXCEPTION(!colMap.is_null() && numCols != (LO)colMap->getLocalNumElements(), std::invalid_argument,
5732  "# rows in file does not match colmap.");
5733 
5734 
5735  // Read the data
5736  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,global_ordinal_type> raw_adder_type;
5737  bool tolerant_required = true;
5738  Teuchos::RCP<raw_adder_type> pRaw =
5739  Teuchos::rcp (new raw_adder_type (numRows,numCols,numNonzeros,tolerant_required,debug));
5740  RCP<adder_type> pAdder = Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
5741 
5742  if (debug) {
5743  std::cerr << "-- Reading matrix data" << std::endl;
5744  }
5745 
5746  try {
5747  // Reader for "coordinate" format sparse matrix data.
5748  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
5749  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
5750  reader_type reader (pAdder);
5751 
5752  // Read the sparse matrix entries.
5753  std::pair<bool, std::vector<size_t> > results = reader.read (in, lineNumber, tolerant_required, debug);
5754 
5755 
5756  readSuccess = results.first ? 1 : 0;
5757  }
5758  catch (std::exception& e) {
5759  readSuccess = 0;
5760  errMsg << e.what();
5761  }
5762 
5764  // Create the CSR Arrays
5765  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,global_ordinal_type> element_type;
5766 
5767  // Additively merge duplicate matrix entries.
5768  pAdder->getAdder()->merge ();
5769 
5770  // Get a temporary const view of the merged matrix entries.
5771  const std::vector<element_type>& entries = pAdder->getAdder()->getEntries();
5772 
5773  // Number of matrix entries (after merging).
5774  const size_t numEntries = (size_t)entries.size();
5775 
5776  if (debug) {
5777  std::cerr << "----- Proc "<<myRank<<": Matrix has numRows=" << numRows
5778  << " rows and numEntries=" << numEntries
5779  << " entries." << std::endl;
5780  }
5781 
5782 
5783  // Make space for the CSR matrix data. Converting to
5784  // CSR is easier if we fill numEntriesPerRow with zeros
5785  // at first.
5786  numEntriesPerRow = arcp<size_t> (numRows);
5787  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
5788  rowPtr = arcp<size_t> (numRows+1);
5789  std::fill (rowPtr.begin(), rowPtr.end(), 0);
5790  colInd = arcp<global_ordinal_type> (numEntries);
5791  values = arcp<scalar_type> (numEntries);
5792 
5793  // Convert from array-of-structs coordinate format to CSR
5794  // (compressed sparse row) format.
5795  global_ordinal_type l_prvRow = 0;
5796  size_t curPos = 0;
5797  LO INVALID = Teuchos::OrdinalTraits<LO>::invalid();
5798  rowPtr[0] = 0;
5799  LO indexBase = rowMap->getIndexBase();
5800  for (curPos = 0; curPos < numEntries; ++curPos) {
5801  const element_type& curEntry = entries[curPos];
5802  const global_ordinal_type curRow = curEntry.rowIndex() + indexBase;
5803  LO l_curRow = rowMap->getLocalElement(curRow);
5804 
5805 
5806  TEUCHOS_TEST_FOR_EXCEPTION(l_curRow == INVALID,std::logic_error,
5807  "Current global row "<< curRow << " is invalid.");
5808 
5809  TEUCHOS_TEST_FOR_EXCEPTION(l_curRow < l_prvRow, std::logic_error,
5810  "Row indices are out of order, even though they are supposed "
5811  "to be sorted. curRow = " << l_curRow << ", prvRow = "
5812  << l_prvRow << ", at curPos = " << curPos << ". Please report "
5813  "this bug to the Tpetra developers.");
5814  if (l_curRow > l_prvRow) {
5815  for (LO r = l_prvRow+1; r <= l_curRow; ++r) {
5816  rowPtr[r] = curPos;
5817  }
5818  l_prvRow = l_curRow;
5819  }
5820  numEntriesPerRow[l_curRow]++;
5821  colInd[curPos] = curEntry.colIndex() + indexBase;
5822  values[curPos] = curEntry.value();
5823 
5824  }
5825  // rowPtr has one more entry than numEntriesPerRow. The
5826  // last entry of rowPtr is the number of entries in
5827  // colInd and values.
5828  rowPtr[numRows] = numEntries;
5829 
5830  }// end base_rank <= myRank < stop
5831 
5832  // Barrier between batches to keep the filesystem happy
5833  comm->barrier();
5834 
5835  }//end outer rank loop
5836 
5837 
5838  // Call the matrix constructor and fill. This isn't particularly efficient
5839  RCP<sparse_matrix_type> A;
5840  if(colMap.is_null()) {
5841  A=rcp(new sparse_matrix_type(rowMap,numEntriesPerRow()));
5842  for(size_t i=0; i<rowMap->getLocalNumElements(); i++) {
5843  GO g_row = rowMap->getGlobalElement(i);
5844  size_t start = rowPtr[i];
5845  size_t size = rowPtr[i+1] - rowPtr[i];
5846  if(size>0) {
5847  A->insertGlobalValues(g_row,size,&values[start],&colInd[start]);
5848  }
5849  }
5850  }
5851  else {
5852  throw std::runtime_error("Reading with a column map is not yet implemented");
5853  }
5854  RCP<const map_type> myDomainMap = domainMap.is_null() ? rowMap : domainMap;
5855  RCP<const map_type> myRangeMap = rangeMap.is_null() ? rowMap : rangeMap;
5856 
5857  A->fillComplete(myDomainMap,myRangeMap);
5858 
5859  if(!readSuccess)
5860  success = false;
5861  TEUCHOS_TEST_FOR_EXCEPTION(success == false, std::runtime_error,
5862  "Read failed.");
5863 
5864  return A;
5865  }// end readSparsePerRank
5866 
5867 
5868  }; // class Reader
5869 
5898  template<class SparseMatrixType>
5899  class Writer {
5900  public:
5902  typedef SparseMatrixType sparse_matrix_type;
5903  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5904 
5906  typedef typename SparseMatrixType::scalar_type scalar_type;
5908  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5914  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5916  typedef typename SparseMatrixType::node_type node_type;
5917 
5919  typedef MultiVector<scalar_type,
5927 
5930 
5932  using trcp_tcomm_t = Teuchos::RCP<const Teuchos::Comm<int>>;
5933 
5965  static void
5966  writeSparseFile (const std::string& filename,
5967  const sparse_matrix_type& matrix,
5968  const std::string& matrixName,
5969  const std::string& matrixDescription,
5970  const bool debug=false)
5971  {
5972  trcp_tcomm_t comm = matrix.getComm ();
5973  TEUCHOS_TEST_FOR_EXCEPTION
5974  (comm.is_null (), std::invalid_argument,
5975  "The input matrix's communicator (Teuchos::Comm object) is null.");
5976  const int myRank = comm->getRank ();
5977 
5978  auto out = Writer::openOutFileOnRankZero(comm, filename, myRank, true);
5979 
5980  writeSparse (out, matrix, matrixName, matrixDescription, debug);
5981  // We can rely on the destructor of the output stream to close
5982  // the file on scope exit, even if writeSparse() throws an
5983  // exception.
5984  }
5985 
5987  static void
5988  writeSparseFile (const std::string& filename,
5989  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5990  const std::string& matrixName,
5991  const std::string& matrixDescription,
5992  const bool debug=false)
5993  {
5994  TEUCHOS_TEST_FOR_EXCEPTION
5995  (pMatrix.is_null (), std::invalid_argument,
5996  "The input matrix is null.");
5997  writeSparseFile (filename, *pMatrix, matrixName,
5998  matrixDescription, debug);
5999  }
6000 
6020  static void
6021  writeSparseFile (const std::string& filename,
6022  const sparse_matrix_type& matrix,
6023  const bool debug=false)
6024  {
6025  writeSparseFile (filename, matrix, "", "", debug);
6026  }
6027 
6029  static void
6030  writeSparseFile (const std::string& filename,
6031  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6032  const bool debug=false)
6033  {
6034  writeSparseFile (filename, *pMatrix, "", "", debug);
6035  }
6036 
6067  static void
6068  writeSparse (std::ostream& out,
6069  const sparse_matrix_type& matrix,
6070  const std::string& matrixName,
6071  const std::string& matrixDescription,
6072  const bool debug=false)
6073  {
6074  using Teuchos::ArrayView;
6075  using Teuchos::Comm;
6076  using Teuchos::FancyOStream;
6077  using Teuchos::getFancyOStream;
6078  using Teuchos::null;
6079  using Teuchos::RCP;
6080  using Teuchos::rcpFromRef;
6081  using std::cerr;
6082  using std::endl;
6083  using ST = scalar_type;
6084  using LO = local_ordinal_type;
6085  using GO = global_ordinal_type;
6086  using STS = typename Teuchos::ScalarTraits<ST>;
6087 
6088  // Make the output stream write floating-point numbers in
6089  // scientific notation. It will politely put the output
6090  // stream back to its state on input, when this scope
6091  // terminates.
6092  Teuchos::SetScientific<ST> sci (out);
6093 
6094  // Get the matrix's communicator.
6095  trcp_tcomm_t comm = matrix.getComm ();
6096  TEUCHOS_TEST_FOR_EXCEPTION(
6097  comm.is_null (), std::invalid_argument,
6098  "The input matrix's communicator (Teuchos::Comm object) is null.");
6099  const int myRank = comm->getRank ();
6100 
6101  // Optionally, make a stream for debugging output.
6102  RCP<FancyOStream> err =
6103  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6104  if (debug) {
6105  std::ostringstream os;
6106  os << myRank << ": writeSparse" << endl;
6107  *err << os.str ();
6108  comm->barrier ();
6109  os << "-- " << myRank << ": past barrier" << endl;
6110  *err << os.str ();
6111  }
6112 
6113  // Whether to print debugging output to stderr.
6114  const bool debugPrint = debug && myRank == 0;
6115 
6116  RCP<const map_type> rowMap = matrix.getRowMap ();
6117  RCP<const map_type> colMap = matrix.getColMap ();
6118  RCP<const map_type> domainMap = matrix.getDomainMap ();
6119  RCP<const map_type> rangeMap = matrix.getRangeMap ();
6120 
6121  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6122  const global_size_t numCols = domainMap->getGlobalNumElements ();
6123 
6124  if (debug && myRank == 0) {
6125  std::ostringstream os;
6126  os << "-- Input sparse matrix is:"
6127  << "---- " << numRows << " x " << numCols << endl
6128  << "---- "
6129  << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
6130  << " indexed." << endl
6131  << "---- Its row map has " << rowMap->getGlobalNumElements ()
6132  << " elements." << endl
6133  << "---- Its col map has " << colMap->getGlobalNumElements ()
6134  << " elements." << endl;
6135  *err << os.str ();
6136  }
6137  // Make the "gather" row map, where Proc 0 owns all rows and
6138  // the other procs own no rows.
6139  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6140  if (debug) {
6141  std::ostringstream os;
6142  os << "-- " << myRank << ": making gatherRowMap" << endl;
6143  *err << os.str ();
6144  }
6145  RCP<const map_type> gatherRowMap =
6146  Details::computeGatherMap (rowMap, err, debug);
6147 
6148  // Since the matrix may in general be non-square, we need to
6149  // make a column map as well. In this case, the column map
6150  // contains all the columns of the original matrix, because we
6151  // are gathering the whole matrix onto Proc 0. We call
6152  // computeGatherMap to preserve the original order of column
6153  // indices over all the processes.
6154  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6155  RCP<const map_type> gatherColMap =
6156  Details::computeGatherMap (colMap, err, debug);
6157 
6158  // Current map is the source map, gather map is the target map.
6159  typedef Import<LO, GO, node_type> import_type;
6160  import_type importer (rowMap, gatherRowMap);
6161 
6162  // Create a new CrsMatrix to hold the result of the import.
6163  // The constructor needs a column map as well as a row map,
6164  // for the case that the matrix is not square.
6165  RCP<sparse_matrix_type> newMatrix =
6166  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
6167  static_cast<size_t> (0)));
6168  // Import the sparse matrix onto Proc 0.
6169  newMatrix->doImport (matrix, importer, INSERT);
6170 
6171  // fillComplete() needs the domain and range maps for the case
6172  // that the matrix is not square.
6173  {
6174  RCP<const map_type> gatherDomainMap =
6175  rcp (new map_type (numCols, localNumCols,
6176  domainMap->getIndexBase (),
6177  comm));
6178  RCP<const map_type> gatherRangeMap =
6179  rcp (new map_type (numRows, localNumRows,
6180  rangeMap->getIndexBase (),
6181  comm));
6182  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
6183  }
6184 
6185  if (debugPrint) {
6186  cerr << "-- Output sparse matrix is:"
6187  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
6188  << " x "
6189  << newMatrix->getDomainMap ()->getGlobalNumElements ()
6190  << " with "
6191  << newMatrix->getGlobalNumEntries () << " entries;" << endl
6192  << "---- "
6193  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
6194  << " indexed." << endl
6195  << "---- Its row map has "
6196  << newMatrix->getRowMap ()->getGlobalNumElements ()
6197  << " elements, with index base "
6198  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
6199  << "---- Its col map has "
6200  << newMatrix->getColMap ()->getGlobalNumElements ()
6201  << " elements, with index base "
6202  << newMatrix->getColMap ()->getIndexBase () << "." << endl
6203  << "---- Element count of output matrix's column Map may differ "
6204  << "from that of the input matrix's column Map, if some columns "
6205  << "of the matrix contain no entries." << endl;
6206  }
6207 
6208  //
6209  // Print the metadata and the matrix entries on Rank 0.
6210  //
6211  if (myRank == 0) {
6212  // Print the Matrix Market banner line. CrsMatrix stores
6213  // data nonsymmetrically ("general"). This implies that
6214  // readSparse() on a symmetrically stored input file,
6215  // followed by writeSparse() on the resulting sparse matrix,
6216  // will result in an output file with a different banner
6217  // line than the original input file.
6218  out << "%%MatrixMarket matrix coordinate "
6219  << (STS::isComplex ? "complex" : "real")
6220  << " general" << endl;
6221 
6222  // Print comments (the matrix name and / or description).
6223  if (matrixName != "") {
6224  printAsComment (out, matrixName);
6225  }
6226  if (matrixDescription != "") {
6227  printAsComment (out, matrixDescription);
6228  }
6229 
6230  // Print the Matrix Market header (# rows, # columns, #
6231  // nonzeros). Use the range resp. domain map for the number
6232  // of rows resp. columns, since Tpetra::CrsMatrix uses the
6233  // column map for the number of columns. That only
6234  // corresponds to the "linear-algebraic" number of columns
6235  // when the column map is uniquely owned (a.k.a. one-to-one),
6236  // which only happens if the matrix is (block) diagonal.
6237  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
6238  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
6239  << newMatrix->getGlobalNumEntries () << endl;
6240 
6241  // The Matrix Market format expects one-based row and column
6242  // indices. We'll convert the indices on output from
6243  // whatever index base they use to one-based indices.
6244  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6245  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
6246  //
6247  // Print the entries of the matrix.
6248  //
6249  // newMatrix can never be globally indexed, since we called
6250  // fillComplete() on it. We include code for both cases
6251  // (globally or locally indexed) just in case that ever
6252  // changes.
6253  if (newMatrix->isGloballyIndexed()) {
6254  // We know that the "gather" row Map is contiguous, so we
6255  // don't need to get the list of GIDs.
6256  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6257  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6258  for (GO globalRowIndex = minAllGlobalIndex;
6259  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6260  ++globalRowIndex) {
6261  typename sparse_matrix_type::global_inds_host_view_type ind;
6262  typename sparse_matrix_type::values_host_view_type val;
6263  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6264  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6265  const GO globalColIndex = ind(ii);
6266  // Convert row and column indices to 1-based.
6267  // This works because the global index type is signed.
6268  out << (globalRowIndex + 1 - rowIndexBase) << " "
6269  << (globalColIndex + 1 - colIndexBase) << " ";
6270  if (STS::isComplex) {
6271  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6272  } else {
6273  out << val(ii);
6274  }
6275  out << endl;
6276  } // For each entry in the current row
6277  } // For each row of the "gather" matrix
6278  }
6279  else { // newMatrix is locally indexed
6280  using OTG = Teuchos::OrdinalTraits<GO>;
6281  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6282  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6283  ++localRowIndex) {
6284  // Convert from local to global row index.
6285  const GO globalRowIndex =
6286  gatherRowMap->getGlobalElement (localRowIndex);
6287  TEUCHOS_TEST_FOR_EXCEPTION(
6288  globalRowIndex == OTG::invalid(), std::logic_error,
6289  "Failed to convert the supposed local row index "
6290  << localRowIndex << " into a global row index. "
6291  "Please report this bug to the Tpetra developers.");
6292  typename sparse_matrix_type::local_inds_host_view_type ind;
6293  typename sparse_matrix_type::values_host_view_type val;
6294  newMatrix->getLocalRowView (localRowIndex, ind, val);
6295  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6296  // Convert the column index from local to global.
6297  const GO globalColIndex =
6298  newMatrix->getColMap()->getGlobalElement (ind(ii));
6299  TEUCHOS_TEST_FOR_EXCEPTION(
6300  globalColIndex == OTG::invalid(), std::logic_error,
6301  "On local row " << localRowIndex << " of the sparse matrix: "
6302  "Failed to convert the supposed local column index "
6303  << ind(ii) << " into a global column index. Please report "
6304  "this bug to the Tpetra developers.");
6305  // Convert row and column indices to 1-based.
6306  // This works because the global index type is signed.
6307  out << (globalRowIndex + 1 - rowIndexBase) << " "
6308  << (globalColIndex + 1 - colIndexBase) << " ";
6309  if (STS::isComplex) {
6310  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6311  } else {
6312  out << val(ii);
6313  }
6314  out << endl;
6315  } // For each entry in the current row
6316  } // For each row of the "gather" matrix
6317  } // Whether the "gather" matrix is locally or globally indexed
6318  } // If my process' rank is 0
6319  }
6320 
6322  static void
6323  writeSparse (std::ostream& out,
6324  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6325  const std::string& matrixName,
6326  const std::string& matrixDescription,
6327  const bool debug=false)
6328  {
6329  TEUCHOS_TEST_FOR_EXCEPTION
6330  (pMatrix.is_null (), std::invalid_argument,
6331  "The input matrix is null.");
6332  writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6333  }
6334 
6365  static void
6366  writeSparseGraph (std::ostream& out,
6367  const crs_graph_type& graph,
6368  const std::string& graphName,
6369  const std::string& graphDescription,
6370  const bool debug=false)
6371  {
6372  using Teuchos::ArrayView;
6373  using Teuchos::Comm;
6374  using Teuchos::FancyOStream;
6375  using Teuchos::getFancyOStream;
6376  using Teuchos::null;
6377  using Teuchos::RCP;
6378  using Teuchos::rcpFromRef;
6379  using std::cerr;
6380  using std::endl;
6381  typedef local_ordinal_type LO;
6382  typedef global_ordinal_type GO;
6383 
6384  // Get the graph's communicator. Processes on which the
6385  // graph's Map or communicator is null don't participate in
6386  // this operation. This function shouldn't even be called on
6387  // those processes.
6388  auto rowMap = graph.getRowMap ();
6389  if (rowMap.is_null ()) {
6390  return;
6391  }
6392  auto comm = rowMap->getComm ();
6393  if (comm.is_null ()) {
6394  return;
6395  }
6396  const int myRank = comm->getRank ();
6397 
6398  // Optionally, make a stream for debugging output.
6399  RCP<FancyOStream> err =
6400  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6401  if (debug) {
6402  std::ostringstream os;
6403  os << myRank << ": writeSparseGraph" << endl;
6404  *err << os.str ();
6405  comm->barrier ();
6406  os << "-- " << myRank << ": past barrier" << endl;
6407  *err << os.str ();
6408  }
6409 
6410  // Whether to print debugging output to stderr.
6411  const bool debugPrint = debug && myRank == 0;
6412 
6413  // We've already gotten the rowMap above.
6414  auto colMap = graph.getColMap ();
6415  auto domainMap = graph.getDomainMap ();
6416  auto rangeMap = graph.getRangeMap ();
6417 
6418  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6419  const global_size_t numCols = domainMap->getGlobalNumElements ();
6420 
6421  if (debug && myRank == 0) {
6422  std::ostringstream os;
6423  os << "-- Input sparse graph is:"
6424  << "---- " << numRows << " x " << numCols << " with "
6425  << graph.getGlobalNumEntries () << " entries;" << endl
6426  << "---- "
6427  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6428  << " indexed." << endl
6429  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6430  << " elements." << endl
6431  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6432  << " elements." << endl;
6433  *err << os.str ();
6434  }
6435  // Make the "gather" row map, where Proc 0 owns all rows and
6436  // the other procs own no rows.
6437  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6438  if (debug) {
6439  std::ostringstream os;
6440  os << "-- " << myRank << ": making gatherRowMap" << endl;
6441  *err << os.str ();
6442  }
6443  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6444 
6445  // Since the graph may in general be non-square, we need to
6446  // make a column map as well. In this case, the column map
6447  // contains all the columns of the original graph, because we
6448  // are gathering the whole graph onto Proc 0. We call
6449  // computeGatherMap to preserve the original order of column
6450  // indices over all the processes.
6451  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6452  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6453 
6454  // Current map is the source map, gather map is the target map.
6455  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6456 
6457  // Create a new CrsGraph to hold the result of the import.
6458  // The constructor needs a column map as well as a row map,
6459  // for the case that the graph is not square.
6460  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6461  static_cast<size_t> (0));
6462  // Import the sparse graph onto Proc 0.
6463  newGraph.doImport (graph, importer, INSERT);
6464 
6465  // fillComplete() needs the domain and range maps for the case
6466  // that the graph is not square.
6467  {
6468  RCP<const map_type> gatherDomainMap =
6469  rcp (new map_type (numCols, localNumCols,
6470  domainMap->getIndexBase (),
6471  comm));
6472  RCP<const map_type> gatherRangeMap =
6473  rcp (new map_type (numRows, localNumRows,
6474  rangeMap->getIndexBase (),
6475  comm));
6476  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6477  }
6478 
6479  if (debugPrint) {
6480  cerr << "-- Output sparse graph is:"
6481  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6482  << " x "
6483  << newGraph.getDomainMap ()->getGlobalNumElements ()
6484  << " with "
6485  << newGraph.getGlobalNumEntries () << " entries;" << endl
6486  << "---- "
6487  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6488  << " indexed." << endl
6489  << "---- Its row map has "
6490  << newGraph.getRowMap ()->getGlobalNumElements ()
6491  << " elements, with index base "
6492  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6493  << "---- Its col map has "
6494  << newGraph.getColMap ()->getGlobalNumElements ()
6495  << " elements, with index base "
6496  << newGraph.getColMap ()->getIndexBase () << "." << endl
6497  << "---- Element count of output graph's column Map may differ "
6498  << "from that of the input matrix's column Map, if some columns "
6499  << "of the matrix contain no entries." << endl;
6500  }
6501 
6502  //
6503  // Print the metadata and the graph entries on Process 0 of
6504  // the graph's communicator.
6505  //
6506  if (myRank == 0) {
6507  // Print the Matrix Market banner line. CrsGraph stores
6508  // data nonsymmetrically ("general"). This implies that
6509  // readSparseGraph() on a symmetrically stored input file,
6510  // followed by writeSparseGraph() on the resulting sparse
6511  // graph, will result in an output file with a different
6512  // banner line than the original input file.
6513  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6514 
6515  // Print comments (the graph name and / or description).
6516  if (graphName != "") {
6517  printAsComment (out, graphName);
6518  }
6519  if (graphDescription != "") {
6520  printAsComment (out, graphDescription);
6521  }
6522 
6523  // Print the Matrix Market header (# rows, # columns, #
6524  // stored entries). Use the range resp. domain map for the
6525  // number of rows resp. columns, since Tpetra::CrsGraph uses
6526  // the column map for the number of columns. That only
6527  // corresponds to the "linear-algebraic" number of columns
6528  // when the column map is uniquely owned
6529  // (a.k.a. one-to-one), which only happens if the graph is
6530  // block diagonal (one block per process).
6531  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6532  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6533  << newGraph.getGlobalNumEntries () << endl;
6534 
6535  // The Matrix Market format expects one-based row and column
6536  // indices. We'll convert the indices on output from
6537  // whatever index base they use to one-based indices.
6538  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6539  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6540  //
6541  // Print the entries of the graph.
6542  //
6543  // newGraph can never be globally indexed, since we called
6544  // fillComplete() on it. We include code for both cases
6545  // (globally or locally indexed) just in case that ever
6546  // changes.
6547  if (newGraph.isGloballyIndexed ()) {
6548  // We know that the "gather" row Map is contiguous, so we
6549  // don't need to get the list of GIDs.
6550  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6551  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6552  for (GO globalRowIndex = minAllGlobalIndex;
6553  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6554  ++globalRowIndex) {
6555  typename crs_graph_type::global_inds_host_view_type ind;
6556  newGraph.getGlobalRowView (globalRowIndex, ind);
6557  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6558  const GO globalColIndex = ind(ii);
6559  // Convert row and column indices to 1-based.
6560  // This works because the global index type is signed.
6561  out << (globalRowIndex + 1 - rowIndexBase) << " "
6562  << (globalColIndex + 1 - colIndexBase) << " ";
6563  out << endl;
6564  } // For each entry in the current row
6565  } // For each row of the "gather" graph
6566  }
6567  else { // newGraph is locally indexed
6568  typedef Teuchos::OrdinalTraits<GO> OTG;
6569  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6570  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6571  ++localRowIndex) {
6572  // Convert from local to global row index.
6573  const GO globalRowIndex =
6574  gatherRowMap->getGlobalElement (localRowIndex);
6575  TEUCHOS_TEST_FOR_EXCEPTION
6576  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6577  "to convert the supposed local row index " << localRowIndex <<
6578  " into a global row index. Please report this bug to the "
6579  "Tpetra developers.");
6580  typename crs_graph_type::local_inds_host_view_type ind;
6581  newGraph.getLocalRowView (localRowIndex, ind);
6582  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6583  // Convert the column index from local to global.
6584  const GO globalColIndex =
6585  newGraph.getColMap ()->getGlobalElement (ind(ii));
6586  TEUCHOS_TEST_FOR_EXCEPTION(
6587  globalColIndex == OTG::invalid(), std::logic_error,
6588  "On local row " << localRowIndex << " of the sparse graph: "
6589  "Failed to convert the supposed local column index "
6590  << ind(ii) << " into a global column index. Please report "
6591  "this bug to the Tpetra developers.");
6592  // Convert row and column indices to 1-based.
6593  // This works because the global index type is signed.
6594  out << (globalRowIndex + 1 - rowIndexBase) << " "
6595  << (globalColIndex + 1 - colIndexBase) << " ";
6596  out << endl;
6597  } // For each entry in the current row
6598  } // For each row of the "gather" graph
6599  } // Whether the "gather" graph is locally or globally indexed
6600  } // If my process' rank is 0
6601  }
6602 
6608  static void
6609  writeSparseGraph (std::ostream& out,
6610  const crs_graph_type& graph,
6611  const bool debug=false)
6612  {
6613  writeSparseGraph (out, graph, "", "", debug);
6614  }
6615 
6650  static void
6651  writeSparseGraphFile (const std::string& filename,
6652  const crs_graph_type& graph,
6653  const std::string& graphName,
6654  const std::string& graphDescription,
6655  const bool debug=false)
6656  {
6657  auto comm = graph.getComm ();
6658  if (comm.is_null ()) {
6659  // Processes on which the communicator is null shouldn't
6660  // even call this function. The convention is that
6661  // processes on which the object's communicator is null do
6662  // not participate in collective operations involving the
6663  // object.
6664  return;
6665  }
6666  const int myRank = comm->getRank ();
6667 
6668  auto out = Writer::openOutFileOnRankZero(comm, filename, myRank, true);
6669 
6670  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6671  // We can rely on the destructor of the output stream to close
6672  // the file on scope exit, even if writeSparseGraph() throws
6673  // an exception.
6674  }
6675 
6680  static void
6681  writeSparseGraphFile (const std::string& filename,
6682  const crs_graph_type& graph,
6683  const bool debug=false)
6684  {
6685  writeSparseGraphFile (filename, graph, "", "", debug);
6686  }
6687 
6696  static void
6697  writeSparseGraphFile (const std::string& filename,
6698  const Teuchos::RCP<const crs_graph_type>& pGraph,
6699  const std::string& graphName,
6700  const std::string& graphDescription,
6701  const bool debug=false)
6702  {
6703  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6704  }
6705 
6715  static void
6716  writeSparseGraphFile (const std::string& filename,
6717  const Teuchos::RCP<const crs_graph_type>& pGraph,
6718  const bool debug=false)
6719  {
6720  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6721  }
6722 
6745  static void
6746  writeSparse (std::ostream& out,
6747  const sparse_matrix_type& matrix,
6748  const bool debug=false)
6749  {
6750  writeSparse (out, matrix, "", "", debug);
6751  }
6752 
6754  static void
6755  writeSparse (std::ostream& out,
6756  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6757  const bool debug=false)
6758  {
6759  writeSparse (out, *pMatrix, "", "", debug);
6760  }
6761 
6790  static void
6791  writeDenseFile (const std::string& filename,
6792  const multivector_type& X,
6793  const std::string& matrixName,
6794  const std::string& matrixDescription,
6795  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6796  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6797  {
6798  trcp_tcomm_t comm = Writer::getComm(X.getMap());
6799  const int myRank = Writer::getRank(comm);
6800 
6801  auto out = Writer::openOutFileOnRankZero(comm, filename, myRank, true);
6802 
6803  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6804  // We can rely on the destructor of the output stream to close
6805  // the file on scope exit, even if writeDense() throws an
6806  // exception.
6807  }
6808 
6814  static void
6815  writeDenseFile (const std::string& filename,
6816  const Teuchos::RCP<const multivector_type>& X,
6817  const std::string& matrixName,
6818  const std::string& matrixDescription,
6819  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6820  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6821  {
6822  TEUCHOS_TEST_FOR_EXCEPTION(
6823  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6824  "writeDenseFile: The input MultiVector X is null.");
6825  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6826  }
6827 
6833  static void
6834  writeDenseFile (const std::string& filename,
6835  const multivector_type& X,
6836  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6837  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6838  {
6839  writeDenseFile (filename, X, "", "", err, dbg);
6840  }
6841 
6847  static void
6848  writeDenseFile (const std::string& filename,
6849  const Teuchos::RCP<const multivector_type>& X,
6850  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6851  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6852  {
6853  TEUCHOS_TEST_FOR_EXCEPTION(
6854  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6855  "writeDenseFile: The input MultiVector X is null.");
6856  writeDenseFile (filename, *X, err, dbg);
6857  }
6858 
6859 
6890  static void
6891  writeDense (std::ostream& out,
6892  const multivector_type& X,
6893  const std::string& matrixName,
6894  const std::string& matrixDescription,
6895  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6896  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6897  {
6898  using Teuchos::Comm;
6899  using Teuchos::outArg;
6900  using Teuchos::REDUCE_MAX;
6901  using Teuchos::reduceAll;
6902  using std::endl;
6903 
6904  trcp_tcomm_t comm = Writer::getComm(X.getMap());
6905  const int myRank = Writer::getRank(comm);
6906 
6907  // If the caller provides a nonnull debug output stream, we
6908  // print debugging output to it. This is a local thing; we
6909  // don't have to check across processes.
6910  const bool debug = ! dbg.is_null ();
6911  if (debug) {
6912  dbg->pushTab ();
6913  std::ostringstream os;
6914  os << myRank << ": writeDense" << endl;
6915  *dbg << os.str ();
6916  dbg->pushTab ();
6917  }
6918  // Print the Matrix Market header.
6919  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6920 
6921  // Print each column one at a time. This is a (perhaps)
6922  // temporary fix for Bug 6288.
6923  const size_t numVecs = X.getNumVectors ();
6924  for (size_t j = 0; j < numVecs; ++j) {
6925  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6926  }
6927 
6928  if (debug) {
6929  dbg->popTab ();
6930  std::ostringstream os;
6931  os << myRank << ": writeDense: Done" << endl;
6932  *dbg << os.str ();
6933  dbg->popTab ();
6934  }
6935  }
6936 
6937  private:
6943  static std::ofstream openOutFileOnRankZero(
6944  const trcp_tcomm_t& comm,
6945  const std::string& filename, const int rank, const bool safe = true,
6946  const std::ios_base::openmode mode = std::ios_base::out
6947  ){
6948  // Placeholder for the output stream.
6949  std::ofstream out;
6950 
6951  // State that will make all ranks throw if the root rank wasn't able to open the stream (using @c int for broadcasting).
6952  int all_should_stop = 0;
6953 
6954  // Try to open the file and update the state.
6955  if(rank == 0) {
6956  out.open(filename, mode);
6957  all_should_stop = !out && safe;
6958  }
6959 
6960  // Broadcast the stream state and throw from all ranks if needed.
6961  if(comm) Teuchos::broadcast(*comm, 0, &all_should_stop);
6962 
6963  TEUCHOS_TEST_FOR_EXCEPTION(
6964  all_should_stop,
6965  std::runtime_error,
6966  "Could not open output file '" + filename + "' on root rank 0."
6967  );
6968 
6969  return out;
6970  }
6971 
6997  static void
6998  writeDenseHeader (std::ostream& out,
6999  const multivector_type& X,
7000  const std::string& matrixName,
7001  const std::string& matrixDescription,
7002  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7003  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7004  {
7005  using Teuchos::Comm;
7006  using Teuchos::outArg;
7007  using Teuchos::RCP;
7008  using Teuchos::REDUCE_MAX;
7009  using Teuchos::reduceAll;
7010  using std::endl;
7011  typedef Teuchos::ScalarTraits<scalar_type> STS;
7012  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
7013 
7014  trcp_tcomm_t comm = Writer::getComm(X.getMap());
7015  const int myRank = Writer::getRank(comm);
7016  int lclErr = 0; // whether this MPI process has seen an error
7017  int gblErr = 0; // whether we know if some MPI process has seen an error
7018 
7019  // If the caller provides a nonnull debug output stream, we
7020  // print debugging output to it. This is a local thing; we
7021  // don't have to check across processes.
7022  const bool debug = ! dbg.is_null ();
7023 
7024  if (debug) {
7025  dbg->pushTab ();
7026  std::ostringstream os;
7027  os << myRank << ": writeDenseHeader" << endl;
7028  *dbg << os.str ();
7029  dbg->pushTab ();
7030  }
7031 
7032  //
7033  // Process 0: Write the MatrixMarket header.
7034  //
7035  if (myRank == 0) {
7036  try {
7037  // Print the Matrix Market header. MultiVector stores data
7038  // nonsymmetrically, hence "general" in the banner line.
7039  // Print first to a temporary string output stream, and then
7040  // write it to the main output stream, so that at least the
7041  // header output has transactional semantics. We can't
7042  // guarantee transactional semantics for the whole output,
7043  // since that would not be memory scalable. (This could be
7044  // done in the file system by using a temporary file; we
7045  // don't do this, but users could.)
7046  std::ostringstream hdr;
7047  {
7048  std::string dataType;
7049  if (STS::isComplex) {
7050  dataType = "complex";
7051  } else if (STS::isOrdinal) {
7052  dataType = "integer";
7053  } else {
7054  dataType = "real";
7055  }
7056  hdr << "%%MatrixMarket matrix array " << dataType << " general"
7057  << endl;
7058  }
7059 
7060  // Print comments (the matrix name and / or description).
7061  if (matrixName != "") {
7062  printAsComment (hdr, matrixName);
7063  }
7064  if (matrixDescription != "") {
7065  printAsComment (hdr, matrixDescription);
7066  }
7067  // Print the Matrix Market dimensions header for dense matrices.
7068  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
7069 
7070  // Write the MatrixMarket header to the output stream.
7071  out << hdr.str ();
7072  } catch (std::exception& e) {
7073  if (! err.is_null ()) {
7074  *err << prefix << "While writing the Matrix Market header, "
7075  "Process 0 threw an exception: " << e.what () << endl;
7076  }
7077  lclErr = 1;
7078  }
7079  } // if I am Process 0
7080 
7081  // Establish global agreement on the error state. It wouldn't
7082  // be good for other processes to keep going, if Process 0
7083  // finds out that it can't write to the given output stream.
7084  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
7085  TEUCHOS_TEST_FOR_EXCEPTION(
7086  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
7087  "which prevented this method from completing.");
7088 
7089  if (debug) {
7090  dbg->popTab ();
7091  *dbg << myRank << ": writeDenseHeader: Done" << endl;
7092  dbg->popTab ();
7093  }
7094  }
7095 
7113  static void
7114  writeDenseColumn (std::ostream& out,
7115  const multivector_type& X,
7116  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7117  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7118  {
7119  using Teuchos::arcp;
7120  using Teuchos::Array;
7121  using Teuchos::ArrayRCP;
7122  using Teuchos::ArrayView;
7123  using Teuchos::Comm;
7124  using Teuchos::CommRequest;
7125  using Teuchos::ireceive;
7126  using Teuchos::isend;
7127  using Teuchos::outArg;
7128  using Teuchos::REDUCE_MAX;
7129  using Teuchos::reduceAll;
7130  using Teuchos::RCP;
7131  using Teuchos::TypeNameTraits;
7132  using Teuchos::wait;
7133  using std::endl;
7134  typedef Teuchos::ScalarTraits<scalar_type> STS;
7135 
7136  const Comm<int>& comm = * (X.getMap ()->getComm ());
7137  const int myRank = comm.getRank ();
7138  const int numProcs = comm.getSize ();
7139  int lclErr = 0; // whether this MPI process has seen an error
7140  int gblErr = 0; // whether we know if some MPI process has seen an error
7141 
7142  // If the caller provides a nonnull debug output stream, we
7143  // print debugging output to it. This is a local thing; we
7144  // don't have to check across processes.
7145  const bool debug = ! dbg.is_null ();
7146 
7147  if (debug) {
7148  dbg->pushTab ();
7149  std::ostringstream os;
7150  os << myRank << ": writeDenseColumn" << endl;
7151  *dbg << os.str ();
7152  dbg->pushTab ();
7153  }
7154 
7155  // Make the output stream write floating-point numbers in
7156  // scientific notation. It will politely put the output
7157  // stream back to its state on input, when this scope
7158  // terminates.
7159  Teuchos::SetScientific<scalar_type> sci (out);
7160 
7161  const size_t myNumRows = X.getLocalLength ();
7162  const size_t numCols = X.getNumVectors ();
7163  // Use a different tag for the "size" messages than for the
7164  // "data" messages, in order to help us debug any mix-ups.
7165  const int sizeTag = 1337;
7166  const int dataTag = 1338;
7167 
7168  // Process 0 pipelines nonblocking receives with file output.
7169  //
7170  // Constraints:
7171  // - Process 0 can't post a receive for another process'
7172  // actual data, until it posts and waits on the receive
7173  // from that process with the amount of data to receive.
7174  // (We could just post receives with a max data size, but
7175  // I feel uncomfortable about that.)
7176  // - The C++ standard library doesn't allow nonblocking
7177  // output to an std::ostream. (Thus, we have to start a
7178  // receive or send before starting the write, and hope
7179  // that MPI completes it in the background.)
7180  //
7181  // Process 0: Post receive-size receives from Processes 1 and 2.
7182  // Process 1: Post send-size send to Process 0.
7183  // Process 2: Post send-size send to Process 0.
7184  //
7185  // All processes: Pack my entries.
7186  //
7187  // Process 1:
7188  // - Post send-data send to Process 0.
7189  // - Wait on my send-size send to Process 0.
7190  //
7191  // Process 0:
7192  // - Print MatrixMarket header.
7193  // - Print my entries.
7194  // - Wait on receive-size receive from Process 1.
7195  // - Post receive-data receive from Process 1.
7196  //
7197  // For each process p = 1, 2, ... numProcs-1:
7198  // If I am Process 0:
7199  // - Post receive-size receive from Process p + 2
7200  // - Wait on receive-size receive from Process p + 1
7201  // - Post receive-data receive from Process p + 1
7202  // - Wait on receive-data receive from Process p
7203  // - Write data from Process p.
7204  // Else if I am Process p:
7205  // - Wait on my send-data send.
7206  // Else if I am Process p+1:
7207  // - Post send-data send to Process 0.
7208  // - Wait on my send-size send.
7209  // Else if I am Process p+2:
7210  // - Post send-size send to Process 0.
7211  //
7212  // Pipelining has three goals here:
7213  // 1. Overlap communication (the receives) with file I/O
7214  // 2. Give Process 0 a chance to prepost some receives,
7215  // before sends show up, by packing local data before
7216  // posting sends
7217  // 3. Don't post _all_ receives or _all_ sends, because that
7218  // wouldn't be memory scalable. (Just because we can't
7219  // see how much memory MPI consumes, doesn't mean that it
7220  // doesn't consume any!)
7221 
7222  // These are used on every process. sendReqSize[0] holds the
7223  // number of rows on this process, and sendReqBuf holds this
7224  // process' data. Process 0 packs into sendReqBuf, but
7225  // doesn't send; it only uses that for printing. All other
7226  // processes send both of these to Process 0.
7227  RCP<CommRequest<int> > sendReqSize, sendReqData;
7228 
7229  // These are used only on Process 0, for received data. Keep
7230  // 3 of each, and treat the arrays as circular buffers. When
7231  // receiving from Process p, the corresponding array index
7232  // here is p % 3.
7233  Array<ArrayRCP<size_t> > recvSizeBufs (3);
7234  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
7235  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7236  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7237 
7238  // Buffer for nonblocking send of the "send size."
7239  ArrayRCP<size_t> sendDataSize (1);
7240  sendDataSize[0] = myNumRows;
7241 
7242  if (myRank == 0) {
7243  if (debug) {
7244  std::ostringstream os;
7245  os << myRank << ": Post receive-size receives from "
7246  "Procs 1 and 2: tag = " << sizeTag << endl;
7247  *dbg << os.str ();
7248  }
7249  // Process 0: Post receive-size receives from Processes 1 and 2.
7250  recvSizeBufs[0].resize (1);
7251  // Set these three to an invalid value as a flag. If we
7252  // don't get these messages, then the invalid value will
7253  // remain, so we can test for it.
7254  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7255  recvSizeBufs[1].resize (1);
7256  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7257  recvSizeBufs[2].resize (1);
7258  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7259  if (numProcs > 1) {
7260  recvSizeReqs[1] =
7261  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
7262  }
7263  if (numProcs > 2) {
7264  recvSizeReqs[2] =
7265  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
7266  }
7267  }
7268  else if (myRank == 1 || myRank == 2) {
7269  if (debug) {
7270  std::ostringstream os;
7271  os << myRank << ": Post send-size send: size = "
7272  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7273  *dbg << os.str ();
7274  }
7275  // Prime the pipeline by having Processes 1 and 2 start
7276  // their send-size sends. We don't want _all_ the processes
7277  // to start their send-size sends, because that wouldn't be
7278  // memory scalable.
7279  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7280  }
7281  else {
7282  if (debug) {
7283  std::ostringstream os;
7284  os << myRank << ": Not posting my send-size send yet" << endl;
7285  *dbg << os.str ();
7286  }
7287  }
7288 
7289  //
7290  // Pack my entries, in column-major order.
7291  //
7292  if (debug) {
7293  std::ostringstream os;
7294  os << myRank << ": Pack my entries" << endl;
7295  *dbg << os.str ();
7296  }
7297  ArrayRCP<scalar_type> sendDataBuf;
7298  try {
7299  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7300  X.get1dCopy (sendDataBuf (), myNumRows);
7301  }
7302  catch (std::exception& e) {
7303  lclErr = 1;
7304  if (! err.is_null ()) {
7305  std::ostringstream os;
7306  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7307  "entries threw an exception: " << e.what () << endl;
7308  *err << os.str ();
7309  }
7310  }
7311  if (debug) {
7312  std::ostringstream os;
7313  os << myRank << ": Done packing my entries" << endl;
7314  *dbg << os.str ();
7315  }
7316 
7317  //
7318  // Process 1: post send-data send to Process 0.
7319  //
7320  if (myRank == 1) {
7321  if (debug) {
7322  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7323  << endl;
7324  }
7325  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7326  }
7327 
7328  //
7329  // Process 0: Write my entries.
7330  //
7331  if (myRank == 0) {
7332  if (debug) {
7333  std::ostringstream os;
7334  os << myRank << ": Write my entries" << endl;
7335  *dbg << os.str ();
7336  }
7337 
7338  // Write Process 0's data to the output stream.
7339  // Matrix Market prints dense matrices in column-major order.
7340  const size_t printNumRows = myNumRows;
7341  ArrayView<const scalar_type> printData = sendDataBuf ();
7342  const size_t printStride = printNumRows;
7343  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7344  lclErr = 1;
7345  if (! err.is_null ()) {
7346  std::ostringstream os;
7347  os << "Process " << myRank << ": My MultiVector data's size "
7348  << printData.size () << " does not match my local dimensions "
7349  << printStride << " x " << numCols << "." << endl;
7350  *err << os.str ();
7351  }
7352  }
7353  else {
7354  // Matrix Market dense format wants one number per line.
7355  // It wants each complex number as two real numbers (real
7356  // resp. imaginary parts) with a space between.
7357  for (size_t col = 0; col < numCols; ++col) {
7358  for (size_t row = 0; row < printNumRows; ++row) {
7359  if (STS::isComplex) {
7360  out << STS::real (printData[row + col * printStride]) << " "
7361  << STS::imag (printData[row + col * printStride]) << endl;
7362  } else {
7363  out << printData[row + col * printStride] << endl;
7364  }
7365  }
7366  }
7367  }
7368  }
7369 
7370  if (myRank == 0) {
7371  // Wait on receive-size receive from Process 1.
7372  const int recvRank = 1;
7373  const int circBufInd = recvRank % 3;
7374  if (debug) {
7375  std::ostringstream os;
7376  os << myRank << ": Wait on receive-size receive from Process "
7377  << recvRank << endl;
7378  *dbg << os.str ();
7379  }
7380  if (numProcs > 1) {
7381  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7382 
7383  // We received the number of rows of data. (The data
7384  // come in two columns.)
7385  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7386  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7387  lclErr = 1;
7388  if (! err.is_null ()) {
7389  std::ostringstream os;
7390  os << myRank << ": Result of receive-size receive from Process "
7391  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7392  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7393  "This should never happen, and suggests that the receive never "
7394  "got posted. Please report this bug to the Tpetra developers."
7395  << endl;
7396  *err << os.str ();
7397  }
7398 
7399  // If we're going to continue after error, set the
7400  // number of rows to receive to a reasonable size. This
7401  // may cause MPI_ERR_TRUNCATE if the sending process is
7402  // sending more than 0 rows, but that's better than MPI
7403  // overflowing due to the huge positive value that is
7404  // Teuchos::OrdinalTraits<size_t>::invalid().
7405  recvNumRows = 0;
7406  }
7407 
7408  // Post receive-data receive from Process 1.
7409  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7410  if (debug) {
7411  std::ostringstream os;
7412  os << myRank << ": Post receive-data receive from Process "
7413  << recvRank << ": tag = " << dataTag << ", buffer size = "
7414  << recvDataBufs[circBufInd].size () << endl;
7415  *dbg << os.str ();
7416  }
7417  if (! recvSizeReqs[circBufInd].is_null ()) {
7418  lclErr = 1;
7419  if (! err.is_null ()) {
7420  std::ostringstream os;
7421  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7422  "null, before posting the receive-data receive from Process "
7423  << recvRank << ". This should never happen. Please report "
7424  "this bug to the Tpetra developers." << endl;
7425  *err << os.str ();
7426  }
7427  }
7428  recvDataReqs[circBufInd] =
7429  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7430  recvRank, dataTag, comm);
7431  } // numProcs > 1
7432  }
7433  else if (myRank == 1) {
7434  // Wait on my send-size send.
7435  if (debug) {
7436  std::ostringstream os;
7437  os << myRank << ": Wait on my send-size send" << endl;
7438  *dbg << os.str ();
7439  }
7440  wait<int> (comm, outArg (sendReqSize));
7441  }
7442 
7443  //
7444  // Pipeline loop
7445  //
7446  for (int p = 1; p < numProcs; ++p) {
7447  if (myRank == 0) {
7448  if (p + 2 < numProcs) {
7449  // Post receive-size receive from Process p + 2.
7450  const int recvRank = p + 2;
7451  const int circBufInd = recvRank % 3;
7452  if (debug) {
7453  std::ostringstream os;
7454  os << myRank << ": Post receive-size receive from Process "
7455  << recvRank << ": tag = " << sizeTag << endl;
7456  *dbg << os.str ();
7457  }
7458  if (! recvSizeReqs[circBufInd].is_null ()) {
7459  lclErr = 1;
7460  if (! err.is_null ()) {
7461  std::ostringstream os;
7462  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7463  << "null, for the receive-size receive from Process "
7464  << recvRank << "! This may mean that this process never "
7465  << "finished waiting for the receive from Process "
7466  << (recvRank - 3) << "." << endl;
7467  *err << os.str ();
7468  }
7469  }
7470  recvSizeReqs[circBufInd] =
7471  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7472  recvRank, sizeTag, comm);
7473  }
7474 
7475  if (p + 1 < numProcs) {
7476  const int recvRank = p + 1;
7477  const int circBufInd = recvRank % 3;
7478 
7479  // Wait on receive-size receive from Process p + 1.
7480  if (debug) {
7481  std::ostringstream os;
7482  os << myRank << ": Wait on receive-size receive from Process "
7483  << recvRank << endl;
7484  *dbg << os.str ();
7485  }
7486  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7487 
7488  // We received the number of rows of data. (The data
7489  // come in two columns.)
7490  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7491  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7492  lclErr = 1;
7493  if (! err.is_null ()) {
7494  std::ostringstream os;
7495  os << myRank << ": Result of receive-size receive from Process "
7496  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7497  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7498  "This should never happen, and suggests that the receive never "
7499  "got posted. Please report this bug to the Tpetra developers."
7500  << endl;
7501  *err << os.str ();
7502  }
7503  // If we're going to continue after error, set the
7504  // number of rows to receive to a reasonable size.
7505  // This may cause MPI_ERR_TRUNCATE if the sending
7506  // process sends more than 0 rows, but that's better
7507  // than MPI overflowing due to the huge positive value
7508  // Teuchos::OrdinalTraits<size_t>::invalid().
7509  recvNumRows = 0;
7510  }
7511 
7512  // Post receive-data receive from Process p + 1.
7513  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7514  if (debug) {
7515  std::ostringstream os;
7516  os << myRank << ": Post receive-data receive from Process "
7517  << recvRank << ": tag = " << dataTag << ", buffer size = "
7518  << recvDataBufs[circBufInd].size () << endl;
7519  *dbg << os.str ();
7520  }
7521  if (! recvDataReqs[circBufInd].is_null ()) {
7522  lclErr = 1;
7523  if (! err.is_null ()) {
7524  std::ostringstream os;
7525  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7526  << "null, for the receive-data receive from Process "
7527  << recvRank << "! This may mean that this process never "
7528  << "finished waiting for the receive from Process "
7529  << (recvRank - 3) << "." << endl;
7530  *err << os.str ();
7531  }
7532  }
7533  recvDataReqs[circBufInd] =
7534  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7535  recvRank, dataTag, comm);
7536  }
7537 
7538  // Wait on receive-data receive from Process p.
7539  const int recvRank = p;
7540  const int circBufInd = recvRank % 3;
7541  if (debug) {
7542  std::ostringstream os;
7543  os << myRank << ": Wait on receive-data receive from Process "
7544  << recvRank << endl;
7545  *dbg << os.str ();
7546  }
7547  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7548 
7549  // Write Process p's data. Number of rows lives in
7550  // recvSizeBufs[circBufInd], and the actual data live in
7551  // recvDataBufs[circBufInd]. Do this after posting receives,
7552  // in order to expose overlap of comm. with file I/O.
7553  if (debug) {
7554  std::ostringstream os;
7555  os << myRank << ": Write entries from Process " << recvRank
7556  << endl;
7557  *dbg << os.str () << endl;
7558  }
7559  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7560  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7561  lclErr = 1;
7562  if (! err.is_null ()) {
7563  std::ostringstream os;
7564  os << myRank << ": Result of receive-size receive from Process "
7565  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7566  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7567  << ". This should never happen, and suggests that its "
7568  "receive-size receive was never posted. "
7569  "Please report this bug to the Tpetra developers." << endl;
7570  *err << os.str ();
7571  }
7572  // If we're going to continue after error, set the
7573  // number of rows to print to a reasonable size.
7574  printNumRows = 0;
7575  }
7576  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7577  lclErr = 1;
7578  if (! err.is_null ()) {
7579  std::ostringstream os;
7580  os << myRank << ": Result of receive-size receive from Proc "
7581  << recvRank << " was " << printNumRows << " > 0, but "
7582  "recvDataBufs[" << circBufInd << "] is null. This should "
7583  "never happen. Please report this bug to the Tpetra "
7584  "developers." << endl;
7585  *err << os.str ();
7586  }
7587  // If we're going to continue after error, set the
7588  // number of rows to print to a reasonable size.
7589  printNumRows = 0;
7590  }
7591 
7592  // Write the received data to the output stream.
7593  // Matrix Market prints dense matrices in column-major order.
7594  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7595  const size_t printStride = printNumRows;
7596  // Matrix Market dense format wants one number per line.
7597  // It wants each complex number as two real numbers (real
7598  // resp. imaginary parts) with a space between.
7599  for (size_t col = 0; col < numCols; ++col) {
7600  for (size_t row = 0; row < printNumRows; ++row) {
7601  if (STS::isComplex) {
7602  out << STS::real (printData[row + col * printStride]) << " "
7603  << STS::imag (printData[row + col * printStride]) << endl;
7604  } else {
7605  out << printData[row + col * printStride] << endl;
7606  }
7607  }
7608  }
7609  }
7610  else if (myRank == p) { // Process p
7611  // Wait on my send-data send.
7612  if (debug) {
7613  std::ostringstream os;
7614  os << myRank << ": Wait on my send-data send" << endl;
7615  *dbg << os.str ();
7616  }
7617  wait<int> (comm, outArg (sendReqData));
7618  }
7619  else if (myRank == p + 1) { // Process p + 1
7620  // Post send-data send to Process 0.
7621  if (debug) {
7622  std::ostringstream os;
7623  os << myRank << ": Post send-data send: tag = " << dataTag
7624  << endl;
7625  *dbg << os.str ();
7626  }
7627  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7628  // Wait on my send-size send.
7629  if (debug) {
7630  std::ostringstream os;
7631  os << myRank << ": Wait on my send-size send" << endl;
7632  *dbg << os.str ();
7633  }
7634  wait<int> (comm, outArg (sendReqSize));
7635  }
7636  else if (myRank == p + 2) { // Process p + 2
7637  // Post send-size send to Process 0.
7638  if (debug) {
7639  std::ostringstream os;
7640  os << myRank << ": Post send-size send: size = "
7641  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7642  *dbg << os.str ();
7643  }
7644  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7645  }
7646  }
7647 
7648  // Establish global agreement on the error state.
7649  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7650  TEUCHOS_TEST_FOR_EXCEPTION(
7651  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7652  "experienced some kind of error and was unable to complete.");
7653 
7654  if (debug) {
7655  dbg->popTab ();
7656  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7657  dbg->popTab ();
7658  }
7659  }
7660 
7661  public:
7662 
7668  static void
7669  writeDense (std::ostream& out,
7670  const Teuchos::RCP<const multivector_type>& X,
7671  const std::string& matrixName,
7672  const std::string& matrixDescription,
7673  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7674  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7675  {
7676  TEUCHOS_TEST_FOR_EXCEPTION(
7677  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7678  "writeDense: The input MultiVector X is null.");
7679  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7680  }
7681 
7687  static void
7688  writeDense (std::ostream& out,
7689  const multivector_type& X,
7690  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7691  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7692  {
7693  writeDense (out, X, "", "", err, dbg);
7694  }
7695 
7701  static void
7702  writeDense (std::ostream& out,
7703  const Teuchos::RCP<const multivector_type>& X,
7704  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7705  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7706  {
7707  TEUCHOS_TEST_FOR_EXCEPTION(
7708  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7709  "writeDense: The input MultiVector X is null.");
7710  writeDense (out, *X, "", "", err, dbg);
7711  }
7712 
7732  static void
7733  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7734  {
7735  Teuchos::RCP<Teuchos::FancyOStream> err =
7736  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7737  writeMap (out, map, err, debug);
7738  }
7739 
7748  static void
7749  writeMap (std::ostream& out,
7750  const map_type& map,
7751  const Teuchos::RCP<Teuchos::FancyOStream>& err,
7752  const bool debug=false)
7753  {
7754  using Teuchos::Array;
7755  using Teuchos::ArrayRCP;
7756  using Teuchos::ArrayView;
7757  using Teuchos::Comm;
7758  using Teuchos::CommRequest;
7759  using Teuchos::ireceive;
7760  using Teuchos::isend;
7761  using Teuchos::RCP;
7762  using Teuchos::TypeNameTraits;
7763  using Teuchos::wait;
7764  using std::endl;
7765  typedef global_ordinal_type GO;
7766  typedef int pid_type;
7767 
7768  // Treat the Map as a 1-column "multivector." This differs
7769  // from the previous two-column format, in which column 0 held
7770  // the GIDs, and column 1 held the corresponding PIDs. It
7771  // differs because printing that format requires knowing the
7772  // entire first column -- that is, all the GIDs -- in advance.
7773  // Sending messages from each process one at a time saves
7774  // memory, but it means that Process 0 doesn't ever have all
7775  // the GIDs at once.
7776  //
7777  // We pack the entries as ptrdiff_t, since this should be the
7778  // biggest signed built-in integer type that can hold any GO
7779  // or pid_type (= int) quantity without overflow. Test this
7780  // assumption at run time.
7781  typedef ptrdiff_t int_type;
7782  TEUCHOS_TEST_FOR_EXCEPTION(
7783  sizeof (GO) > sizeof (int_type), std::logic_error,
7784  "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7785  << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7786  << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7787  TEUCHOS_TEST_FOR_EXCEPTION(
7788  sizeof (pid_type) > sizeof (int_type), std::logic_error,
7789  "The (MPI) process rank type pid_type=" <<
7790  TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7791  "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7792  " = " << sizeof (ptrdiff_t) << ".");
7793 
7794  const Comm<int>& comm = * (map.getComm ());
7795  const int myRank = comm.getRank ();
7796  const int numProcs = comm.getSize ();
7797 
7798  if (! err.is_null ()) {
7799  err->pushTab ();
7800  }
7801  if (debug) {
7802  std::ostringstream os;
7803  os << myRank << ": writeMap" << endl;
7804  *err << os.str ();
7805  }
7806  if (! err.is_null ()) {
7807  err->pushTab ();
7808  }
7809 
7810  const size_t myNumRows = map.getLocalNumElements ();
7811  // Use a different tag for the "size" messages than for the
7812  // "data" messages, in order to help us debug any mix-ups.
7813  const int sizeTag = 1337;
7814  const int dataTag = 1338;
7815 
7816  // Process 0 pipelines nonblocking receives with file output.
7817  //
7818  // Constraints:
7819  // - Process 0 can't post a receive for another process'
7820  // actual data, until it posts and waits on the receive
7821  // from that process with the amount of data to receive.
7822  // (We could just post receives with a max data size, but
7823  // I feel uncomfortable about that.)
7824  // - The C++ standard library doesn't allow nonblocking
7825  // output to an std::ostream.
7826  //
7827  // Process 0: Post receive-size receives from Processes 1 and 2.
7828  // Process 1: Post send-size send to Process 0.
7829  // Process 2: Post send-size send to Process 0.
7830  //
7831  // All processes: Pack my GIDs and PIDs.
7832  //
7833  // Process 1:
7834  // - Post send-data send to Process 0.
7835  // - Wait on my send-size send to Process 0.
7836  //
7837  // Process 0:
7838  // - Print MatrixMarket header.
7839  // - Print my GIDs and PIDs.
7840  // - Wait on receive-size receive from Process 1.
7841  // - Post receive-data receive from Process 1.
7842  //
7843  // For each process p = 1, 2, ... numProcs-1:
7844  // If I am Process 0:
7845  // - Post receive-size receive from Process p + 2
7846  // - Wait on receive-size receive from Process p + 1
7847  // - Post receive-data receive from Process p + 1
7848  // - Wait on receive-data receive from Process p
7849  // - Write data from Process p.
7850  // Else if I am Process p:
7851  // - Wait on my send-data send.
<