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.
7852  // Else if I am Process p+1:
7853  // - Post send-data send to Process 0.
7854  // - Wait on my send-size send.
7855  // Else if I am Process p+2:
7856  // - Post send-size send to Process 0.
7857  //
7858  // Pipelining has three goals here:
7859  // 1. Overlap communication (the receives) with file I/O
7860  // 2. Give Process 0 a chance to prepost some receives,
7861  // before sends show up, by packing local data before
7862  // posting sends
7863  // 3. Don't post _all_ receives or _all_ sends, because that
7864  // wouldn't be memory scalable. (Just because we can't
7865  // see how much memory MPI consumes, doesn't mean that it
7866  // doesn't consume any!)
7867 
7868  // These are used on every process. sendReqSize[0] holds the
7869  // number of rows on this process, and sendReqBuf holds this
7870  // process' data. Process 0 packs into sendReqBuf, but
7871  // doesn't send; it only uses that for printing. All other
7872  // processes send both of these to Process 0.
7873  RCP<CommRequest<int> > sendReqSize, sendReqData;
7874 
7875  // These are used only on Process 0, for received data. Keep
7876  // 3 of each, and treat the arrays as circular buffers. When
7877  // receiving from Process p, the corresponding array index
7878  // here is p % 3.
7879  Array<ArrayRCP<int_type> > recvSizeBufs (3);
7880  Array<ArrayRCP<int_type> > recvDataBufs (3);
7881  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7882  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7883 
7884  // Buffer for nonblocking send of the "send size."
7885  ArrayRCP<int_type> sendDataSize (1);
7886  sendDataSize[0] = myNumRows;
7887 
7888  if (myRank == 0) {
7889  if (debug) {
7890  std::ostringstream os;
7891  os << myRank << ": Post receive-size receives from "
7892  "Procs 1 and 2: tag = " << sizeTag << endl;
7893  *err << os.str ();
7894  }
7895  // Process 0: Post receive-size receives from Processes 1 and 2.
7896  recvSizeBufs[0].resize (1);
7897  (recvSizeBufs[0])[0] = -1; // error flag
7898  recvSizeBufs[1].resize (1);
7899  (recvSizeBufs[1])[0] = -1; // error flag
7900  recvSizeBufs[2].resize (1);
7901  (recvSizeBufs[2])[0] = -1; // error flag
7902  if (numProcs > 1) {
7903  recvSizeReqs[1] =
7904  ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7905  }
7906  if (numProcs > 2) {
7907  recvSizeReqs[2] =
7908  ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7909  }
7910  }
7911  else if (myRank == 1 || myRank == 2) {
7912  if (debug) {
7913  std::ostringstream os;
7914  os << myRank << ": Post send-size send: size = "
7915  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7916  *err << os.str ();
7917  }
7918  // Prime the pipeline by having Processes 1 and 2 start
7919  // their send-size sends. We don't want _all_ the processes
7920  // to start their send-size sends, because that wouldn't be
7921  // memory scalable.
7922  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7923  }
7924  else {
7925  if (debug) {
7926  std::ostringstream os;
7927  os << myRank << ": Not posting my send-size send yet" << endl;
7928  *err << os.str ();
7929  }
7930  }
7931 
7932  //
7933  // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7934  // consecutively, for better locality.
7935  //
7936 
7937  if (debug) {
7938  std::ostringstream os;
7939  os << myRank << ": Pack my GIDs and PIDs" << endl;
7940  *err << os.str ();
7941  }
7942 
7943  ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7944 
7945  if (map.isContiguous ()) {
7946  const int_type myMinGblIdx =
7947  static_cast<int_type> (map.getMinGlobalIndex ());
7948  for (size_t k = 0; k < myNumRows; ++k) {
7949  const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7950  const int_type pid = static_cast<int_type> (myRank);
7951  sendDataBuf[2*k] = gid;
7952  sendDataBuf[2*k+1] = pid;
7953  }
7954  }
7955  else {
7956  ArrayView<const GO> myGblInds = map.getLocalElementList ();
7957  for (size_t k = 0; k < myNumRows; ++k) {
7958  const int_type gid = static_cast<int_type> (myGblInds[k]);
7959  const int_type pid = static_cast<int_type> (myRank);
7960  sendDataBuf[2*k] = gid;
7961  sendDataBuf[2*k+1] = pid;
7962  }
7963  }
7964 
7965  if (debug) {
7966  std::ostringstream os;
7967  os << myRank << ": Done packing my GIDs and PIDs" << endl;
7968  *err << os.str ();
7969  }
7970 
7971  if (myRank == 1) {
7972  // Process 1: post send-data send to Process 0.
7973  if (debug) {
7974  *err << myRank << ": Post send-data send: tag = " << dataTag
7975  << endl;
7976  }
7977  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7978  }
7979 
7980  if (myRank == 0) {
7981  if (debug) {
7982  *err << myRank << ": Write MatrixMarket header" << endl;
7983  }
7984 
7985  // Process 0: Write the MatrixMarket header.
7986  // Description section explains each column.
7987  std::ostringstream hdr;
7988 
7989  // Print the Matrix Market header. MultiVector stores data
7990  // nonsymmetrically, hence "general" in the banner line.
7991  hdr << "%%MatrixMarket matrix array integer general" << endl
7992  << "% Format: Version 2.0" << endl
7993  << "%" << endl
7994  << "% This file encodes a Tpetra::Map." << endl
7995  << "% It is stored as a dense vector, with twice as many " << endl
7996  << "% entries as the global number of GIDs (global indices)." << endl
7997  << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7998  << "% is the rank of the process owning that GID." << endl
7999  << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
8000  out << hdr.str ();
8001 
8002  if (debug) {
8003  std::ostringstream os;
8004  os << myRank << ": Write my GIDs and PIDs" << endl;
8005  *err << os.str ();
8006  }
8007 
8008  // Write Process 0's data to the output stream.
8009  // Matrix Market prints dense matrices in column-major order.
8010  const int_type printNumRows = myNumRows;
8011  ArrayView<const int_type> printData = sendDataBuf ();
8012  for (int_type k = 0; k < printNumRows; ++k) {
8013  const int_type gid = printData[2*k];
8014  const int_type pid = printData[2*k+1];
8015  out << gid << endl << pid << endl;
8016  }
8017  }
8018 
8019  if (myRank == 0) {
8020  // Wait on receive-size receive from Process 1.
8021  const int recvRank = 1;
8022  const int circBufInd = recvRank % 3;
8023  if (debug) {
8024  std::ostringstream os;
8025  os << myRank << ": Wait on receive-size receive from Process "
8026  << recvRank << endl;
8027  *err << os.str ();
8028  }
8029  if (numProcs > 1) {
8030  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8031 
8032  // We received the number of rows of data. (The data
8033  // come in two columns.)
8034  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8035  if (debug && recvNumRows == -1) {
8036  std::ostringstream os;
8037  os << myRank << ": Result of receive-size receive from Process "
8038  << recvRank << " is -1. This should never happen, and "
8039  "suggests that the receive never got posted. Please report "
8040  "this bug to the Tpetra developers." << endl;
8041  *err << os.str ();
8042  }
8043 
8044  // Post receive-data receive from Process 1.
8045  recvDataBufs[circBufInd].resize (recvNumRows * 2);
8046  if (debug) {
8047  std::ostringstream os;
8048  os << myRank << ": Post receive-data receive from Process "
8049  << recvRank << ": tag = " << dataTag << ", buffer size = "
8050  << recvDataBufs[circBufInd].size () << endl;
8051  *err << os.str ();
8052  }
8053  if (! recvSizeReqs[circBufInd].is_null ()) {
8054  std::ostringstream os;
8055  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8056  "null, before posting the receive-data receive from Process "
8057  << recvRank << ". This should never happen. Please report "
8058  "this bug to the Tpetra developers." << endl;
8059  *err << os.str ();
8060  }
8061  recvDataReqs[circBufInd] =
8062  ireceive<int, int_type> (recvDataBufs[circBufInd],
8063  recvRank, dataTag, comm);
8064  } // numProcs > 1
8065  }
8066  else if (myRank == 1) {
8067  // Wait on my send-size send.
8068  if (debug) {
8069  std::ostringstream os;
8070  os << myRank << ": Wait on my send-size send" << endl;
8071  *err << os.str ();
8072  }
8073  wait<int> (comm, outArg (sendReqSize));
8074  }
8075 
8076  //
8077  // Pipeline loop
8078  //
8079  for (int p = 1; p < numProcs; ++p) {
8080  if (myRank == 0) {
8081  if (p + 2 < numProcs) {
8082  // Post receive-size receive from Process p + 2.
8083  const int recvRank = p + 2;
8084  const int circBufInd = recvRank % 3;
8085  if (debug) {
8086  std::ostringstream os;
8087  os << myRank << ": Post receive-size receive from Process "
8088  << recvRank << ": tag = " << sizeTag << endl;
8089  *err << os.str ();
8090  }
8091  if (! recvSizeReqs[circBufInd].is_null ()) {
8092  std::ostringstream os;
8093  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
8094  << "null, for the receive-size receive from Process "
8095  << recvRank << "! This may mean that this process never "
8096  << "finished waiting for the receive from Process "
8097  << (recvRank - 3) << "." << endl;
8098  *err << os.str ();
8099  }
8100  recvSizeReqs[circBufInd] =
8101  ireceive<int, int_type> (recvSizeBufs[circBufInd],
8102  recvRank, sizeTag, comm);
8103  }
8104 
8105  if (p + 1 < numProcs) {
8106  const int recvRank = p + 1;
8107  const int circBufInd = recvRank % 3;
8108 
8109  // Wait on receive-size receive from Process p + 1.
8110  if (debug) {
8111  std::ostringstream os;
8112  os << myRank << ": Wait on receive-size receive from Process "
8113  << recvRank << endl;
8114  *err << os.str ();
8115  }
8116  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8117 
8118  // We received the number of rows of data. (The data
8119  // come in two columns.)
8120  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8121  if (debug && recvNumRows == -1) {
8122  std::ostringstream os;
8123  os << myRank << ": Result of receive-size receive from Process "
8124  << recvRank << " is -1. This should never happen, and "
8125  "suggests that the receive never got posted. Please report "
8126  "this bug to the Tpetra developers." << endl;
8127  *err << os.str ();
8128  }
8129 
8130  // Post receive-data receive from Process p + 1.
8131  recvDataBufs[circBufInd].resize (recvNumRows * 2);
8132  if (debug) {
8133  std::ostringstream os;
8134  os << myRank << ": Post receive-data receive from Process "
8135  << recvRank << ": tag = " << dataTag << ", buffer size = "
8136  << recvDataBufs[circBufInd].size () << endl;
8137  *err << os.str ();
8138  }
8139  if (! recvDataReqs[circBufInd].is_null ()) {
8140  std::ostringstream os;
8141  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
8142  << "null, for the receive-data receive from Process "
8143  << recvRank << "! This may mean that this process never "
8144  << "finished waiting for the receive from Process "
8145  << (recvRank - 3) << "." << endl;
8146  *err << os.str ();
8147  }
8148  recvDataReqs[circBufInd] =
8149  ireceive<int, int_type> (recvDataBufs[circBufInd],
8150  recvRank, dataTag, comm);
8151  }
8152 
8153  // Wait on receive-data receive from Process p.
8154  const int recvRank = p;
8155  const int circBufInd = recvRank % 3;
8156  if (debug) {
8157  std::ostringstream os;
8158  os << myRank << ": Wait on receive-data receive from Process "
8159  << recvRank << endl;
8160  *err << os.str ();
8161  }
8162  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
8163 
8164  // Write Process p's data. Number of rows lives in
8165  // recvSizeBufs[circBufInd], and the actual data live in
8166  // recvDataBufs[circBufInd]. Do this after posting receives,
8167  // in order to expose overlap of comm. with file I/O.
8168  if (debug) {
8169  std::ostringstream os;
8170  os << myRank << ": Write GIDs and PIDs from Process "
8171  << recvRank << endl;
8172  *err << os.str () << endl;
8173  }
8174  const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
8175  if (debug && printNumRows == -1) {
8176  std::ostringstream os;
8177  os << myRank << ": Result of receive-size receive from Process "
8178  << recvRank << " was -1. This should never happen, and "
8179  "suggests that its receive-size receive was never posted. "
8180  "Please report this bug to the Tpetra developers." << endl;
8181  *err << os.str ();
8182  }
8183  if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
8184  std::ostringstream os;
8185  os << myRank << ": Result of receive-size receive from Proc "
8186  << recvRank << " was " << printNumRows << " > 0, but "
8187  "recvDataBufs[" << circBufInd << "] is null. This should "
8188  "never happen. Please report this bug to the Tpetra "
8189  "developers." << endl;
8190  *err << os.str ();
8191  }
8192  ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
8193  for (int_type k = 0; k < printNumRows; ++k) {
8194  const int_type gid = printData[2*k];
8195  const int_type pid = printData[2*k+1];
8196  out << gid << endl << pid << endl;
8197  }
8198  }
8199  else if (myRank == p) { // Process p
8200  // Wait on my send-data send.
8201  if (debug) {
8202  std::ostringstream os;
8203  os << myRank << ": Wait on my send-data send" << endl;
8204  *err << os.str ();
8205  }
8206  wait<int> (comm, outArg (sendReqData));
8207  }
8208  else if (myRank == p + 1) { // Process p + 1
8209  // Post send-data send to Process 0.
8210  if (debug) {
8211  std::ostringstream os;
8212  os << myRank << ": Post send-data send: tag = " << dataTag
8213  << endl;
8214  *err << os.str ();
8215  }
8216  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8217  // Wait on my send-size send.
8218  if (debug) {
8219  std::ostringstream os;
8220  os << myRank << ": Wait on my send-size send" << endl;
8221  *err << os.str ();
8222  }
8223  wait<int> (comm, outArg (sendReqSize));
8224  }
8225  else if (myRank == p + 2) { // Process p + 2
8226  // Post send-size send to Process 0.
8227  if (debug) {
8228  std::ostringstream os;
8229  os << myRank << ": Post send-size send: size = "
8230  << sendDataSize[0] << ", tag = " << sizeTag << endl;
8231  *err << os.str ();
8232  }
8233  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8234  }
8235  }
8236 
8237  if (! err.is_null ()) {
8238  err->popTab ();
8239  }
8240  if (debug) {
8241  *err << myRank << ": writeMap: Done" << endl;
8242  }
8243  if (! err.is_null ()) {
8244  err->popTab ();
8245  }
8246  }
8247 
8249  static void
8250  writeMapFile (const std::string& filename,
8251  const map_type& map)
8252  {
8253  const int myRank = map.getComm ()->getRank ();
8254 
8255  auto out = Writer::openOutFileOnRankZero(map.getComm(), filename, myRank, true);
8256 
8257  writeMap (out, map);
8258  // We can rely on the destructor of the output stream to close
8259  // the file on scope exit, even if writeDense() throws an
8260  // exception.
8261  }
8262 
8263  private:
8287  static void
8288  printAsComment (std::ostream& out, const std::string& str)
8289  {
8290  using std::endl;
8291  std::istringstream inpstream (str);
8292  std::string line;
8293 
8294  while (getline (inpstream, line)) {
8295  if (! line.empty()) {
8296  // Note that getline() doesn't store '\n', so we have to
8297  // append the endline ourselves.
8298  if (line[0] == '%') { // Line starts with a comment character.
8299  out << line << endl;
8300  }
8301  else { // Line doesn't start with a comment character.
8302  out << "%% " << line << endl;
8303  }
8304  }
8305  }
8306  }
8307 
8308  public:
8309 
8328  static void
8329  writeOperator(const std::string& fileName, operator_type const &A) {
8330  Teuchos::ParameterList pl;
8331  writeOperator(fileName, A, pl);
8332  }
8333 
8354  static void
8355  writeOperator (std::ostream& out, const operator_type& A) {
8356  Teuchos::ParameterList pl;
8357  writeOperator (out, A, pl);
8358  }
8359 
8396  static void
8397  writeOperator (const std::string& fileName,
8398  const operator_type& A,
8399  const Teuchos::ParameterList& params)
8400  {
8401  std::ofstream out;
8402  std::string tmpFile = "__TMP__" + fileName;
8403  const int myRank = A.getDomainMap()->getComm()->getRank();
8404  bool precisionChanged=false;
8405  int oldPrecision;
8406  // The number of nonzero entries in a Tpetra::Operator is
8407  // unknown until probing is completed. In order to write a
8408  // MatrixMarket header, we write the matrix to a temporary
8409  // file.
8410  //
8411  // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8412  // TEMPORARY FILE.
8413  if (myRank==0) {
8414  if (std::ifstream(tmpFile))
8415  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8416  "writeOperator: temporary file " << tmpFile << " already exists");
8417  out.open(tmpFile.c_str());
8418  if (params.isParameter("precision")) {
8419  oldPrecision = out.precision(params.get<int>("precision"));
8420  precisionChanged=true;
8421  }
8422  }
8423 
8424  const std::string header = writeOperatorImpl(out, A, params);
8425 
8426  if (myRank==0) {
8427  if (precisionChanged)
8428  out.precision(oldPrecision);
8429  out.close();
8430  out.open(fileName.c_str(), std::ios::binary);
8431  bool printMatrixMarketHeader = true;
8432  if (params.isParameter("print MatrixMarket header"))
8433  printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8434  if (printMatrixMarketHeader && myRank == 0) {
8435  // Write header to final file.
8436  out << header;
8437  }
8438  // Append matrix from temporary to final file.
8439  std::ifstream src(tmpFile, std::ios_base::binary);
8440  out << src.rdbuf();
8441  src.close();
8442  // Delete the temporary file.
8443  remove(tmpFile.c_str());
8444  }
8445  }
8446 
8485  static void
8486  writeOperator (std::ostream& out,
8487  const operator_type& A,
8488  const Teuchos::ParameterList& params)
8489  {
8490  const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8491 
8492  // The number of nonzero entries in a Tpetra::Operator is
8493  // unknown until probing is completed. In order to write a
8494  // MatrixMarket header, we write the matrix to a temporary
8495  // output stream.
8496  //
8497  // NOTE (mfh 23 May 2015): Writing to a temporary output
8498  // stream may double the memory usage, depending on whether
8499  // 'out' is a file stream or an in-memory output stream (e.g.,
8500  // std::ostringstream). It might be wise to use a temporary
8501  // file instead. However, please look carefully at POSIX
8502  // functions for safe creation of temporary files. Don't just
8503  // prepend "__TMP__" to the filename and hope for the best.
8504  // Furthermore, it should be valid to call the std::ostream
8505  // overload of this method even when Process 0 does not have
8506  // access to a file system.
8507  std::ostringstream tmpOut;
8508  if (myRank == 0) {
8509  if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8510  (void) tmpOut.precision (params.get<int> ("precision"));
8511  }
8512  }
8513 
8514  const std::string header = writeOperatorImpl (tmpOut, A, params);
8515 
8516  if (myRank == 0) {
8517  bool printMatrixMarketHeader = true;
8518  if (params.isParameter ("print MatrixMarket header") &&
8519  params.isType<bool> ("print MatrixMarket header")) {
8520  printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8521  }
8522  if (printMatrixMarketHeader && myRank == 0) {
8523  out << header; // write header to final output stream
8524  }
8525  // Append matrix from temporary output stream to final output stream.
8526  //
8527  // NOTE (mfh 23 May 2015) This might use a lot of memory.
8528  // However, we should not use temporary files in this
8529  // method. Since it does not access the file system (unlike
8530  // the overload that takes a file name), it should not
8531  // require the file system at all.
8532  //
8533  // If memory usage becomes a problem, one thing we could do
8534  // is write the entries of the Operator one column (or a few
8535  // columns) at a time. The Matrix Market sparse format does
8536  // not impose an order on its entries, so it would be OK to
8537  // write them in that order.
8538  out << tmpOut.str ();
8539  }
8540  }
8541 
8542  private:
8543 
8551  static std::string
8552  writeOperatorImpl (std::ostream& os,
8553  const operator_type& A,
8554  const Teuchos::ParameterList& params)
8555  {
8556  using Teuchos::RCP;
8557  using Teuchos::rcp;
8558  using Teuchos::ArrayRCP;
8559  using Teuchos::Array;
8560 
8561  typedef local_ordinal_type LO;
8562  typedef global_ordinal_type GO;
8563  typedef scalar_type Scalar;
8564  typedef Teuchos::OrdinalTraits<LO> TLOT;
8565  typedef Teuchos::OrdinalTraits<GO> TGOT;
8566  typedef Tpetra::Import<LO, GO, node_type> import_type;
8567  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
8568 
8569  const map_type& domainMap = *(A.getDomainMap());
8570  RCP<const map_type> rangeMap = A.getRangeMap();
8571  trcp_tcomm_t comm = rangeMap->getComm();
8572  const int myRank = comm->getRank();
8573  const size_t numProcs = comm->getSize();
8574 
8575  size_t numMVs = 10;
8576  if (params.isParameter("probing size"))
8577  numMVs = params.get<int>("probing size");
8578 
8579  GO globalNnz = 0;
8580  GO minColGid = domainMap.getMinAllGlobalIndex();
8581  GO maxColGid = domainMap.getMaxAllGlobalIndex();
8582  // Rather than replicating the domainMap on all processors, we instead
8583  // iterate from the min GID to the max GID. If the map is gappy,
8584  // there will be invalid GIDs, i.e., GIDs no one has. This will require
8585  // unnecessary matvecs against potentially zero vectors.
8586  GO numGlobElts = maxColGid - minColGid + TGOT::one();
8587  GO numChunks = numGlobElts / numMVs;
8588  GO rem = numGlobElts % numMVs;
8589  GO indexBase = rangeMap->getIndexBase();
8590 
8591  int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8592  if (params.isParameter("zero-based indexing")) {
8593  if (params.get<bool>("zero-based indexing") == true)
8594  offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8595  }
8596 
8597  // Create map that replicates the range map on pid 0 and is empty for all other pids
8598  size_t numLocalRangeEntries = rangeMap->getLocalNumElements();
8599 
8600  // Create contiguous source map
8601  RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8602  indexBase, comm));
8603  // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8604  mv_type_go allGids(allGidsMap,1);
8605  Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8606 
8607  for (size_t i=0; i<numLocalRangeEntries; i++)
8608  allGidsData[i] = rangeMap->getGlobalElement(i);
8609  allGidsData = Teuchos::null;
8610 
8611  // Create target map that is nontrivial only on pid 0
8612  GO numTargetMapEntries=TGOT::zero();
8613  Teuchos::Array<GO> importGidList;
8614  if (myRank==0) {
8615  numTargetMapEntries = rangeMap->getGlobalNumElements();
8616  importGidList.reserve(numTargetMapEntries);
8617  for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8618  } else {
8619  importGidList.reserve(numTargetMapEntries);
8620  }
8621  RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8622 
8623  // Import all rangeMap GIDs to pid 0
8624  import_type gidImporter(allGidsMap, importGidMap);
8625  mv_type_go importedGids(importGidMap, 1);
8626  importedGids.doImport(allGids, gidImporter, INSERT);
8627 
8628  // The following import map will be non-trivial only on pid 0.
8629  ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8630  RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8631 
8632  // Importer from original range map to pid 0
8633  import_type importer(rangeMap, importMap);
8634  // Target vector on pid 0
8635  RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8636 
8637  RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8638  RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8639 
8640  Array<GO> globalColsArray, localColsArray;
8641  globalColsArray.reserve(numMVs);
8642  localColsArray.reserve(numMVs);
8643 
8644  ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8645  for (size_t i=0; i<numMVs; ++i)
8646  eiData[i] = ei->getDataNonConst(i);
8647 
8648  // //////////////////////////////////////
8649  // Discover A by chunks
8650  // //////////////////////////////////////
8651  for (GO k=0; k<numChunks; ++k) {
8652  for (size_t j=0; j<numMVs; ++j ) {
8653  //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8654  GO curGlobalCol = minColGid + k*numMVs + j;
8655  globalColsArray.push_back(curGlobalCol);
8656  //TODO extract the g2l map outside of this loop loop
8657  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8658  if (curLocalCol != TLOT::invalid()) {
8659  eiData[j][curLocalCol] = TGOT::one();
8660  localColsArray.push_back(curLocalCol);
8661  }
8662  }
8663 
8664  // drop host views before apply
8665  for (size_t i=0; i<numMVs; ++i)
8666  eiData[i] = Teuchos::null;
8667  // probe
8668  A.apply(*ei,*colsA);
8669 
8670  colsOnPid0->doImport(*colsA,importer,INSERT);
8671 
8672  if (myRank==0)
8673  globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8674  globalColsArray, offsetToUseInPrinting);
8675 
8676  // reconstruct dropped eiData
8677  for (size_t i=0; i<numMVs; ++i)
8678  eiData[i] = ei->getDataNonConst(i);
8679  for (size_t j=0; j<numMVs; ++j ) {
8680  GO curGlobalCol = minColGid + k*numMVs + j;
8681  //TODO extract the g2l map outside of this loop loop
8682  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8683  if (curLocalCol != TLOT::invalid()) {
8684  eiData[j][curLocalCol] = TGOT::one();
8685  }
8686  }
8687 
8688  //zero out the ei's
8689  for (size_t j=0; j<numMVs; ++j ) {
8690  for (int i=0; i<localColsArray.size(); ++i)
8691  eiData[j][localColsArray[i]] = TGOT::zero();
8692  }
8693  globalColsArray.clear();
8694  localColsArray.clear();
8695 
8696  }
8697 
8698  // //////////////////////////////////////
8699  // Handle leftover part of A
8700  // //////////////////////////////////////
8701  if (rem > 0) {
8702  for (int j=0; j<rem; ++j ) {
8703  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8704  globalColsArray.push_back(curGlobalCol);
8705  //TODO extract the g2l map outside of this loop loop
8706  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8707  if (curLocalCol != TLOT::invalid()) {
8708  eiData[j][curLocalCol] = TGOT::one();
8709  localColsArray.push_back(curLocalCol);
8710  }
8711  }
8712 
8713  // drop host views before apply
8714  for (size_t i=0; i<numMVs; ++i)
8715  eiData[i] = Teuchos::null;
8716  // probe
8717  A.apply(*ei,*colsA);
8718 
8719  colsOnPid0->doImport(*colsA,importer,INSERT);
8720  if (myRank==0)
8721  globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8722  globalColsArray, offsetToUseInPrinting);
8723 
8724  // reconstruct dropped eiData
8725  for (size_t i=0; i<numMVs; ++i)
8726  eiData[i] = ei->getDataNonConst(i);
8727  for (int j=0; j<rem; ++j ) {
8728  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8729  //TODO extract the g2l map outside of this loop loop
8730  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8731  if (curLocalCol != TLOT::invalid()) {
8732  eiData[j][curLocalCol] = TGOT::one();
8733  }
8734  }
8735 
8736  //zero out the ei's
8737  for (int j=0; j<rem; ++j ) {
8738  for (int i=0; i<localColsArray.size(); ++i)
8739  eiData[j][localColsArray[i]] = TGOT::zero();
8740  }
8741  globalColsArray.clear();
8742  localColsArray.clear();
8743 
8744  }
8745 
8746  // Return the Matrix Market header. It includes the header
8747  // line (that starts with "%%"), some comments, and the triple
8748  // of matrix dimensions and number of nonzero entries. We
8749  // don't actually print this here, because we don't know the
8750  // number of nonzero entries until after probing.
8751  std::ostringstream oss;
8752  if (myRank == 0) {
8753  oss << "%%MatrixMarket matrix coordinate ";
8754  if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8755  oss << "complex";
8756  } else {
8757  oss << "real";
8758  }
8759  oss << " general" << std::endl;
8760  oss << "% Tpetra::Operator" << std::endl;
8761  std::time_t now = std::time(NULL);
8762  oss << "% time stamp: " << ctime(&now);
8763  oss << "% written from " << numProcs << " processes" << std::endl;
8764  size_t numRows = rangeMap->getGlobalNumElements();
8765  size_t numCols = domainMap.getGlobalNumElements();
8766  oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8767  }
8768 
8769  return oss.str ();
8770  }
8771 
8772  static global_ordinal_type
8773  writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8774  Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8775  Teuchos::Array<global_ordinal_type> const &colsArray,
8776  global_ordinal_type const & indexBase) {
8777 
8778  typedef global_ordinal_type GO;
8779  typedef scalar_type Scalar;
8780  typedef Teuchos::ScalarTraits<Scalar> STS;
8781 
8782  GO nnz=0;
8783  const Scalar zero = STS::zero();
8784  const size_t numRows = colsA.getGlobalLength();
8785  for (size_t j=0; j<numCols; ++j) {
8786  Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8787  const GO J = colsArray[j];
8788  for (size_t i=0; i<numRows; ++i) {
8789  const Scalar val = curCol[i];
8790  if (val!=zero) {
8791  os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8792  ++nnz;
8793  }
8794  }
8795  }
8796 
8797  return nnz;
8798 
8799  }
8800 
8801  public:
8802 
8803 
8810 
8811  static
8812  void
8813  writeSparsePerRank (const std::string& filename_prefix,
8814  const std::string& filename_suffix,
8815  const sparse_matrix_type& matrix,
8816  const std::string& matrixName,
8817  const std::string& matrixDescription,
8818  const int ranksToWriteAtOnce=8,
8819  const bool debug=false) {
8820 
8821  using ST = scalar_type;
8822  //using LO = local_ordinal_type;
8823  using GO = global_ordinal_type;
8824  using STS = typename Teuchos::ScalarTraits<ST>;
8825  using Teuchos::RCP;
8826 
8827  // Sanity Checks
8828  trcp_tcomm_t comm = matrix.getComm ();
8829  TEUCHOS_TEST_FOR_EXCEPTION
8830  (comm.is_null (), std::invalid_argument,
8831  "The input matrix's communicator (Teuchos::Comm object) is null.");
8832  TEUCHOS_TEST_FOR_EXCEPTION
8833  (matrix.isGloballyIndexed() || !matrix.isFillComplete(), std::invalid_argument,
8834  "The input matrix must not be GloballyIndexed and must be fillComplete.");
8835 
8836  // Setup
8837  const int myRank = comm->getRank();
8838  const int numProc = comm->getSize();
8839  std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
8840  RCP<const map_type> rowMap = matrix.getRowMap();
8841  RCP<const map_type> colMap = matrix.getColMap();
8842  size_t local_nnz = matrix.getLocalNumEntries();
8843  size_t local_num_rows = rowMap->getLocalNumElements();
8844  size_t local_num_cols = colMap->getLocalNumElements();
8845  const GO rowIndexBase = rowMap->getIndexBase();
8846  const GO colIndexBase = colMap->getIndexBase();
8847 
8848  // Bounds check the writing limits
8849  int rank_limit = std::min(std::max(ranksToWriteAtOnce,1),numProc);
8850 
8851  // Start the writing
8852  for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
8853  int stop = std::min(base_rank+rank_limit,numProc);
8854 
8855  if(base_rank <= myRank && myRank < stop) {
8856  // My turn to write
8857  std::ofstream out(filename);
8858 
8859  // MatrixMarket Header
8860  out << "%%MatrixMarket matrix coordinate "
8861  << (STS::isComplex ? "complex" : "real")
8862  << " general" << std::endl;
8863 
8864  // Print comments (the matrix name and / or description).
8865  if (matrixName != "") {
8866  printAsComment (out, matrixName);
8867  }
8868  if (matrixDescription != "") {
8869  printAsComment (out, matrixDescription);
8870  }
8871 
8872  // Print the Matrix Market header (# local rows, # local columns, #
8873  // local enonzeros). This will *not* be read correctly by a generic matrix
8874  // market reader since we'll be writing out GIDs here and local row/col counts
8875  out << local_num_rows << " " << local_num_cols << " " << local_nnz <<std::endl;
8876 
8877  {
8878  // Make the output stream write floating-point numbers in
8879  // scientific notation. It will politely put the output
8880  // stream back to its state on input, when this scope
8881  // terminates.
8882  Teuchos::SetScientific<ST> sci (out);
8883 
8884  for(size_t l_row = 0; l_row < local_num_rows; l_row++) {
8885  GO g_row = rowMap->getGlobalElement(l_row);
8886 
8887  typename sparse_matrix_type::local_inds_host_view_type indices;
8888  typename sparse_matrix_type::values_host_view_type values;
8889  matrix.getLocalRowView(l_row, indices, values);
8890  for (size_t ii = 0; ii < indices.extent(0); ii++) {
8891  const GO g_col = colMap->getGlobalElement(indices(ii));
8892  // Convert row and column indices to 1-based.
8893  // This works because the global index type is signed.
8894  out << (g_row + 1 - rowIndexBase) << " "
8895  << (g_col + 1 - colIndexBase) << " ";
8896  if (STS::isComplex) {
8897  out << STS::real(values(ii)) << " " << STS::imag(values(ii));
8898  } else {
8899  out << values(ii);
8900  }
8901  out << std::endl;
8902  } // For each entry in the current row
8903  } // For each row of the matrix
8904  }// end Teuchos::SetScientfic scoping
8905 
8906  out.close();
8907  }// end if base_rank <= myRank < stop
8908 
8909  // Barrier after each writing "batch" to make sure we're not hammering the file system
8910  // too aggressively
8911  comm->barrier();
8912 
8913  }// end outer loop
8914 
8915  }// end writeSparsePerRank
8916 
8918  template <typename T>
8919  static inline trcp_tcomm_t getComm(const Teuchos::RCP<T>& obj)
8920  {
8921  return obj.is_null() ? Teuchos::null : obj->getComm();
8922  }
8923 
8925  static inline int getRank(const trcp_tcomm_t& comm)
8926  {
8927  return comm.is_null() ? 0 : comm->getRank();
8928  }
8929 
8930  }; // class Writer
8931 
8932  } // namespace MatrixMarket
8933 } // namespace Tpetra
8934 
8935 #endif // __MatrixMarket_Tpetra_hpp
static std::ifstream openInFileOnRankZero(const trcp_tcomm_t &comm, const std::string &filename, const bool safe=true, std::ios_base::openmode mode=std::ios_base::in)
Open an input file stream safely on rank zero.
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const trcp_tcomm_t &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments...
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const trcp_tcomm_t &comm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const trcp_tcomm_t &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Import data into this object using an Import object (&quot;forward mode&quot;).
size_t getNumVectors() const
Number of columns in the multivector.
Declaration of a function that prints strings from each process.
size_t getLocalNumElements() const
The number of elements belonging to the calling process.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
One or more distributed dense vectors.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const trcp_tcomm_t &comm, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given Matrix Market file.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
SparseMatrixType::scalar_type scalar_type
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file, with provided Maps.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const trcp_tcomm_t &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const trcp_tcomm_t &comm, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given input stream.
bool isGloballyIndexed() const override
Whether the graph&#39;s column indices are stored as global indices.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static trcp_tcomm_t getComm(const Teuchos::RCP< T > &obj)
Return obj MPI communicator or Teuchos::null.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const trcp_tcomm_t &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream...
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps. ...
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator, in rank order.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const trcp_tcomm_t &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments...
Teuchos::ArrayView< const global_ordinal_type > getLocalElementList() const
Return a NONOWNING view of the global indices owned by this process.
static Teuchos::RCP< sparse_matrix_type > readSparsePerRank(const std::string &filename_prefix, const std::string &filename_suffix, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const int ranksToReadAtOnce=8, const bool debug=false)
Read a Tpetra::CrsMatrix from a file per rank setup.
size_t global_size_t
Global size_t object.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeSparsePerRank(const std::string &filename_prefix, const std::string &filename_suffix, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const int ranksToWriteAtOnce=8, const bool debug=false)
Write a Tpetra::CrsMatrix to a file per rank.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const trcp_tcomm_t &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false, const bool binary=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
Insert new values that don&#39;t currently exist.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
Abstract interface for operators (e.g., matrices and preconditioners).
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
Teuchos::RCP< const Teuchos::Comm< int >> trcp_tcomm_t
Type of the MPI communicator.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const trcp_tcomm_t &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
From a distributed map build a map with all GIDs on the root node.
static int getRank(const trcp_tcomm_t &comm)
Return MPI rank or 0.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
Teuchos::RCP< const Teuchos::Comm< int >> trcp_tcomm_t
Type of the MPI communicator.
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments...
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
void start()
Start the deep_copy counter.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
A parallel distribution of indices over processes.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
void getLocalRowView(const LocalOrdinal lclRow, local_inds_host_view_type &lclColInds) const override
Get a const view of the given local row&#39;s local column indices.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
A distributed dense vector.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
SparseMatrixType sparse_matrix_type
This class&#39; template parameter; a specialization of CrsMatrix.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps. ...
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Matrix Market file reader for CrsMatrix and MultiVector.
Matrix Market file writer for CrsMatrix and MultiVector.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
void getGlobalRowView(const global_ordinal_type gblRow, global_inds_host_view_type &gblColInds) const override
Get a const view of the given global row&#39;s global column indices.
void stop()
Stop the deep_copy counter.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.