Tpetra parallel linear algebra  Version of the Day
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef __MatrixMarket_Tpetra_hpp
43 #define __MatrixMarket_Tpetra_hpp
44 
56 #include "Tpetra_Details_gathervPrint.hpp"
57 #include "Tpetra_CrsMatrix.hpp"
58 #include "Tpetra_Operator.hpp"
59 #include "Tpetra_Vector.hpp"
61 #include "Teuchos_MatrixMarket_Raw_Adder.hpp"
62 #include "Teuchos_MatrixMarket_Raw_Graph_Adder.hpp"
63 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
64 #include "Teuchos_MatrixMarket_SymmetrizingGraphAdder.hpp"
65 #include "Teuchos_MatrixMarket_assignScalar.hpp"
66 #include "Teuchos_MatrixMarket_Banner.hpp"
67 #include "Teuchos_MatrixMarket_CoordDataReader.hpp"
68 #include "Teuchos_SetScientific.hpp"
69 
70 #include <algorithm>
71 #include <fstream>
72 #include <iostream>
73 #include <iterator>
74 #include <vector>
75 #include <stdexcept>
76 #include <numeric>
77 
78 namespace Tpetra {
108  namespace MatrixMarket {
164  template<class SparseMatrixType>
165  class Reader {
166  public:
168  typedef SparseMatrixType sparse_matrix_type;
169  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
170 
173  typedef typename SparseMatrixType::scalar_type scalar_type;
176  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
184  typedef typename SparseMatrixType::global_ordinal_type
187  typedef typename SparseMatrixType::node_type node_type;
188 
192  node_type> sparse_graph_type;
193 
195  typedef MultiVector<scalar_type,
198  node_type> multivector_type;
199 
201  typedef Vector<scalar_type,
204  node_type> vector_type;
205 
206  typedef Teuchos::Comm<int> comm_type;
208 
209  // DEPRECATED typedefs for backwards compatibility.
210  typedef Teuchos::RCP<const comm_type> comm_ptr;
211  typedef Teuchos::RCP<const map_type> map_ptr;
212  typedef Teuchos::RCP<node_type> node_ptr;
213 
214  private:
220  typedef Teuchos::ArrayRCP<int>::size_type size_type;
221 
233  static Teuchos::RCP<const map_type>
234  makeRangeMap (const Teuchos::RCP<const comm_type>& pComm,
235  const Teuchos::RCP<node_type>& pNode,
236  const global_ordinal_type numRows)
237  {
238  // Return a conventional, uniformly partitioned, contiguous map.
239  if (pNode.is_null ()) {
240  return rcp (new map_type (static_cast<global_size_t> (numRows),
241  static_cast<global_ordinal_type> (0),
242  pComm, GloballyDistributed));
243  }
244  else {
245  return rcp (new map_type (static_cast<global_size_t> (numRows),
246  static_cast<global_ordinal_type> (0),
247  pComm, GloballyDistributed, pNode));
248  }
249  }
250 
279  static Teuchos::RCP<const map_type>
280  makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
281  const Teuchos::RCP<const comm_type>& pComm,
282  const Teuchos::RCP<node_type>& pNode,
283  const global_ordinal_type numRows)
284  {
285  // If the caller didn't provide a map, return a conventional,
286  // uniformly partitioned, contiguous map.
287  if (pRowMap.is_null ()) {
288  if (pNode.is_null ()) {
289  return rcp (new map_type (static_cast<global_size_t> (numRows),
290  static_cast<global_ordinal_type> (0),
291  pComm, GloballyDistributed));
292  }
293  else {
294  return rcp (new map_type (static_cast<global_size_t> (numRows),
295  static_cast<global_ordinal_type> (0),
296  pComm, GloballyDistributed, pNode));
297  }
298  }
299  else {
300  TEUCHOS_TEST_FOR_EXCEPTION
301  (! pRowMap->isDistributed () && pComm->getSize () > 1,
302  std::invalid_argument, "The specified row map is not distributed, "
303  "but the given communicator includes more than one process (in "
304  "fact, there are " << pComm->getSize () << " processes).");
305  TEUCHOS_TEST_FOR_EXCEPTION
306  (pRowMap->getComm () != pComm, std::invalid_argument,
307  "The specified row Map's communicator (pRowMap->getComm()) "
308  "differs from the given separately supplied communicator pComm.");
309  return pRowMap;
310  }
311  }
312 
327  static Teuchos::RCP<const map_type>
328  makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
329  const global_ordinal_type numRows,
330  const global_ordinal_type numCols)
331  {
332  // Abbreviations so that the map creation call isn't too long.
333  typedef local_ordinal_type LO;
334  typedef global_ordinal_type GO;
335  typedef node_type NT;
336 
337  if (numRows == numCols) {
338  return pRangeMap;
339  } else {
340  return createUniformContigMapWithNode<LO,GO,NT> (numCols,
341  pRangeMap->getComm (),
342  pRangeMap->getNode ());
343  }
344  }
345 
418  static void
419  distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
420  Teuchos::ArrayRCP<size_t>& myRowPtr,
421  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
422  Teuchos::ArrayRCP<scalar_type>& myValues,
423  const Teuchos::RCP<const map_type>& pRowMap,
424  Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
425  Teuchos::ArrayRCP<size_t>& rowPtr,
426  Teuchos::ArrayRCP<global_ordinal_type>& colInd,
427  Teuchos::ArrayRCP<scalar_type>& values,
428  const bool debug=false)
429  {
430  using Teuchos::arcp;
431  using Teuchos::ArrayRCP;
432  using Teuchos::ArrayView;
433  using Teuchos::as;
434  using Teuchos::Comm;
435  using Teuchos::CommRequest;
436  using Teuchos::null;
437  using Teuchos::RCP;
438  using Teuchos::receive;
439  using Teuchos::send;
440  using std::cerr;
441  using std::endl;
442 
443  const bool extraDebug = false;
444  RCP<const comm_type> pComm = pRowMap->getComm ();
445  const int numProcs = pComm->getSize ();
446  const int myRank = pComm->getRank ();
447  const int rootRank = 0;
448 
449  // Type abbreviations to make the code more concise.
450  typedef global_ordinal_type GO;
451 
452  // List of the global indices of my rows. They may or may
453  // not be contiguous, and the row map need not be one-to-one.
454  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
455  const size_type myNumRows = myRows.size();
456  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
457  pRowMap->getNodeNumElements(),
458  std::logic_error,
459  "pRowMap->getNodeElementList().size() = "
460  << myNumRows
461  << " != pRowMap->getNodeNumElements() = "
462  << pRowMap->getNodeNumElements() << ". "
463  "Please report this bug to the Tpetra developers.");
464  TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
465  std::logic_error,
466  "On Proc 0: numEntriesPerRow.size() = "
467  << numEntriesPerRow.size()
468  << " != pRowMap->getNodeElementList().size() = "
469  << myNumRows << ". Please report this bug to the "
470  "Tpetra developers.");
471 
472  // Space for my proc's number of entries per row. Will be
473  // filled in below.
474  myNumEntriesPerRow = arcp<size_t> (myNumRows);
475 
476  if (myRank != rootRank) {
477  // Tell the root how many rows we have. If we're sending
478  // none, then we don't have anything else to send, nor does
479  // the root have to receive anything else.
480  send (*pComm, myNumRows, rootRank);
481  if (myNumRows != 0) {
482  // Now send my rows' global indices. Hopefully the cast
483  // to int doesn't overflow. This is unlikely, since it
484  // should fit in a LO, even though it is a GO.
485  send (*pComm, static_cast<int> (myNumRows),
486  myRows.getRawPtr(), rootRank);
487 
488  // I (this proc) don't care if my global row indices are
489  // contiguous, though the root proc does (since otherwise
490  // it needs to pack noncontiguous data into contiguous
491  // storage before sending). That's why we don't check
492  // for contiguousness here.
493 
494  // Ask the root process for my part of the array of the
495  // number of entries per row.
496  receive (*pComm, rootRank,
497  static_cast<int> (myNumRows),
498  myNumEntriesPerRow.getRawPtr());
499 
500  // Use the resulting array to figure out how many column
501  // indices and values I should ask from the root process.
502  const local_ordinal_type myNumEntries =
503  std::accumulate (myNumEntriesPerRow.begin(),
504  myNumEntriesPerRow.end(), 0);
505 
506  // Make space for my entries of the sparse matrix. Note
507  // that they don't have to be sorted by row index.
508  // Iterating through all my rows requires computing a
509  // running sum over myNumEntriesPerRow.
510  myColInd = arcp<GO> (myNumEntries);
511  myValues = arcp<scalar_type> (myNumEntries);
512  if (myNumEntries > 0) {
513  // Ask for that many column indices and values, if
514  // there are any.
515  receive (*pComm, rootRank,
516  static_cast<int> (myNumEntries),
517  myColInd.getRawPtr());
518  receive (*pComm, rootRank,
519  static_cast<int> (myNumEntries),
520  myValues.getRawPtr());
521  }
522  } // If I own at least one row
523  } // If I am not the root processor
524  else { // I _am_ the root processor
525  if (debug) {
526  cerr << "-- Proc 0: Copying my data from global arrays" << endl;
527  }
528  // Proc 0 still needs to (allocate, if not done already)
529  // and fill its part of the matrix (my*).
530  for (size_type k = 0; k < myNumRows; ++k) {
531  const GO myCurRow = myRows[k];
532  const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
533  myNumEntriesPerRow[k] = numEntriesInThisRow;
534  }
535  if (extraDebug && debug) {
536  cerr << "Proc " << pRowMap->getComm ()->getRank ()
537  << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
538  for (size_type k = 0; k < myNumRows; ++k) {
539  cerr << myNumEntriesPerRow[k];
540  if (k < myNumRows-1) {
541  cerr << " ";
542  }
543  }
544  cerr << "]" << endl;
545  }
546  // The total number of matrix entries that my proc owns.
547  const local_ordinal_type myNumEntries =
548  std::accumulate (myNumEntriesPerRow.begin(),
549  myNumEntriesPerRow.end(), 0);
550  if (debug) {
551  cerr << "-- Proc 0: I own " << myNumRows << " rows and "
552  << myNumEntries << " entries" << endl;
553  }
554  myColInd = arcp<GO> (myNumEntries);
555  myValues = arcp<scalar_type> (myNumEntries);
556 
557  // Copy Proc 0's part of the matrix into the my* arrays.
558  // It's important that myCurPos be updated _before_ k,
559  // otherwise myCurPos will get the wrong number of entries
560  // per row (it should be for the row in the just-completed
561  // iteration, not for the next iteration's row).
562  local_ordinal_type myCurPos = 0;
563  for (size_type k = 0; k < myNumRows;
564  myCurPos += myNumEntriesPerRow[k], ++k) {
565  const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
566  const GO myRow = myRows[k];
567  const size_t curPos = rowPtr[myRow];
568  // Only copy if there are entries to copy, in order not
569  // to construct empty ranges for the ArrayRCP views.
570  if (curNumEntries > 0) {
571  ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
572  ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
573  std::copy (colIndView.begin(), colIndView.end(),
574  myColIndView.begin());
575 
576  ArrayView<scalar_type> valuesView =
577  values (curPos, curNumEntries);
578  ArrayView<scalar_type> myValuesView =
579  myValues (myCurPos, curNumEntries);
580  std::copy (valuesView.begin(), valuesView.end(),
581  myValuesView.begin());
582  }
583  }
584 
585  // Proc 0 processes each other proc p in turn.
586  for (int p = 1; p < numProcs; ++p) {
587  if (debug) {
588  cerr << "-- Proc 0: Processing proc " << p << endl;
589  }
590 
591  size_type theirNumRows = 0;
592  // Ask Proc p how many rows it has. If it doesn't
593  // have any, we can move on to the next proc. This
594  // has to be a standard receive so that we can avoid
595  // the degenerate case of sending zero data.
596  receive (*pComm, p, &theirNumRows);
597  if (debug) {
598  cerr << "-- Proc 0: Proc " << p << " owns "
599  << theirNumRows << " rows" << endl;
600  }
601  if (theirNumRows != 0) {
602  // Ask Proc p which rows it owns. The resulting global
603  // row indices are not guaranteed to be contiguous or
604  // sorted. Global row indices are themselves indices
605  // into the numEntriesPerRow array.
606  ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
607  receive (*pComm, p, as<int> (theirNumRows),
608  theirRows.getRawPtr ());
609  // Extra test to make sure that the rows we received
610  // are all sensible. This is a good idea since we are
611  // going to use the global row indices we've received
612  // to index into the numEntriesPerRow array. Better to
613  // catch any bugs here and print a sensible error
614  // message, rather than segfault and print a cryptic
615  // error message.
616  {
617  const global_size_t numRows = pRowMap->getGlobalNumElements ();
618  const GO indexBase = pRowMap->getIndexBase ();
619  bool theirRowsValid = true;
620  for (size_type k = 0; k < theirNumRows; ++k) {
621  if (theirRows[k] < indexBase ||
622  as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
623  theirRowsValid = false;
624  }
625  }
626  if (! theirRowsValid) {
627  TEUCHOS_TEST_FOR_EXCEPTION(
628  ! theirRowsValid, std::logic_error,
629  "Proc " << p << " has at least one invalid row index. "
630  "Here are all of them: " <<
631  Teuchos::toString (theirRows ()) << ". Valid row index "
632  "range (zero-based): [0, " << (numRows - 1) << "].");
633  }
634  }
635 
636  // Perhaps we could save a little work if we check
637  // whether Proc p's row indices are contiguous. That
638  // would make lookups in the global data arrays
639  // faster. For now, we just implement the general
640  // case and don't prematurely optimize. (Remember
641  // that you're making Proc 0 read the whole file, so
642  // you've already lost scalability.)
643 
644  // Compute the number of entries in each of Proc p's
645  // rows. (Proc p will compute its row pointer array
646  // on its own, after it gets the data from Proc 0.)
647  ArrayRCP<size_t> theirNumEntriesPerRow;
648  theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
649  for (size_type k = 0; k < theirNumRows; ++k) {
650  theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
651  }
652 
653  // Tell Proc p the number of entries in each of its
654  // rows. Hopefully the cast to int doesn't overflow.
655  // This is unlikely, since it should fit in a LO,
656  // even though it is a GO.
657  send (*pComm, static_cast<int> (theirNumRows),
658  theirNumEntriesPerRow.getRawPtr(), p);
659 
660  // Figure out how many entries Proc p owns.
661  const local_ordinal_type theirNumEntries =
662  std::accumulate (theirNumEntriesPerRow.begin(),
663  theirNumEntriesPerRow.end(), 0);
664 
665  if (debug) {
666  cerr << "-- Proc 0: Proc " << p << " owns "
667  << theirNumEntries << " entries" << endl;
668  }
669 
670  // If there are no entries to send, then we're done
671  // with Proc p.
672  if (theirNumEntries == 0) {
673  continue;
674  }
675 
676  // Construct (views of) proc p's column indices and
677  // values. Later, we might like to optimize for the
678  // (common) contiguous case, for which we don't need to
679  // copy data into separate "their*" arrays (we can just
680  // use contiguous views of the global arrays).
681  ArrayRCP<GO> theirColInd (theirNumEntries);
682  ArrayRCP<scalar_type> theirValues (theirNumEntries);
683  // Copy Proc p's part of the matrix into the their*
684  // arrays. It's important that theirCurPos be updated
685  // _before_ k, otherwise theirCurPos will get the wrong
686  // number of entries per row (it should be for the row
687  // in the just-completed iteration, not for the next
688  // iteration's row).
689  local_ordinal_type theirCurPos = 0;
690  for (size_type k = 0; k < theirNumRows;
691  theirCurPos += theirNumEntriesPerRow[k], k++) {
692  const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
693  const GO theirRow = theirRows[k];
694  const local_ordinal_type curPos = rowPtr[theirRow];
695 
696  // Only copy if there are entries to copy, in order
697  // not to construct empty ranges for the ArrayRCP
698  // views.
699  if (curNumEntries > 0) {
700  ArrayView<GO> colIndView =
701  colInd (curPos, curNumEntries);
702  ArrayView<GO> theirColIndView =
703  theirColInd (theirCurPos, curNumEntries);
704  std::copy (colIndView.begin(), colIndView.end(),
705  theirColIndView.begin());
706 
707  ArrayView<scalar_type> valuesView =
708  values (curPos, curNumEntries);
709  ArrayView<scalar_type> theirValuesView =
710  theirValues (theirCurPos, curNumEntries);
711  std::copy (valuesView.begin(), valuesView.end(),
712  theirValuesView.begin());
713  }
714  }
715  // Send Proc p its column indices and values.
716  // Hopefully the cast to int doesn't overflow. This
717  // is unlikely, since it should fit in a LO, even
718  // though it is a GO.
719  send (*pComm, static_cast<int> (theirNumEntries),
720  theirColInd.getRawPtr(), p);
721  send (*pComm, static_cast<int> (theirNumEntries),
722  theirValues.getRawPtr(), p);
723 
724  if (debug) {
725  cerr << "-- Proc 0: Finished with proc " << p << endl;
726  }
727  } // If proc p owns at least one row
728  } // For each proc p not the root proc 0
729  } // If I'm (not) the root proc 0
730 
731  // Invalidate the input data to save space, since we don't
732  // need it anymore.
733  numEntriesPerRow = null;
734  rowPtr = null;
735  colInd = null;
736  values = null;
737 
738  if (debug && myRank == 0) {
739  cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
740  }
741 
742  // Allocate and fill in myRowPtr (the row pointer array for
743  // my rank's rows). We delay this until the end because we
744  // don't need it to compute anything else in distribute().
745  // Each proc can do this work for itself, since it only needs
746  // myNumEntriesPerRow to do so.
747  myRowPtr = arcp<size_t> (myNumRows+1);
748  myRowPtr[0] = 0;
749  for (size_type k = 1; k < myNumRows+1; ++k) {
750  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
751  }
752  if (extraDebug && debug) {
753  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
754  << ": myRowPtr[0.." << myNumRows << "] = [";
755  for (size_type k = 0; k < myNumRows+1; ++k) {
756  cerr << myRowPtr[k];
757  if (k < myNumRows) {
758  cerr << " ";
759  }
760  }
761  cerr << "]" << endl << endl;
762  }
763 
764  if (debug && myRank == 0) {
765  cerr << "-- Proc 0: Done with distribute" << endl;
766  }
767  }
768 
782  static Teuchos::RCP<sparse_matrix_type>
783  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
784  Teuchos::ArrayRCP<size_t>& myRowPtr,
785  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
786  Teuchos::ArrayRCP<scalar_type>& myValues,
787  const Teuchos::RCP<const map_type>& pRowMap,
788  const Teuchos::RCP<const map_type>& pRangeMap,
789  const Teuchos::RCP<const map_type>& pDomainMap,
790  const bool callFillComplete = true)
791  {
792  using Teuchos::ArrayView;
793  using Teuchos::null;
794  using Teuchos::RCP;
795  using Teuchos::rcp;
796  using std::cerr;
797  using std::endl;
798  // Typedef to make certain type declarations shorter.
799  typedef global_ordinal_type GO;
800 
801  // The row pointer array always has at least one entry, even
802  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
803  // and myValues would all be empty arrays in that degenerate
804  // case, but the row and domain maps would still be nonnull
805  // (though they would be trivial maps).
806  TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
807  "makeMatrix: myRowPtr array is null. "
808  "Please report this bug to the Tpetra developers.");
809  TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
810  "makeMatrix: domain map is null. "
811  "Please report this bug to the Tpetra developers.");
812  TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
813  "makeMatrix: range map is null. "
814  "Please report this bug to the Tpetra developers.");
815  TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
816  "makeMatrix: row map is null. "
817  "Please report this bug to the Tpetra developers.");
818 
819  // Construct the CrsMatrix, using the row map, with the
820  // constructor specifying the number of nonzeros for each row.
821  // Create with DynamicProfile, so that the fillComplete() can
822  // do first-touch reallocation (a NUMA (Non-Uniform Memory
823  // Access) optimization on multicore CPUs).
824  RCP<sparse_matrix_type> A =
825  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow,
826  DynamicProfile));
827 
828  // List of the global indices of my rows.
829  // They may or may not be contiguous.
830  ArrayView<const GO> myRows = pRowMap->getNodeElementList ();
831  const size_type myNumRows = myRows.size ();
832 
833  // Add this processor's matrix entries to the CrsMatrix.
834  const GO indexBase = pRowMap->getIndexBase ();
835  for (size_type i = 0; i < myNumRows; ++i) {
836  const size_type myCurPos = myRowPtr[i];
837  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
838  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
839  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
840 
841  // Modify the column indices in place to have the right index base.
842  for (size_type k = 0; k < curNumEntries; ++k) {
843  curColInd[k] += indexBase;
844  }
845  // Avoid constructing empty views of ArrayRCP objects.
846  if (curNumEntries > 0) {
847  A->insertGlobalValues (myRows[i], curColInd, curValues);
848  }
849  }
850  // We've entered in all our matrix entries, so we can delete
851  // the original data. This will save memory when we call
852  // fillComplete(), so that we never keep more than two copies
853  // of the matrix's data in memory at once.
854  myNumEntriesPerRow = null;
855  myRowPtr = null;
856  myColInd = null;
857  myValues = null;
858 
859  if (callFillComplete) {
860  A->fillComplete (pDomainMap, pRangeMap);
861  }
862  return A;
863  }
864 
870  static Teuchos::RCP<sparse_matrix_type>
871  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
872  Teuchos::ArrayRCP<size_t>& myRowPtr,
873  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
874  Teuchos::ArrayRCP<scalar_type>& myValues,
875  const Teuchos::RCP<const map_type>& pRowMap,
876  const Teuchos::RCP<const map_type>& pRangeMap,
877  const Teuchos::RCP<const map_type>& pDomainMap,
878  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
879  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
880  {
881  using Teuchos::ArrayView;
882  using Teuchos::null;
883  using Teuchos::RCP;
884  using Teuchos::rcp;
885  using std::cerr;
886  using std::endl;
887  // Typedef to make certain type declarations shorter.
888  typedef global_ordinal_type GO;
889 
890  // The row pointer array always has at least one entry, even
891  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
892  // and myValues would all be empty arrays in that degenerate
893  // case, but the row and domain maps would still be nonnull
894  // (though they would be trivial maps).
895  TEUCHOS_TEST_FOR_EXCEPTION(
896  myRowPtr.is_null(), std::logic_error,
897  "makeMatrix: myRowPtr array is null. "
898  "Please report this bug to the Tpetra developers.");
899  TEUCHOS_TEST_FOR_EXCEPTION(
900  pDomainMap.is_null(), std::logic_error,
901  "makeMatrix: domain map is null. "
902  "Please report this bug to the Tpetra developers.");
903  TEUCHOS_TEST_FOR_EXCEPTION(
904  pRangeMap.is_null(), std::logic_error,
905  "makeMatrix: range map is null. "
906  "Please report this bug to the Tpetra developers.");
907  TEUCHOS_TEST_FOR_EXCEPTION(
908  pRowMap.is_null(), std::logic_error,
909  "makeMatrix: row map is null. "
910  "Please report this bug to the Tpetra developers.");
911 
912  // Construct the CrsMatrix, using the row map, with the
913  // constructor specifying the number of nonzeros for each row.
914  // Create with DynamicProfile, so that the fillComplete() can
915  // do first-touch reallocation (a NUMA (Non-Uniform Memory
916  // Access) optimization on multicore CPUs).
917  RCP<sparse_matrix_type> A =
918  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow,
919  DynamicProfile, constructorParams));
920 
921  // List of the global indices of my rows.
922  // They may or may not be contiguous.
923  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
924  const size_type myNumRows = myRows.size();
925 
926  // Add this processor's matrix entries to the CrsMatrix.
927  const GO indexBase = pRowMap->getIndexBase ();
928  for (size_type i = 0; i < myNumRows; ++i) {
929  const size_type myCurPos = myRowPtr[i];
930  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
931  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
932  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
933 
934  // Modify the column indices in place to have the right index base.
935  for (size_type k = 0; k < curNumEntries; ++k) {
936  curColInd[k] += indexBase;
937  }
938  if (curNumEntries > 0) {
939  A->insertGlobalValues (myRows[i], curColInd, curValues);
940  }
941  }
942  // We've entered in all our matrix entries, so we can delete
943  // the original data. This will save memory when we call
944  // fillComplete(), so that we never keep more than two copies
945  // of the matrix's data in memory at once.
946  myNumEntriesPerRow = null;
947  myRowPtr = null;
948  myColInd = null;
949  myValues = null;
950 
951  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
952  return A;
953  }
954 
959  static Teuchos::RCP<sparse_matrix_type>
960  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
961  Teuchos::ArrayRCP<size_t>& myRowPtr,
962  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
963  Teuchos::ArrayRCP<scalar_type>& myValues,
964  const Teuchos::RCP<const map_type>& rowMap,
965  Teuchos::RCP<const map_type>& colMap,
966  const Teuchos::RCP<const map_type>& domainMap,
967  const Teuchos::RCP<const map_type>& rangeMap,
968  const bool callFillComplete = true)
969  {
970  using Teuchos::ArrayView;
971  using Teuchos::as;
972  using Teuchos::null;
973  using Teuchos::RCP;
974  using Teuchos::rcp;
975  typedef global_ordinal_type GO;
976  typedef typename ArrayView<const GO>::size_type size_type;
977 
978  // Construct the CrsMatrix.
979  //
980  // Create with DynamicProfile, so that the fillComplete() can
981  // do first-touch reallocation.
982  RCP<sparse_matrix_type> A; // the matrix to return.
983  if (colMap.is_null ()) { // the user didn't provide a column Map
984  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow, DynamicProfile));
985  } else { // the user provided a column Map
986  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow, DynamicProfile));
987  }
988 
989  // List of the global indices of my rows.
990  // They may or may not be contiguous.
991  ArrayView<const GO> myRows = rowMap->getNodeElementList ();
992  const size_type myNumRows = myRows.size ();
993 
994  // Add this process' matrix entries to the CrsMatrix.
995  const GO indexBase = rowMap->getIndexBase ();
996  for (size_type i = 0; i < myNumRows; ++i) {
997  const size_type myCurPos = myRowPtr[i];
998  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
999  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
1000  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
1001 
1002  // Modify the column indices in place to have the right index base.
1003  for (size_type k = 0; k < curNumEntries; ++k) {
1004  curColInd[k] += indexBase;
1005  }
1006  if (curNumEntries > 0) {
1007  A->insertGlobalValues (myRows[i], curColInd, curValues);
1008  }
1009  }
1010  // We've entered in all our matrix entries, so we can delete
1011  // the original data. This will save memory when we call
1012  // fillComplete(), so that we never keep more than two copies
1013  // of the matrix's data in memory at once.
1014  myNumEntriesPerRow = null;
1015  myRowPtr = null;
1016  myColInd = null;
1017  myValues = null;
1018 
1019  if (callFillComplete) {
1020  A->fillComplete (domainMap, rangeMap);
1021  if (colMap.is_null ()) {
1022  colMap = A->getColMap ();
1023  }
1024  }
1025  return A;
1026  }
1027 
1028  private:
1029 
1046  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1047  readBanner (std::istream& in,
1048  size_t& lineNumber,
1049  const bool tolerant=false,
1050  const bool debug=false,
1051  const bool isGraph=false)
1052  {
1053  using Teuchos::MatrixMarket::Banner;
1054  using Teuchos::RCP;
1055  using Teuchos::rcp;
1056  using std::cerr;
1057  using std::endl;
1058  typedef Teuchos::ScalarTraits<scalar_type> STS;
1059 
1060  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1061  std::string line; // If read from stream successful: the Banner line
1062 
1063  // Try to read a line from the input stream.
1064  const bool readFailed = ! getline(in, line);
1065  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1066  "Failed to get Matrix Market banner line from input.");
1067 
1068  // We read a line from the input stream.
1069  lineNumber++;
1070 
1071  // Assume that the line we found is the Banner line.
1072  try {
1073  pBanner = rcp (new Banner (line, tolerant));
1074  } catch (std::exception& e) {
1075  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1076  "Matrix Market banner line contains syntax error(s): "
1077  << e.what());
1078  }
1079  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1080  std::invalid_argument, "The Matrix Market file does not contain "
1081  "matrix data. Its Banner (first) line says that its object type is \""
1082  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1083 
1084  // Validate the data type of the matrix, with respect to the
1085  // Scalar type of the CrsMatrix entries.
1086  TEUCHOS_TEST_FOR_EXCEPTION(
1087  ! STS::isComplex && pBanner->dataType() == "complex",
1088  std::invalid_argument,
1089  "The Matrix Market file contains complex-valued data, but you are "
1090  "trying to read it into a matrix containing entries of the real-"
1091  "valued Scalar type \""
1092  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1093  TEUCHOS_TEST_FOR_EXCEPTION(
1094  !isGraph &&
1095  pBanner->dataType() != "real" &&
1096  pBanner->dataType() != "complex" &&
1097  pBanner->dataType() != "integer",
1098  std::invalid_argument,
1099  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1100  "Matrix Market file may not contain a \"pattern\" matrix. A "
1101  "pattern matrix is really just a graph with no weights. It "
1102  "should be stored in a CrsGraph, not a CrsMatrix.");
1103 
1104  TEUCHOS_TEST_FOR_EXCEPTION(
1105  isGraph &&
1106  pBanner->dataType() != "pattern",
1107  std::invalid_argument,
1108  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1109  "Matrix Market file must contain a \"pattern\" matrix.");
1110 
1111  return pBanner;
1112  }
1113 
1136  static Teuchos::Tuple<global_ordinal_type, 3>
1137  readCoordDims (std::istream& in,
1138  size_t& lineNumber,
1139  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1140  const Teuchos::RCP<const comm_type>& pComm,
1141  const bool tolerant = false,
1142  const bool debug = false)
1143  {
1144  using Teuchos::MatrixMarket::readCoordinateDimensions;
1145  using Teuchos::Tuple;
1146 
1147  // Packed coordinate matrix dimensions (numRows, numCols,
1148  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1149  // ranks.
1150  Tuple<global_ordinal_type, 3> dims;
1151 
1152  // Read in the coordinate matrix dimensions from the input
1153  // stream. "success" tells us whether reading in the
1154  // coordinate matrix dimensions succeeded ("Guilty unless
1155  // proven innocent").
1156  bool success = false;
1157  if (pComm->getRank() == 0) {
1158  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1159  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1160  "only accepts \"coordinate\" (sparse) matrix data.");
1161  // Unpacked coordinate matrix dimensions
1162  global_ordinal_type numRows, numCols, numNonzeros;
1163  // Only MPI Rank 0 reads from the input stream
1164  success = readCoordinateDimensions (in, numRows, numCols,
1165  numNonzeros, lineNumber,
1166  tolerant);
1167  // Pack up the data into a Tuple so we can send them with
1168  // one broadcast instead of three.
1169  dims[0] = numRows;
1170  dims[1] = numCols;
1171  dims[2] = numNonzeros;
1172  }
1173  // Only Rank 0 did the reading, so it decides success.
1174  //
1175  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1176  // to send bools. For now, we convert to/from int instead,
1177  // using the usual "true is 1, false is 0" encoding.
1178  {
1179  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1180  Teuchos::broadcast (*pComm, 0, &the_success);
1181  success = (the_success == 1);
1182  }
1183  if (success) {
1184  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1185  // to all the other MPI ranks.
1186  Teuchos::broadcast (*pComm, 0, dims);
1187  }
1188  else {
1189  // Perhaps in tolerant mode, we could set all the
1190  // dimensions to zero for now, and deduce correct
1191  // dimensions by reading all of the file's entries and
1192  // computing the max(row index) and max(column index).
1193  // However, for now we just error out in that case.
1194  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1195  "Error reading Matrix Market sparse matrix: failed to read "
1196  "coordinate matrix dimensions.");
1197  }
1198  return dims;
1199  }
1200 
1211  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1212 
1213  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1214 
1240  static Teuchos::RCP<adder_type>
1241  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1242  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1243  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1244  const bool tolerant=false,
1245  const bool debug=false)
1246  {
1247  if (pComm->getRank () == 0) {
1248  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1249  global_ordinal_type>
1250  raw_adder_type;
1251  Teuchos::RCP<raw_adder_type> pRaw =
1252  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1253  tolerant, debug));
1254  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1255  }
1256  else {
1257  return Teuchos::null;
1258  }
1259  }
1260 
1286  static Teuchos::RCP<graph_adder_type>
1287  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1288  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1289  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1290  const bool tolerant=false,
1291  const bool debug=false)
1292  {
1293  if (pComm->getRank () == 0) {
1294  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1295  Teuchos::RCP<raw_adder_type> pRaw =
1296  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1297  tolerant, debug));
1298  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1299  }
1300  else {
1301  return Teuchos::null;
1302  }
1303  }
1304 
1306  static Teuchos::RCP<sparse_graph_type>
1307  readSparseGraphHelper (std::istream& in,
1308  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1309  const Teuchos::RCP<node_type>& pNode,
1310  const Teuchos::RCP<const map_type>& rowMap,
1311  Teuchos::RCP<const map_type>& colMap,
1312  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1313  const bool tolerant,
1314  const bool debug)
1315  {
1316  using Teuchos::MatrixMarket::Banner;
1317  using Teuchos::RCP;
1318  using Teuchos::ptr;
1319  using Teuchos::Tuple;
1320  using std::cerr;
1321  using std::endl;
1322 
1323  const int myRank = pComm->getRank ();
1324  const int rootRank = 0;
1325 
1326  // Current line number in the input stream. Various calls
1327  // will modify this depending on the number of lines that are
1328  // read from the input stream. Only Rank 0 modifies this.
1329  size_t lineNumber = 1;
1330 
1331  if (debug && myRank == rootRank) {
1332  cerr << "Matrix Market reader: readGraph:" << endl
1333  << "-- Reading banner line" << endl;
1334  }
1335 
1336  // The "Banner" tells you whether the input stream represents
1337  // a sparse matrix, the symmetry type of the matrix, and the
1338  // type of the data it contains.
1339  //
1340  // pBanner will only be nonnull on MPI Rank 0. It will be
1341  // null on all other MPI processes.
1342  RCP<const Banner> pBanner;
1343  {
1344  // We read and validate the Banner on Proc 0, but broadcast
1345  // the validation result to all processes.
1346  // Teuchos::broadcast doesn't currently work with bool, so
1347  // we use int (true -> 1, false -> 0).
1348  int bannerIsCorrect = 1;
1349  std::ostringstream errMsg;
1350 
1351  if (myRank == rootRank) {
1352  // Read the Banner line from the input stream.
1353  try {
1354  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1355  }
1356  catch (std::exception& e) {
1357  errMsg << "Attempt to read the Matrix Market file's Banner line "
1358  "threw an exception: " << e.what();
1359  bannerIsCorrect = 0;
1360  }
1361 
1362  if (bannerIsCorrect) {
1363  // Validate the Banner for the case of a sparse graph.
1364  // We validate on Proc 0, since it reads the Banner.
1365 
1366  // In intolerant mode, the matrix type must be "coordinate".
1367  if (! tolerant && pBanner->matrixType() != "coordinate") {
1368  bannerIsCorrect = 0;
1369  errMsg << "The Matrix Market input file must contain a "
1370  "\"coordinate\"-format sparse graph in order to create a "
1371  "Tpetra::CrsGraph object from it, but the file's matrix "
1372  "type is \"" << pBanner->matrixType() << "\" instead.";
1373  }
1374  // In tolerant mode, we allow the matrix type to be
1375  // anything other than "array" (which would mean that
1376  // the file contains a dense matrix).
1377  if (tolerant && pBanner->matrixType() == "array") {
1378  bannerIsCorrect = 0;
1379  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1380  "format sparse graph in order to create a Tpetra::CrsGraph "
1381  "object from it, but the file's matrix type is \"array\" "
1382  "instead. That probably means the file contains dense matrix "
1383  "data.";
1384  }
1385  }
1386  } // Proc 0: Done reading the Banner, hopefully successfully.
1387 
1388  // Broadcast from Proc 0 whether the Banner was read correctly.
1389  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1390 
1391  // If the Banner is invalid, all processes throw an
1392  // exception. Only Proc 0 gets the exception message, but
1393  // that's OK, since the main point is to "stop the world"
1394  // (rather than throw an exception on one process and leave
1395  // the others hanging).
1396  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1397  std::invalid_argument, errMsg.str ());
1398  } // Done reading the Banner line and broadcasting success.
1399  if (debug && myRank == rootRank) {
1400  cerr << "-- Reading dimensions line" << endl;
1401  }
1402 
1403  // Read the graph dimensions from the Matrix Market metadata.
1404  // dims = (numRows, numCols, numEntries). Proc 0 does the
1405  // reading, but it broadcasts the results to all MPI
1406  // processes. Thus, readCoordDims() is a collective
1407  // operation. It does a collective check for correctness too.
1408  Tuple<global_ordinal_type, 3> dims =
1409  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1410 
1411  if (debug && myRank == rootRank) {
1412  cerr << "-- Making Adder for collecting graph data" << endl;
1413  }
1414 
1415  // "Adder" object for collecting all the sparse graph entries
1416  // from the input stream. This is only nonnull on Proc 0.
1417  // The Adder internally converts the one-based indices (native
1418  // Matrix Market format) into zero-based indices.
1419  RCP<graph_adder_type> pAdder =
1420  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1421 
1422  if (debug && myRank == rootRank) {
1423  cerr << "-- Reading graph data" << endl;
1424  }
1425  //
1426  // Read the graph entries from the input stream on Proc 0.
1427  //
1428  {
1429  // We use readSuccess to broadcast the results of the read
1430  // (succeeded or not) to all MPI processes. Since
1431  // Teuchos::broadcast doesn't currently know how to send
1432  // bools, we convert to int (true -> 1, false -> 0).
1433  int readSuccess = 1;
1434  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1435  if (myRank == rootRank) {
1436  try {
1437  // Reader for "coordinate" format sparse graph data.
1438  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1439  global_ordinal_type> reader_type;
1440  reader_type reader (pAdder);
1441 
1442  // Read the sparse graph entries.
1443  std::pair<bool, std::vector<size_t> > results =
1444  reader.read (in, lineNumber, tolerant, debug);
1445  readSuccess = results.first ? 1 : 0;
1446  }
1447  catch (std::exception& e) {
1448  readSuccess = 0;
1449  errMsg << e.what();
1450  }
1451  }
1452  broadcast (*pComm, rootRank, ptr (&readSuccess));
1453 
1454  // It would be nice to add a "verbose" flag, so that in
1455  // tolerant mode, we could log any bad line number(s) on
1456  // Proc 0. For now, we just throw if the read fails to
1457  // succeed.
1458  //
1459  // Question: If we're in tolerant mode, and if the read did
1460  // not succeed, should we attempt to call fillComplete()?
1461  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1462  "Failed to read the Matrix Market sparse graph file: "
1463  << errMsg.str());
1464  } // Done reading the graph entries (stored on Proc 0 for now)
1465 
1466  if (debug && myRank == rootRank) {
1467  cerr << "-- Successfully read the Matrix Market data" << endl;
1468  }
1469 
1470  // In tolerant mode, we need to rebroadcast the graph
1471  // dimensions, since they may be different after reading the
1472  // actual graph data. We only need to broadcast the number
1473  // of rows and columns. Only Rank 0 needs to know the actual
1474  // global number of entries, since (a) we need to merge
1475  // duplicates on Rank 0 first anyway, and (b) when we
1476  // distribute the entries, each rank other than Rank 0 will
1477  // only need to know how many entries it owns, not the total
1478  // number of entries.
1479  if (tolerant) {
1480  if (debug && myRank == rootRank) {
1481  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1482  << endl
1483  << "----- Dimensions before: "
1484  << dims[0] << " x " << dims[1]
1485  << endl;
1486  }
1487  // Packed coordinate graph dimensions (numRows, numCols).
1488  Tuple<global_ordinal_type, 2> updatedDims;
1489  if (myRank == rootRank) {
1490  // If one or more bottom rows of the graph contain no
1491  // entries, then the Adder will report that the number
1492  // of rows is less than that specified in the
1493  // metadata. We allow this case, and favor the
1494  // metadata so that the zero row(s) will be included.
1495  updatedDims[0] =
1496  std::max (dims[0], pAdder->getAdder()->numRows());
1497  updatedDims[1] = pAdder->getAdder()->numCols();
1498  }
1499  broadcast (*pComm, rootRank, updatedDims);
1500  dims[0] = updatedDims[0];
1501  dims[1] = updatedDims[1];
1502  if (debug && myRank == rootRank) {
1503  cerr << "----- Dimensions after: " << dims[0] << " x "
1504  << dims[1] << endl;
1505  }
1506  }
1507  else {
1508  // In strict mode, we require that the graph's metadata and
1509  // its actual data agree, at least somewhat. In particular,
1510  // the number of rows must agree, since otherwise we cannot
1511  // distribute the graph correctly.
1512 
1513  // Teuchos::broadcast() doesn't know how to broadcast bools,
1514  // so we use an int with the standard 1 == true, 0 == false
1515  // encoding.
1516  int dimsMatch = 1;
1517  if (myRank == rootRank) {
1518  // If one or more bottom rows of the graph contain no
1519  // entries, then the Adder will report that the number of
1520  // rows is less than that specified in the metadata. We
1521  // allow this case, and favor the metadata, but do not
1522  // allow the Adder to think there are more rows in the
1523  // graph than the metadata says.
1524  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1525  dimsMatch = 0;
1526  }
1527  }
1528  broadcast (*pComm, 0, ptr (&dimsMatch));
1529  if (dimsMatch == 0) {
1530  // We're in an error state anyway, so we might as well
1531  // work a little harder to print an informative error
1532  // message.
1533  //
1534  // Broadcast the Adder's idea of the graph dimensions
1535  // from Proc 0 to all processes.
1536  Tuple<global_ordinal_type, 2> addersDims;
1537  if (myRank == rootRank) {
1538  addersDims[0] = pAdder->getAdder()->numRows();
1539  addersDims[1] = pAdder->getAdder()->numCols();
1540  }
1541  broadcast (*pComm, 0, addersDims);
1542  TEUCHOS_TEST_FOR_EXCEPTION(
1543  dimsMatch == 0, std::runtime_error,
1544  "The graph metadata says that the graph is " << dims[0] << " x "
1545  << dims[1] << ", but the actual data says that the graph is "
1546  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1547  "data includes more rows than reported in the metadata. This "
1548  "is not allowed when parsing in strict mode. Parse the graph in "
1549  "tolerant mode to ignore the metadata when it disagrees with the "
1550  "data.");
1551  }
1552  } // Matrix dimensions (# rows, # cols, # entries) agree.
1553 
1554  // Create a map describing a distribution where the root owns EVERYTHING
1555  RCP<map_type> proc0Map;
1556  global_ordinal_type indexBase;
1557  if(Teuchos::is_null(rowMap)) {
1558  indexBase = 0;
1559  }
1560  else {
1561  indexBase = rowMap->getIndexBase();
1562  }
1563  if(myRank == rootRank) {
1564  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm,pNode));
1565  }
1566  else {
1567  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm,pNode));
1568  }
1569 
1570  // Create the graph where the root owns EVERYTHING
1571  RCP<sparse_graph_type> proc0Graph =
1572  rcp(new sparse_graph_type(proc0Map,0,DynamicProfile,constructorParams));
1573  if(myRank == rootRank) {
1574  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1575 
1576  // Get the entries
1577  const std::vector<element_type>& entries =
1578  pAdder->getAdder()->getEntries();
1579 
1580  // Insert them one at a time
1581  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1582  const element_type& curEntry = entries[curPos];
1583  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1584  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1585  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1586  proc0Graph->insertGlobalIndices(curRow,colView);
1587  }
1588  }
1589  proc0Graph->fillComplete();
1590 
1591  RCP<sparse_graph_type> distGraph;
1592  if(Teuchos::is_null(rowMap))
1593  {
1594  // Create a map describing the distribution we actually want
1595  RCP<map_type> distMap =
1596  rcp(new map_type(dims[0],0,pComm,GloballyDistributed,pNode));
1597 
1598  // Create the graph with that distribution too
1599  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,DynamicProfile,constructorParams));
1600 
1601  // Create an importer/exporter/vandelay to redistribute the graph
1603  import_type importer (proc0Map, distMap);
1604 
1605  // Import the data
1606  distGraph->doImport(*proc0Graph,importer,INSERT);
1607  }
1608  else {
1609  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,DynamicProfile,constructorParams));
1610 
1611  // Create an importer/exporter/vandelay to redistribute the graph
1613  import_type importer (proc0Map, rowMap);
1614 
1615  // Import the data
1616  distGraph->doImport(*proc0Graph,importer,INSERT);
1617  }
1618 
1619  return distGraph;
1620  }
1621 
1622  public:
1646  static Teuchos::RCP<sparse_graph_type>
1647  readSparseGraphFile (const std::string& filename,
1648  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1649  const bool callFillComplete=true,
1650  const bool tolerant=false,
1651  const bool debug=false)
1652  {
1653  // Call the overload below.
1654  return readSparseGraphFile (filename, pComm, Teuchos::null,
1655  callFillComplete, tolerant, debug);
1656  }
1657 
1664  static Teuchos::RCP<sparse_graph_type>
1665  readSparseGraphFile (const std::string& filename,
1666  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1667  const Teuchos::RCP<node_type>& node,
1668  const bool callFillComplete=true,
1669  const bool tolerant=false,
1670  const bool debug=false)
1671  {
1672  using Teuchos::broadcast;
1673  using Teuchos::outArg;
1674 
1675  // Only open the file on Process 0. Test carefully to make
1676  // sure that the file opened successfully (and broadcast that
1677  // result to all processes to prevent a hang on exception
1678  // throw), since it's a common mistake to misspell a filename.
1679  std::ifstream in;
1680  int opened = 0;
1681  if (comm->getRank () == 0) {
1682  try {
1683  in.open (filename.c_str ());
1684  opened = 1;
1685  }
1686  catch (...) {
1687  opened = 0;
1688  }
1689  }
1690  broadcast<int, int> (*comm, 0, outArg (opened));
1691  TEUCHOS_TEST_FOR_EXCEPTION
1692  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1693  "Failed to open file \"" << filename << "\" on Process 0.");
1694  return readSparseGraph (in, comm, node, callFillComplete,
1695  tolerant, debug);
1696  // We can rely on the destructor of the input stream to close
1697  // the file on scope exit, even if readSparseGraph() throws an
1698  // exception.
1699  }
1700 
1729  static Teuchos::RCP<sparse_graph_type>
1730  readSparseGraphFile (const std::string& filename,
1731  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1732  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1733  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1734  const bool tolerant=false,
1735  const bool debug=false)
1736  {
1737  // Call the overload below.
1738  return readSparseGraphFile (filename, pComm, Teuchos::null,
1739  constructorParams, fillCompleteParams,
1740  tolerant, debug);
1741  }
1742 
1749  static Teuchos::RCP<sparse_graph_type>
1750  readSparseGraphFile (const std::string& filename,
1751  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1752  const Teuchos::RCP<node_type>& pNode,
1753  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1754  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1755  const bool tolerant=false,
1756  const bool debug=false)
1757  {
1758  using Teuchos::broadcast;
1759  using Teuchos::outArg;
1760 
1761  // Only open the file on Process 0. Test carefully to make
1762  // sure that the file opened successfully (and broadcast that
1763  // result to all processes to prevent a hang on exception
1764  // throw), since it's a common mistake to misspell a filename.
1765  std::ifstream in;
1766  int opened = 0;
1767  if (pComm->getRank () == 0) {
1768  try {
1769  in.open (filename.c_str ());
1770  opened = 1;
1771  }
1772  catch (...) {
1773  opened = 0;
1774  }
1775  }
1776  broadcast<int, int> (*pComm, 0, outArg (opened));
1777  TEUCHOS_TEST_FOR_EXCEPTION
1778  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1779  "Failed to open file \"" << filename << "\" on Process 0.");
1780  if (pComm->getRank () == 0) { // only open the input file on Process 0
1781  in.open (filename.c_str ());
1782  }
1783  return readSparseGraph (in, pComm, pNode, constructorParams,
1784  fillCompleteParams, tolerant, debug);
1785  // We can rely on the destructor of the input stream to close
1786  // the file on scope exit, even if readSparseGraph() throws an
1787  // exception.
1788  }
1789 
1827  static Teuchos::RCP<sparse_graph_type>
1828  readSparseGraphFile (const std::string& filename,
1829  const Teuchos::RCP<const map_type>& rowMap,
1830  Teuchos::RCP<const map_type>& colMap,
1831  const Teuchos::RCP<const map_type>& domainMap,
1832  const Teuchos::RCP<const map_type>& rangeMap,
1833  const bool callFillComplete=true,
1834  const bool tolerant=false,
1835  const bool debug=false)
1836  {
1837  using Teuchos::broadcast;
1838  using Teuchos::Comm;
1839  using Teuchos::outArg;
1840  using Teuchos::RCP;
1841 
1842  TEUCHOS_TEST_FOR_EXCEPTION
1843  (rowMap.is_null (), std::invalid_argument,
1844  "Input rowMap must be nonnull.");
1845  RCP<const Comm<int> > comm = rowMap->getComm ();
1846  if (comm.is_null ()) {
1847  // If the input communicator is null on some process, then
1848  // that process does not participate in the collective.
1849  return Teuchos::null;
1850  }
1851 
1852  // Only open the file on Process 0. Test carefully to make
1853  // sure that the file opened successfully (and broadcast that
1854  // result to all processes to prevent a hang on exception
1855  // throw), since it's a common mistake to misspell a filename.
1856  std::ifstream in;
1857  int opened = 0;
1858  if (comm->getRank () == 0) {
1859  try {
1860  in.open (filename.c_str ());
1861  opened = 1;
1862  }
1863  catch (...) {
1864  opened = 0;
1865  }
1866  }
1867  broadcast<int, int> (*comm, 0, outArg (opened));
1868  TEUCHOS_TEST_FOR_EXCEPTION
1869  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1870  "Failed to open file \"" << filename << "\" on Process 0.");
1871  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1872  callFillComplete, tolerant, debug);
1873  }
1874 
1900  static Teuchos::RCP<sparse_graph_type>
1901  readSparseGraph (std::istream& in,
1902  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1903  const bool callFillComplete=true,
1904  const bool tolerant=false,
1905  const bool debug=false)
1906  {
1907  // Call the overload below.
1908  return readSparseGraph (in, pComm, Teuchos::null, callFillComplete,
1909  tolerant, debug);
1910  }
1911 
1913  static Teuchos::RCP<sparse_graph_type>
1914  readSparseGraph (std::istream& in,
1915  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1916  const Teuchos::RCP<node_type>& pNode,
1917  const bool callFillComplete=true,
1918  const bool tolerant=false,
1919  const bool debug=false)
1920  {
1921  Teuchos::RCP<const map_type> fakeRowMap;
1922  Teuchos::RCP<const map_type> fakeColMap;
1923  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1924 
1925  Teuchos::RCP<sparse_graph_type> graph =
1926  readSparseGraphHelper (in, pComm, pNode, fakeRowMap, fakeColMap,
1927  fakeCtorParams, tolerant, debug);
1928  if (callFillComplete) {
1929  graph->fillComplete ();
1930  }
1931  return graph;
1932  }
1933 
1963  static Teuchos::RCP<sparse_graph_type>
1964  readSparseGraph (std::istream& in,
1965  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1966  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1967  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1968  const bool tolerant=false,
1969  const bool debug=false)
1970  {
1971  // Call the overload below.
1972  return readSparseGraph (in, pComm, Teuchos::null, constructorParams,
1973  fillCompleteParams, tolerant, debug);
1974  }
1975 
1977  static Teuchos::RCP<sparse_graph_type>
1978  readSparseGraph (std::istream& in,
1979  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1980  const Teuchos::RCP<node_type>& pNode,
1981  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1982  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1983  const bool tolerant=false,
1984  const bool debug=false)
1985  {
1986  Teuchos::RCP<const map_type> fakeRowMap;
1987  Teuchos::RCP<const map_type> fakeColMap;
1988  Teuchos::RCP<sparse_graph_type> graph =
1989  readSparseGraphHelper (in, pComm, pNode, fakeRowMap, fakeColMap,
1990  constructorParams, tolerant, debug);
1991  graph->fillComplete (fillCompleteParams);
1992  return graph;
1993  }
1994 
2035  static Teuchos::RCP<sparse_graph_type>
2036  readSparseGraph (std::istream& in,
2037  const Teuchos::RCP<const map_type>& rowMap,
2038  Teuchos::RCP<const map_type>& colMap,
2039  const Teuchos::RCP<const map_type>& domainMap,
2040  const Teuchos::RCP<const map_type>& rangeMap,
2041  const bool callFillComplete=true,
2042  const bool tolerant=false,
2043  const bool debug=false)
2044  {
2045  Teuchos::RCP<sparse_graph_type> graph =
2046  readSparseGraphHelper (in, rowMap->getComm (), rowMap->getNode (),
2047  rowMap, colMap, Teuchos::null, tolerant,
2048  debug);
2049  if (callFillComplete) {
2050  graph->fillComplete (domainMap, rangeMap);
2051  }
2052  return graph;
2053  }
2054 
2078  static Teuchos::RCP<sparse_matrix_type>
2079  readSparseFile (const std::string& filename,
2080  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2081  const bool callFillComplete=true,
2082  const bool tolerant=false,
2083  const bool debug=false)
2084  {
2085  return readSparseFile (filename, pComm, Teuchos::null, callFillComplete, tolerant, debug);
2086  }
2087 
2089  static Teuchos::RCP<sparse_matrix_type>
2090  readSparseFile (const std::string& filename,
2091  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2092  const Teuchos::RCP<node_type>& pNode,
2093  const bool callFillComplete=true,
2094  const bool tolerant=false,
2095  const bool debug=false)
2096  {
2097  const int myRank = pComm->getRank ();
2098  std::ifstream in;
2099 
2100  // Only open the file on Rank 0.
2101  if (myRank == 0) {
2102  in.open (filename.c_str ());
2103  }
2104  // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2105  // opening the file succeeded, before continuing. That will
2106  // avoid hangs if the read doesn't work. On the other hand,
2107  // readSparse could do that too, by checking the status of the
2108  // std::ostream.
2109 
2110  return readSparse (in, pComm, pNode, callFillComplete, tolerant, debug);
2111  // We can rely on the destructor of the input stream to close
2112  // the file on scope exit, even if readSparse() throws an
2113  // exception.
2114  }
2115 
2144  static Teuchos::RCP<sparse_matrix_type>
2145  readSparseFile (const std::string& filename,
2146  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2147  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2148  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2149  const bool tolerant=false,
2150  const bool debug=false)
2151  {
2152  return readSparseFile (filename, pComm, Teuchos::null,
2153  constructorParams, fillCompleteParams,
2154  tolerant, debug);
2155  }
2156 
2158  static Teuchos::RCP<sparse_matrix_type>
2159  readSparseFile (const std::string& filename,
2160  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2161  const Teuchos::RCP<node_type>& pNode,
2162  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2163  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2164  const bool tolerant=false,
2165  const bool debug=false)
2166  {
2167  std::ifstream in;
2168  if (pComm->getRank () == 0) { // only open on Process 0
2169  in.open (filename.c_str ());
2170  }
2171  return readSparse (in, pComm, pNode, constructorParams,
2172  fillCompleteParams, tolerant, debug);
2173  }
2174 
2212  static Teuchos::RCP<sparse_matrix_type>
2213  readSparseFile (const std::string& filename,
2214  const Teuchos::RCP<const map_type>& rowMap,
2215  Teuchos::RCP<const map_type>& colMap,
2216  const Teuchos::RCP<const map_type>& domainMap,
2217  const Teuchos::RCP<const map_type>& rangeMap,
2218  const bool callFillComplete=true,
2219  const bool tolerant=false,
2220  const bool debug=false)
2221  {
2222  using Teuchos::broadcast;
2223  using Teuchos::Comm;
2224  using Teuchos::outArg;
2225  using Teuchos::RCP;
2226 
2227  TEUCHOS_TEST_FOR_EXCEPTION(
2228  rowMap.is_null (), std::invalid_argument,
2229  "Row Map must be nonnull.");
2230 
2231  RCP<const Comm<int> > comm = rowMap->getComm ();
2232  const int myRank = comm->getRank ();
2233 
2234  // Only open the file on Process 0. Test carefully to make
2235  // sure that the file opened successfully (and broadcast that
2236  // result to all processes to prevent a hang on exception
2237  // throw), since it's a common mistake to misspell a filename.
2238  std::ifstream in;
2239  int opened = 0;
2240  if (myRank == 0) {
2241  try {
2242  in.open (filename.c_str ());
2243  opened = 1;
2244  }
2245  catch (...) {
2246  opened = 0;
2247  }
2248  }
2249  broadcast<int, int> (*comm, 0, outArg (opened));
2250  TEUCHOS_TEST_FOR_EXCEPTION(
2251  opened == 0, std::runtime_error,
2252  "readSparseFile: Failed to open file \"" << filename << "\" on "
2253  "Process 0.");
2254  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2255  callFillComplete, tolerant, debug);
2256  }
2257 
2283  static Teuchos::RCP<sparse_matrix_type>
2284  readSparse (std::istream& in,
2285  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2286  const bool callFillComplete=true,
2287  const bool tolerant=false,
2288  const bool debug=false)
2289  {
2290  return readSparse (in, pComm, Teuchos::null, callFillComplete, tolerant, debug);
2291  }
2292 
2294  static Teuchos::RCP<sparse_matrix_type>
2295  readSparse (std::istream& in,
2296  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2297  const Teuchos::RCP<node_type>& pNode,
2298  const bool callFillComplete=true,
2299  const bool tolerant=false,
2300  const bool debug=false)
2301  {
2302  using Teuchos::MatrixMarket::Banner;
2303  using Teuchos::arcp;
2304  using Teuchos::ArrayRCP;
2305  using Teuchos::broadcast;
2306  using Teuchos::null;
2307  using Teuchos::ptr;
2308  using Teuchos::RCP;
2309  using Teuchos::REDUCE_MAX;
2310  using Teuchos::reduceAll;
2311  using Teuchos::Tuple;
2312  using std::cerr;
2313  using std::endl;
2314  typedef Teuchos::ScalarTraits<scalar_type> STS;
2315 
2316  const bool extraDebug = false;
2317  const int myRank = pComm->getRank ();
2318  const int rootRank = 0;
2319 
2320  // Current line number in the input stream. Various calls
2321  // will modify this depending on the number of lines that are
2322  // read from the input stream. Only Rank 0 modifies this.
2323  size_t lineNumber = 1;
2324 
2325  if (debug && myRank == rootRank) {
2326  cerr << "Matrix Market reader: readSparse:" << endl
2327  << "-- Reading banner line" << endl;
2328  }
2329 
2330  // The "Banner" tells you whether the input stream represents
2331  // a sparse matrix, the symmetry type of the matrix, and the
2332  // type of the data it contains.
2333  //
2334  // pBanner will only be nonnull on MPI Rank 0. It will be
2335  // null on all other MPI processes.
2336  RCP<const Banner> pBanner;
2337  {
2338  // We read and validate the Banner on Proc 0, but broadcast
2339  // the validation result to all processes.
2340  // Teuchos::broadcast doesn't currently work with bool, so
2341  // we use int (true -> 1, false -> 0).
2342  int bannerIsCorrect = 1;
2343  std::ostringstream errMsg;
2344 
2345  if (myRank == rootRank) {
2346  // Read the Banner line from the input stream.
2347  try {
2348  pBanner = readBanner (in, lineNumber, tolerant, debug);
2349  }
2350  catch (std::exception& e) {
2351  errMsg << "Attempt to read the Matrix Market file's Banner line "
2352  "threw an exception: " << e.what();
2353  bannerIsCorrect = 0;
2354  }
2355 
2356  if (bannerIsCorrect) {
2357  // Validate the Banner for the case of a sparse matrix.
2358  // We validate on Proc 0, since it reads the Banner.
2359 
2360  // In intolerant mode, the matrix type must be "coordinate".
2361  if (! tolerant && pBanner->matrixType() != "coordinate") {
2362  bannerIsCorrect = 0;
2363  errMsg << "The Matrix Market input file must contain a "
2364  "\"coordinate\"-format sparse matrix in order to create a "
2365  "Tpetra::CrsMatrix object from it, but the file's matrix "
2366  "type is \"" << pBanner->matrixType() << "\" instead.";
2367  }
2368  // In tolerant mode, we allow the matrix type to be
2369  // anything other than "array" (which would mean that
2370  // the file contains a dense matrix).
2371  if (tolerant && pBanner->matrixType() == "array") {
2372  bannerIsCorrect = 0;
2373  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2374  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2375  "object from it, but the file's matrix type is \"array\" "
2376  "instead. That probably means the file contains dense matrix "
2377  "data.";
2378  }
2379  }
2380  } // Proc 0: Done reading the Banner, hopefully successfully.
2381 
2382  // Broadcast from Proc 0 whether the Banner was read correctly.
2383  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2384 
2385  // If the Banner is invalid, all processes throw an
2386  // exception. Only Proc 0 gets the exception message, but
2387  // that's OK, since the main point is to "stop the world"
2388  // (rather than throw an exception on one process and leave
2389  // the others hanging).
2390  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2391  std::invalid_argument, errMsg.str ());
2392  } // Done reading the Banner line and broadcasting success.
2393  if (debug && myRank == rootRank) {
2394  cerr << "-- Reading dimensions line" << endl;
2395  }
2396 
2397  // Read the matrix dimensions from the Matrix Market metadata.
2398  // dims = (numRows, numCols, numEntries). Proc 0 does the
2399  // reading, but it broadcasts the results to all MPI
2400  // processes. Thus, readCoordDims() is a collective
2401  // operation. It does a collective check for correctness too.
2402  Tuple<global_ordinal_type, 3> dims =
2403  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2404 
2405  if (debug && myRank == rootRank) {
2406  cerr << "-- Making Adder for collecting matrix data" << endl;
2407  }
2408 
2409  // "Adder" object for collecting all the sparse matrix entries
2410  // from the input stream. This is only nonnull on Proc 0.
2411  RCP<adder_type> pAdder =
2412  makeAdder (pComm, pBanner, dims, tolerant, debug);
2413 
2414  if (debug && myRank == rootRank) {
2415  cerr << "-- Reading matrix data" << endl;
2416  }
2417  //
2418  // Read the matrix entries from the input stream on Proc 0.
2419  //
2420  {
2421  // We use readSuccess to broadcast the results of the read
2422  // (succeeded or not) to all MPI processes. Since
2423  // Teuchos::broadcast doesn't currently know how to send
2424  // bools, we convert to int (true -> 1, false -> 0).
2425  int readSuccess = 1;
2426  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2427  if (myRank == rootRank) {
2428  try {
2429  // Reader for "coordinate" format sparse matrix data.
2430  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2431  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2432  reader_type reader (pAdder);
2433 
2434  // Read the sparse matrix entries.
2435  std::pair<bool, std::vector<size_t> > results =
2436  reader.read (in, lineNumber, tolerant, debug);
2437  readSuccess = results.first ? 1 : 0;
2438  }
2439  catch (std::exception& e) {
2440  readSuccess = 0;
2441  errMsg << e.what();
2442  }
2443  }
2444  broadcast (*pComm, rootRank, ptr (&readSuccess));
2445 
2446  // It would be nice to add a "verbose" flag, so that in
2447  // tolerant mode, we could log any bad line number(s) on
2448  // Proc 0. For now, we just throw if the read fails to
2449  // succeed.
2450  //
2451  // Question: If we're in tolerant mode, and if the read did
2452  // not succeed, should we attempt to call fillComplete()?
2453  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2454  "Failed to read the Matrix Market sparse matrix file: "
2455  << errMsg.str());
2456  } // Done reading the matrix entries (stored on Proc 0 for now)
2457 
2458  if (debug && myRank == rootRank) {
2459  cerr << "-- Successfully read the Matrix Market data" << endl;
2460  }
2461 
2462  // In tolerant mode, we need to rebroadcast the matrix
2463  // dimensions, since they may be different after reading the
2464  // actual matrix data. We only need to broadcast the number
2465  // of rows and columns. Only Rank 0 needs to know the actual
2466  // global number of entries, since (a) we need to merge
2467  // duplicates on Rank 0 first anyway, and (b) when we
2468  // distribute the entries, each rank other than Rank 0 will
2469  // only need to know how many entries it owns, not the total
2470  // number of entries.
2471  if (tolerant) {
2472  if (debug && myRank == rootRank) {
2473  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2474  << endl
2475  << "----- Dimensions before: "
2476  << dims[0] << " x " << dims[1]
2477  << endl;
2478  }
2479  // Packed coordinate matrix dimensions (numRows, numCols).
2480  Tuple<global_ordinal_type, 2> updatedDims;
2481  if (myRank == rootRank) {
2482  // If one or more bottom rows of the matrix contain no
2483  // entries, then the Adder will report that the number
2484  // of rows is less than that specified in the
2485  // metadata. We allow this case, and favor the
2486  // metadata so that the zero row(s) will be included.
2487  updatedDims[0] =
2488  std::max (dims[0], pAdder->getAdder()->numRows());
2489  updatedDims[1] = pAdder->getAdder()->numCols();
2490  }
2491  broadcast (*pComm, rootRank, updatedDims);
2492  dims[0] = updatedDims[0];
2493  dims[1] = updatedDims[1];
2494  if (debug && myRank == rootRank) {
2495  cerr << "----- Dimensions after: " << dims[0] << " x "
2496  << dims[1] << endl;
2497  }
2498  }
2499  else {
2500  // In strict mode, we require that the matrix's metadata and
2501  // its actual data agree, at least somewhat. In particular,
2502  // the number of rows must agree, since otherwise we cannot
2503  // distribute the matrix correctly.
2504 
2505  // Teuchos::broadcast() doesn't know how to broadcast bools,
2506  // so we use an int with the standard 1 == true, 0 == false
2507  // encoding.
2508  int dimsMatch = 1;
2509  if (myRank == rootRank) {
2510  // If one or more bottom rows of the matrix contain no
2511  // entries, then the Adder will report that the number of
2512  // rows is less than that specified in the metadata. We
2513  // allow this case, and favor the metadata, but do not
2514  // allow the Adder to think there are more rows in the
2515  // matrix than the metadata says.
2516  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2517  dimsMatch = 0;
2518  }
2519  }
2520  broadcast (*pComm, 0, ptr (&dimsMatch));
2521  if (dimsMatch == 0) {
2522  // We're in an error state anyway, so we might as well
2523  // work a little harder to print an informative error
2524  // message.
2525  //
2526  // Broadcast the Adder's idea of the matrix dimensions
2527  // from Proc 0 to all processes.
2528  Tuple<global_ordinal_type, 2> addersDims;
2529  if (myRank == rootRank) {
2530  addersDims[0] = pAdder->getAdder()->numRows();
2531  addersDims[1] = pAdder->getAdder()->numCols();
2532  }
2533  broadcast (*pComm, 0, addersDims);
2534  TEUCHOS_TEST_FOR_EXCEPTION(
2535  dimsMatch == 0, std::runtime_error,
2536  "The matrix metadata says that the matrix is " << dims[0] << " x "
2537  << dims[1] << ", but the actual data says that the matrix is "
2538  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2539  "data includes more rows than reported in the metadata. This "
2540  "is not allowed when parsing in strict mode. Parse the matrix in "
2541  "tolerant mode to ignore the metadata when it disagrees with the "
2542  "data.");
2543  }
2544  } // Matrix dimensions (# rows, # cols, # entries) agree.
2545 
2546  if (debug && myRank == rootRank) {
2547  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2548  }
2549 
2550  // Now that we've read in all the matrix entries from the
2551  // input stream into the adder on Proc 0, post-process them
2552  // into CSR format (still on Proc 0). This will facilitate
2553  // distributing them to all the processors.
2554  //
2555  // These arrays represent the global matrix data as a CSR
2556  // matrix (with numEntriesPerRow as redundant but convenient
2557  // metadata, since it's computable from rowPtr and vice
2558  // versa). They are valid only on Proc 0.
2559  ArrayRCP<size_t> numEntriesPerRow;
2560  ArrayRCP<size_t> rowPtr;
2561  ArrayRCP<global_ordinal_type> colInd;
2562  ArrayRCP<scalar_type> values;
2563 
2564  // Proc 0 first merges duplicate entries, and then converts
2565  // the coordinate-format matrix data to CSR.
2566  {
2567  int mergeAndConvertSucceeded = 1;
2568  std::ostringstream errMsg;
2569 
2570  if (myRank == rootRank) {
2571  try {
2572  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2573  global_ordinal_type> element_type;
2574 
2575  // Number of rows in the matrix. If we are in tolerant
2576  // mode, we've already synchronized dims with the actual
2577  // matrix data. If in strict mode, we should use dims
2578  // (as read from the file's metadata) rather than the
2579  // matrix data to determine the dimensions. (The matrix
2580  // data will claim fewer rows than the metadata, if one
2581  // or more rows have no entries stored in the file.)
2582  const size_type numRows = dims[0];
2583 
2584  // Additively merge duplicate matrix entries.
2585  pAdder->getAdder()->merge ();
2586 
2587  // Get a temporary const view of the merged matrix entries.
2588  const std::vector<element_type>& entries =
2589  pAdder->getAdder()->getEntries();
2590 
2591  // Number of matrix entries (after merging).
2592  const size_t numEntries = (size_t)entries.size();
2593 
2594  if (debug) {
2595  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2596  << " rows and numEntries=" << numEntries
2597  << " entries." << endl;
2598  }
2599 
2600  // Make space for the CSR matrix data. Converting to
2601  // CSR is easier if we fill numEntriesPerRow with zeros
2602  // at first.
2603  numEntriesPerRow = arcp<size_t> (numRows);
2604  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2605  rowPtr = arcp<size_t> (numRows+1);
2606  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2607  colInd = arcp<global_ordinal_type> (numEntries);
2608  values = arcp<scalar_type> (numEntries);
2609 
2610  // Convert from array-of-structs coordinate format to CSR
2611  // (compressed sparse row) format.
2612  global_ordinal_type prvRow = 0;
2613  size_t curPos = 0;
2614  rowPtr[0] = 0;
2615  for (curPos = 0; curPos < numEntries; ++curPos) {
2616  const element_type& curEntry = entries[curPos];
2617  const global_ordinal_type curRow = curEntry.rowIndex();
2618  TEUCHOS_TEST_FOR_EXCEPTION(
2619  curRow < prvRow, std::logic_error,
2620  "Row indices are out of order, even though they are supposed "
2621  "to be sorted. curRow = " << curRow << ", prvRow = "
2622  << prvRow << ", at curPos = " << curPos << ". Please report "
2623  "this bug to the Tpetra developers.");
2624  if (curRow > prvRow) {
2625  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2626  rowPtr[r] = curPos;
2627  }
2628  prvRow = curRow;
2629  }
2630  numEntriesPerRow[curRow]++;
2631  colInd[curPos] = curEntry.colIndex();
2632  values[curPos] = curEntry.value();
2633  }
2634  // rowPtr has one more entry than numEntriesPerRow. The
2635  // last entry of rowPtr is the number of entries in
2636  // colInd and values.
2637  rowPtr[numRows] = numEntries;
2638  } // Finished conversion to CSR format
2639  catch (std::exception& e) {
2640  mergeAndConvertSucceeded = 0;
2641  errMsg << "Failed to merge sparse matrix entries and convert to "
2642  "CSR format: " << e.what();
2643  }
2644 
2645  if (debug && mergeAndConvertSucceeded) {
2646  // Number of rows in the matrix.
2647  const size_type numRows = dims[0];
2648  const size_type maxToDisplay = 100;
2649 
2650  cerr << "----- Proc 0: numEntriesPerRow[0.."
2651  << (numEntriesPerRow.size()-1) << "] ";
2652  if (numRows > maxToDisplay) {
2653  cerr << "(only showing first and last few entries) ";
2654  }
2655  cerr << "= [";
2656  if (numRows > 0) {
2657  if (numRows > maxToDisplay) {
2658  for (size_type k = 0; k < 2; ++k) {
2659  cerr << numEntriesPerRow[k] << " ";
2660  }
2661  cerr << "... ";
2662  for (size_type k = numRows-2; k < numRows-1; ++k) {
2663  cerr << numEntriesPerRow[k] << " ";
2664  }
2665  }
2666  else {
2667  for (size_type k = 0; k < numRows-1; ++k) {
2668  cerr << numEntriesPerRow[k] << " ";
2669  }
2670  }
2671  cerr << numEntriesPerRow[numRows-1];
2672  } // numRows > 0
2673  cerr << "]" << endl;
2674 
2675  cerr << "----- Proc 0: rowPtr ";
2676  if (numRows > maxToDisplay) {
2677  cerr << "(only showing first and last few entries) ";
2678  }
2679  cerr << "= [";
2680  if (numRows > maxToDisplay) {
2681  for (size_type k = 0; k < 2; ++k) {
2682  cerr << rowPtr[k] << " ";
2683  }
2684  cerr << "... ";
2685  for (size_type k = numRows-2; k < numRows; ++k) {
2686  cerr << rowPtr[k] << " ";
2687  }
2688  }
2689  else {
2690  for (size_type k = 0; k < numRows; ++k) {
2691  cerr << rowPtr[k] << " ";
2692  }
2693  }
2694  cerr << rowPtr[numRows] << "]" << endl;
2695  }
2696  } // if myRank == rootRank
2697  } // Done converting sparse matrix data to CSR format
2698 
2699  // Now we're done with the Adder, so we can release the
2700  // reference ("free" it) to save space. This only actually
2701  // does anything on Rank 0, since pAdder is null on all the
2702  // other MPI processes.
2703  pAdder = null;
2704 
2705  if (debug && myRank == rootRank) {
2706  cerr << "-- Making range, domain, and row maps" << endl;
2707  }
2708 
2709  // Make the maps that describe the matrix's range and domain,
2710  // and the distribution of its rows. Creating a Map is a
2711  // collective operation, so we don't have to do a broadcast of
2712  // a success Boolean.
2713  RCP<const map_type> pRangeMap = makeRangeMap (pComm, pNode, dims[0]);
2714  RCP<const map_type> pDomainMap =
2715  makeDomainMap (pRangeMap, dims[0], dims[1]);
2716  RCP<const map_type> pRowMap = makeRowMap (null, pComm, pNode, dims[0]);
2717 
2718  if (debug && myRank == rootRank) {
2719  cerr << "-- Distributing the matrix data" << endl;
2720  }
2721 
2722  // Distribute the matrix data. Each processor has to add the
2723  // rows that it owns. If you try to make Proc 0 call
2724  // insertGlobalValues() for _all_ the rows, not just those it
2725  // owns, then fillComplete() will compute the number of
2726  // columns incorrectly. That's why Proc 0 has to distribute
2727  // the matrix data and why we make all the processors (not
2728  // just Proc 0) call insertGlobalValues() on their own data.
2729  //
2730  // These arrays represent each processor's part of the matrix
2731  // data, in "CSR" format (sort of, since the row indices might
2732  // not be contiguous).
2733  ArrayRCP<size_t> myNumEntriesPerRow;
2734  ArrayRCP<size_t> myRowPtr;
2735  ArrayRCP<global_ordinal_type> myColInd;
2736  ArrayRCP<scalar_type> myValues;
2737  // Distribute the matrix data. This is a collective operation.
2738  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2739  numEntriesPerRow, rowPtr, colInd, values, debug);
2740 
2741  if (debug && myRank == rootRank) {
2742  cerr << "-- Inserting matrix entries on each processor";
2743  if (callFillComplete) {
2744  cerr << " and calling fillComplete()";
2745  }
2746  cerr << endl;
2747  }
2748  // Each processor inserts its part of the matrix data, and
2749  // then they all call fillComplete(). This method invalidates
2750  // the my* distributed matrix data before calling
2751  // fillComplete(), in order to save space. In general, we
2752  // never store more than two copies of the matrix's entries in
2753  // memory at once, which is no worse than what Tpetra
2754  // promises.
2755  RCP<sparse_matrix_type> pMatrix =
2756  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2757  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2758  // Only use a reduce-all in debug mode to check if pMatrix is
2759  // null. Otherwise, just throw an exception. We never expect
2760  // a null pointer here, so we can save a communication.
2761  if (debug) {
2762  int localIsNull = pMatrix.is_null () ? 1 : 0;
2763  int globalIsNull = 0;
2764  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2765  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2766  "Reader::makeMatrix() returned a null pointer on at least one "
2767  "process. Please report this bug to the Tpetra developers.");
2768  }
2769  else {
2770  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2771  "Reader::makeMatrix() returned a null pointer. "
2772  "Please report this bug to the Tpetra developers.");
2773  }
2774 
2775  // We can't get the dimensions of the matrix until after
2776  // fillComplete() is called. Thus, we can't do the sanity
2777  // check (dimensions read from the Matrix Market data,
2778  // vs. dimensions reported by the CrsMatrix) unless the user
2779  // asked makeMatrix() to call fillComplete().
2780  //
2781  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2782  // what one might think it does, so you have to ask the range
2783  // resp. domain map for the number of rows resp. columns.
2784  if (callFillComplete) {
2785  const int numProcs = pComm->getSize ();
2786 
2787  if (extraDebug && debug) {
2788  const global_size_t globalNumRows =
2789  pRangeMap->getGlobalNumElements ();
2790  const global_size_t globalNumCols =
2791  pDomainMap->getGlobalNumElements ();
2792  if (myRank == rootRank) {
2793  cerr << "-- Matrix is "
2794  << globalNumRows << " x " << globalNumCols
2795  << " with " << pMatrix->getGlobalNumEntries()
2796  << " entries, and index base "
2797  << pMatrix->getIndexBase() << "." << endl;
2798  }
2799  pComm->barrier ();
2800  for (int p = 0; p < numProcs; ++p) {
2801  if (myRank == p) {
2802  cerr << "-- Proc " << p << " owns "
2803  << pMatrix->getNodeNumCols() << " columns, and "
2804  << pMatrix->getNodeNumEntries() << " entries." << endl;
2805  }
2806  pComm->barrier ();
2807  }
2808  } // if (extraDebug && debug)
2809  } // if (callFillComplete)
2810 
2811  if (debug && myRank == rootRank) {
2812  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2813  << endl;
2814  }
2815  return pMatrix;
2816  }
2817 
2818 
2847  static Teuchos::RCP<sparse_matrix_type>
2848  readSparse (std::istream& in,
2849  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2850  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2851  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2852  const bool tolerant=false,
2853  const bool debug=false)
2854  {
2855  return readSparse (in, pComm, Teuchos::null, constructorParams,
2856  fillCompleteParams, tolerant, debug);
2857  }
2858 
2860  static Teuchos::RCP<sparse_matrix_type>
2861  readSparse (std::istream& in,
2862  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2863  const Teuchos::RCP<node_type>& pNode,
2864  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2865  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2866  const bool tolerant=false,
2867  const bool debug=false)
2868  {
2869  using Teuchos::MatrixMarket::Banner;
2870  using Teuchos::arcp;
2871  using Teuchos::ArrayRCP;
2872  using Teuchos::broadcast;
2873  using Teuchos::null;
2874  using Teuchos::ptr;
2875  using Teuchos::RCP;
2876  using Teuchos::reduceAll;
2877  using Teuchos::Tuple;
2878  using std::cerr;
2879  using std::endl;
2880  typedef Teuchos::ScalarTraits<scalar_type> STS;
2881 
2882  const bool extraDebug = false;
2883  const int myRank = pComm->getRank ();
2884  const int rootRank = 0;
2885 
2886  // Current line number in the input stream. Various calls
2887  // will modify this depending on the number of lines that are
2888  // read from the input stream. Only Rank 0 modifies this.
2889  size_t lineNumber = 1;
2890 
2891  if (debug && myRank == rootRank) {
2892  cerr << "Matrix Market reader: readSparse:" << endl
2893  << "-- Reading banner line" << endl;
2894  }
2895 
2896  // The "Banner" tells you whether the input stream represents
2897  // a sparse matrix, the symmetry type of the matrix, and the
2898  // type of the data it contains.
2899  //
2900  // pBanner will only be nonnull on MPI Rank 0. It will be
2901  // null on all other MPI processes.
2902  RCP<const Banner> pBanner;
2903  {
2904  // We read and validate the Banner on Proc 0, but broadcast
2905  // the validation result to all processes.
2906  // Teuchos::broadcast doesn't currently work with bool, so
2907  // we use int (true -> 1, false -> 0).
2908  int bannerIsCorrect = 1;
2909  std::ostringstream errMsg;
2910 
2911  if (myRank == rootRank) {
2912  // Read the Banner line from the input stream.
2913  try {
2914  pBanner = readBanner (in, lineNumber, tolerant, debug);
2915  }
2916  catch (std::exception& e) {
2917  errMsg << "Attempt to read the Matrix Market file's Banner line "
2918  "threw an exception: " << e.what();
2919  bannerIsCorrect = 0;
2920  }
2921 
2922  if (bannerIsCorrect) {
2923  // Validate the Banner for the case of a sparse matrix.
2924  // We validate on Proc 0, since it reads the Banner.
2925 
2926  // In intolerant mode, the matrix type must be "coordinate".
2927  if (! tolerant && pBanner->matrixType() != "coordinate") {
2928  bannerIsCorrect = 0;
2929  errMsg << "The Matrix Market input file must contain a "
2930  "\"coordinate\"-format sparse matrix in order to create a "
2931  "Tpetra::CrsMatrix object from it, but the file's matrix "
2932  "type is \"" << pBanner->matrixType() << "\" instead.";
2933  }
2934  // In tolerant mode, we allow the matrix type to be
2935  // anything other than "array" (which would mean that
2936  // the file contains a dense matrix).
2937  if (tolerant && pBanner->matrixType() == "array") {
2938  bannerIsCorrect = 0;
2939  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2940  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2941  "object from it, but the file's matrix type is \"array\" "
2942  "instead. That probably means the file contains dense matrix "
2943  "data.";
2944  }
2945  }
2946  } // Proc 0: Done reading the Banner, hopefully successfully.
2947 
2948  // Broadcast from Proc 0 whether the Banner was read correctly.
2949  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2950 
2951  // If the Banner is invalid, all processes throw an
2952  // exception. Only Proc 0 gets the exception message, but
2953  // that's OK, since the main point is to "stop the world"
2954  // (rather than throw an exception on one process and leave
2955  // the others hanging).
2956  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2957  std::invalid_argument, errMsg.str ());
2958  } // Done reading the Banner line and broadcasting success.
2959  if (debug && myRank == rootRank) {
2960  cerr << "-- Reading dimensions line" << endl;
2961  }
2962 
2963  // Read the matrix dimensions from the Matrix Market metadata.
2964  // dims = (numRows, numCols, numEntries). Proc 0 does the
2965  // reading, but it broadcasts the results to all MPI
2966  // processes. Thus, readCoordDims() is a collective
2967  // operation. It does a collective check for correctness too.
2968  Tuple<global_ordinal_type, 3> dims =
2969  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2970 
2971  if (debug && myRank == rootRank) {
2972  cerr << "-- Making Adder for collecting matrix data" << endl;
2973  }
2974 
2975  // "Adder" object for collecting all the sparse matrix entries
2976  // from the input stream. This is only nonnull on Proc 0.
2977  RCP<adder_type> pAdder =
2978  makeAdder (pComm, pBanner, dims, tolerant, debug);
2979 
2980  if (debug && myRank == rootRank) {
2981  cerr << "-- Reading matrix data" << endl;
2982  }
2983  //
2984  // Read the matrix entries from the input stream on Proc 0.
2985  //
2986  {
2987  // We use readSuccess to broadcast the results of the read
2988  // (succeeded or not) to all MPI processes. Since
2989  // Teuchos::broadcast doesn't currently know how to send
2990  // bools, we convert to int (true -> 1, false -> 0).
2991  int readSuccess = 1;
2992  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2993  if (myRank == rootRank) {
2994  try {
2995  // Reader for "coordinate" format sparse matrix data.
2996  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2997  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2998  reader_type reader (pAdder);
2999 
3000  // Read the sparse matrix entries.
3001  std::pair<bool, std::vector<size_t> > results =
3002  reader.read (in, lineNumber, tolerant, debug);
3003  readSuccess = results.first ? 1 : 0;
3004  }
3005  catch (std::exception& e) {
3006  readSuccess = 0;
3007  errMsg << e.what();
3008  }
3009  }
3010  broadcast (*pComm, rootRank, ptr (&readSuccess));
3011 
3012  // It would be nice to add a "verbose" flag, so that in
3013  // tolerant mode, we could log any bad line number(s) on
3014  // Proc 0. For now, we just throw if the read fails to
3015  // succeed.
3016  //
3017  // Question: If we're in tolerant mode, and if the read did
3018  // not succeed, should we attempt to call fillComplete()?
3019  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3020  "Failed to read the Matrix Market sparse matrix file: "
3021  << errMsg.str());
3022  } // Done reading the matrix entries (stored on Proc 0 for now)
3023 
3024  if (debug && myRank == rootRank) {
3025  cerr << "-- Successfully read the Matrix Market data" << endl;
3026  }
3027 
3028  // In tolerant mode, we need to rebroadcast the matrix
3029  // dimensions, since they may be different after reading the
3030  // actual matrix data. We only need to broadcast the number
3031  // of rows and columns. Only Rank 0 needs to know the actual
3032  // global number of entries, since (a) we need to merge
3033  // duplicates on Rank 0 first anyway, and (b) when we
3034  // distribute the entries, each rank other than Rank 0 will
3035  // only need to know how many entries it owns, not the total
3036  // number of entries.
3037  if (tolerant) {
3038  if (debug && myRank == rootRank) {
3039  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3040  << endl
3041  << "----- Dimensions before: "
3042  << dims[0] << " x " << dims[1]
3043  << endl;
3044  }
3045  // Packed coordinate matrix dimensions (numRows, numCols).
3046  Tuple<global_ordinal_type, 2> updatedDims;
3047  if (myRank == rootRank) {
3048  // If one or more bottom rows of the matrix contain no
3049  // entries, then the Adder will report that the number
3050  // of rows is less than that specified in the
3051  // metadata. We allow this case, and favor the
3052  // metadata so that the zero row(s) will be included.
3053  updatedDims[0] =
3054  std::max (dims[0], pAdder->getAdder()->numRows());
3055  updatedDims[1] = pAdder->getAdder()->numCols();
3056  }
3057  broadcast (*pComm, rootRank, updatedDims);
3058  dims[0] = updatedDims[0];
3059  dims[1] = updatedDims[1];
3060  if (debug && myRank == rootRank) {
3061  cerr << "----- Dimensions after: " << dims[0] << " x "
3062  << dims[1] << endl;
3063  }
3064  }
3065  else {
3066  // In strict mode, we require that the matrix's metadata and
3067  // its actual data agree, at least somewhat. In particular,
3068  // the number of rows must agree, since otherwise we cannot
3069  // distribute the matrix correctly.
3070 
3071  // Teuchos::broadcast() doesn't know how to broadcast bools,
3072  // so we use an int with the standard 1 == true, 0 == false
3073  // encoding.
3074  int dimsMatch = 1;
3075  if (myRank == rootRank) {
3076  // If one or more bottom rows of the matrix contain no
3077  // entries, then the Adder will report that the number of
3078  // rows is less than that specified in the metadata. We
3079  // allow this case, and favor the metadata, but do not
3080  // allow the Adder to think there are more rows in the
3081  // matrix than the metadata says.
3082  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3083  dimsMatch = 0;
3084  }
3085  }
3086  broadcast (*pComm, 0, ptr (&dimsMatch));
3087  if (dimsMatch == 0) {
3088  // We're in an error state anyway, so we might as well
3089  // work a little harder to print an informative error
3090  // message.
3091  //
3092  // Broadcast the Adder's idea of the matrix dimensions
3093  // from Proc 0 to all processes.
3094  Tuple<global_ordinal_type, 2> addersDims;
3095  if (myRank == rootRank) {
3096  addersDims[0] = pAdder->getAdder()->numRows();
3097  addersDims[1] = pAdder->getAdder()->numCols();
3098  }
3099  broadcast (*pComm, 0, addersDims);
3100  TEUCHOS_TEST_FOR_EXCEPTION(
3101  dimsMatch == 0, std::runtime_error,
3102  "The matrix metadata says that the matrix is " << dims[0] << " x "
3103  << dims[1] << ", but the actual data says that the matrix is "
3104  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3105  "data includes more rows than reported in the metadata. This "
3106  "is not allowed when parsing in strict mode. Parse the matrix in "
3107  "tolerant mode to ignore the metadata when it disagrees with the "
3108  "data.");
3109  }
3110  } // Matrix dimensions (# rows, # cols, # entries) agree.
3111 
3112  if (debug && myRank == rootRank) {
3113  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3114  }
3115 
3116  // Now that we've read in all the matrix entries from the
3117  // input stream into the adder on Proc 0, post-process them
3118  // into CSR format (still on Proc 0). This will facilitate
3119  // distributing them to all the processors.
3120  //
3121  // These arrays represent the global matrix data as a CSR
3122  // matrix (with numEntriesPerRow as redundant but convenient
3123  // metadata, since it's computable from rowPtr and vice
3124  // versa). They are valid only on Proc 0.
3125  ArrayRCP<size_t> numEntriesPerRow;
3126  ArrayRCP<size_t> rowPtr;
3127  ArrayRCP<global_ordinal_type> colInd;
3128  ArrayRCP<scalar_type> values;
3129 
3130  // Proc 0 first merges duplicate entries, and then converts
3131  // the coordinate-format matrix data to CSR.
3132  {
3133  int mergeAndConvertSucceeded = 1;
3134  std::ostringstream errMsg;
3135 
3136  if (myRank == rootRank) {
3137  try {
3138  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3139  global_ordinal_type> element_type;
3140 
3141  // Number of rows in the matrix. If we are in tolerant
3142  // mode, we've already synchronized dims with the actual
3143  // matrix data. If in strict mode, we should use dims
3144  // (as read from the file's metadata) rather than the
3145  // matrix data to determine the dimensions. (The matrix
3146  // data will claim fewer rows than the metadata, if one
3147  // or more rows have no entries stored in the file.)
3148  const size_type numRows = dims[0];
3149 
3150  // Additively merge duplicate matrix entries.
3151  pAdder->getAdder()->merge ();
3152 
3153  // Get a temporary const view of the merged matrix entries.
3154  const std::vector<element_type>& entries =
3155  pAdder->getAdder()->getEntries();
3156 
3157  // Number of matrix entries (after merging).
3158  const size_t numEntries = (size_t)entries.size();
3159 
3160  if (debug) {
3161  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3162  << " rows and numEntries=" << numEntries
3163  << " entries." << endl;
3164  }
3165 
3166  // Make space for the CSR matrix data. Converting to
3167  // CSR is easier if we fill numEntriesPerRow with zeros
3168  // at first.
3169  numEntriesPerRow = arcp<size_t> (numRows);
3170  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3171  rowPtr = arcp<size_t> (numRows+1);
3172  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3173  colInd = arcp<global_ordinal_type> (numEntries);
3174  values = arcp<scalar_type> (numEntries);
3175 
3176  // Convert from array-of-structs coordinate format to CSR
3177  // (compressed sparse row) format.
3178  global_ordinal_type prvRow = 0;
3179  size_t curPos = 0;
3180  rowPtr[0] = 0;
3181  for (curPos = 0; curPos < numEntries; ++curPos) {
3182  const element_type& curEntry = entries[curPos];
3183  const global_ordinal_type curRow = curEntry.rowIndex();
3184  TEUCHOS_TEST_FOR_EXCEPTION(
3185  curRow < prvRow, std::logic_error,
3186  "Row indices are out of order, even though they are supposed "
3187  "to be sorted. curRow = " << curRow << ", prvRow = "
3188  << prvRow << ", at curPos = " << curPos << ". Please report "
3189  "this bug to the Tpetra developers.");
3190  if (curRow > prvRow) {
3191  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3192  rowPtr[r] = curPos;
3193  }
3194  prvRow = curRow;
3195  }
3196  numEntriesPerRow[curRow]++;
3197  colInd[curPos] = curEntry.colIndex();
3198  values[curPos] = curEntry.value();
3199  }
3200  // rowPtr has one more entry than numEntriesPerRow. The
3201  // last entry of rowPtr is the number of entries in
3202  // colInd and values.
3203  rowPtr[numRows] = numEntries;
3204  } // Finished conversion to CSR format
3205  catch (std::exception& e) {
3206  mergeAndConvertSucceeded = 0;
3207  errMsg << "Failed to merge sparse matrix entries and convert to "
3208  "CSR format: " << e.what();
3209  }
3210 
3211  if (debug && mergeAndConvertSucceeded) {
3212  // Number of rows in the matrix.
3213  const size_type numRows = dims[0];
3214  const size_type maxToDisplay = 100;
3215 
3216  cerr << "----- Proc 0: numEntriesPerRow[0.."
3217  << (numEntriesPerRow.size()-1) << "] ";
3218  if (numRows > maxToDisplay) {
3219  cerr << "(only showing first and last few entries) ";
3220  }
3221  cerr << "= [";
3222  if (numRows > 0) {
3223  if (numRows > maxToDisplay) {
3224  for (size_type k = 0; k < 2; ++k) {
3225  cerr << numEntriesPerRow[k] << " ";
3226  }
3227  cerr << "... ";
3228  for (size_type k = numRows-2; k < numRows-1; ++k) {
3229  cerr << numEntriesPerRow[k] << " ";
3230  }
3231  }
3232  else {
3233  for (size_type k = 0; k < numRows-1; ++k) {
3234  cerr << numEntriesPerRow[k] << " ";
3235  }
3236  }
3237  cerr << numEntriesPerRow[numRows-1];
3238  } // numRows > 0
3239  cerr << "]" << endl;
3240 
3241  cerr << "----- Proc 0: rowPtr ";
3242  if (numRows > maxToDisplay) {
3243  cerr << "(only showing first and last few entries) ";
3244  }
3245  cerr << "= [";
3246  if (numRows > maxToDisplay) {
3247  for (size_type k = 0; k < 2; ++k) {
3248  cerr << rowPtr[k] << " ";
3249  }
3250  cerr << "... ";
3251  for (size_type k = numRows-2; k < numRows; ++k) {
3252  cerr << rowPtr[k] << " ";
3253  }
3254  }
3255  else {
3256  for (size_type k = 0; k < numRows; ++k) {
3257  cerr << rowPtr[k] << " ";
3258  }
3259  }
3260  cerr << rowPtr[numRows] << "]" << endl;
3261  }
3262  } // if myRank == rootRank
3263  } // Done converting sparse matrix data to CSR format
3264 
3265  // Now we're done with the Adder, so we can release the
3266  // reference ("free" it) to save space. This only actually
3267  // does anything on Rank 0, since pAdder is null on all the
3268  // other MPI processes.
3269  pAdder = null;
3270 
3271  if (debug && myRank == rootRank) {
3272  cerr << "-- Making range, domain, and row maps" << endl;
3273  }
3274 
3275  // Make the maps that describe the matrix's range and domain,
3276  // and the distribution of its rows. Creating a Map is a
3277  // collective operation, so we don't have to do a broadcast of
3278  // a success Boolean.
3279  RCP<const map_type> pRangeMap = makeRangeMap (pComm, pNode, dims[0]);
3280  RCP<const map_type> pDomainMap =
3281  makeDomainMap (pRangeMap, dims[0], dims[1]);
3282  RCP<const map_type> pRowMap = makeRowMap (null, pComm, pNode, dims[0]);
3283 
3284  if (debug && myRank == rootRank) {
3285  cerr << "-- Distributing the matrix data" << endl;
3286  }
3287 
3288  // Distribute the matrix data. Each processor has to add the
3289  // rows that it owns. If you try to make Proc 0 call
3290  // insertGlobalValues() for _all_ the rows, not just those it
3291  // owns, then fillComplete() will compute the number of
3292  // columns incorrectly. That's why Proc 0 has to distribute
3293  // the matrix data and why we make all the processors (not
3294  // just Proc 0) call insertGlobalValues() on their own data.
3295  //
3296  // These arrays represent each processor's part of the matrix
3297  // data, in "CSR" format (sort of, since the row indices might
3298  // not be contiguous).
3299  ArrayRCP<size_t> myNumEntriesPerRow;
3300  ArrayRCP<size_t> myRowPtr;
3301  ArrayRCP<global_ordinal_type> myColInd;
3302  ArrayRCP<scalar_type> myValues;
3303  // Distribute the matrix data. This is a collective operation.
3304  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3305  numEntriesPerRow, rowPtr, colInd, values, debug);
3306 
3307  if (debug && myRank == rootRank) {
3308  cerr << "-- Inserting matrix entries on each process "
3309  "and calling fillComplete()" << endl;
3310  }
3311  // Each processor inserts its part of the matrix data, and
3312  // then they all call fillComplete(). This method invalidates
3313  // the my* distributed matrix data before calling
3314  // fillComplete(), in order to save space. In general, we
3315  // never store more than two copies of the matrix's entries in
3316  // memory at once, which is no worse than what Tpetra
3317  // promises.
3318  Teuchos::RCP<sparse_matrix_type> pMatrix =
3319  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3320  pRowMap, pRangeMap, pDomainMap, constructorParams,
3321  fillCompleteParams);
3322  // Only use a reduce-all in debug mode to check if pMatrix is
3323  // null. Otherwise, just throw an exception. We never expect
3324  // a null pointer here, so we can save a communication.
3325  if (debug) {
3326  int localIsNull = pMatrix.is_null () ? 1 : 0;
3327  int globalIsNull = 0;
3328  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3329  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3330  "Reader::makeMatrix() returned a null pointer on at least one "
3331  "process. Please report this bug to the Tpetra developers.");
3332  }
3333  else {
3334  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3335  "Reader::makeMatrix() returned a null pointer. "
3336  "Please report this bug to the Tpetra developers.");
3337  }
3338 
3339  // Sanity check for dimensions (read from the Matrix Market
3340  // data, vs. dimensions reported by the CrsMatrix).
3341  //
3342  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3343  // what one might think it does, so you have to ask the range
3344  // resp. domain map for the number of rows resp. columns.
3345  if (extraDebug && debug) {
3346  const int numProcs = pComm->getSize ();
3347  const global_size_t globalNumRows =
3348  pRangeMap->getGlobalNumElements();
3349  const global_size_t globalNumCols =
3350  pDomainMap->getGlobalNumElements();
3351  if (myRank == rootRank) {
3352  cerr << "-- Matrix is "
3353  << globalNumRows << " x " << globalNumCols
3354  << " with " << pMatrix->getGlobalNumEntries()
3355  << " entries, and index base "
3356  << pMatrix->getIndexBase() << "." << endl;
3357  }
3358  pComm->barrier ();
3359  for (int p = 0; p < numProcs; ++p) {
3360  if (myRank == p) {
3361  cerr << "-- Proc " << p << " owns "
3362  << pMatrix->getNodeNumCols() << " columns, and "
3363  << pMatrix->getNodeNumEntries() << " entries." << endl;
3364  }
3365  pComm->barrier ();
3366  }
3367  } // if (extraDebug && debug)
3368 
3369  if (debug && myRank == rootRank) {
3370  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3371  << endl;
3372  }
3373  return pMatrix;
3374  }
3375 
3416  static Teuchos::RCP<sparse_matrix_type>
3417  readSparse (std::istream& in,
3418  const Teuchos::RCP<const map_type>& rowMap,
3419  Teuchos::RCP<const map_type>& colMap,
3420  const Teuchos::RCP<const map_type>& domainMap,
3421  const Teuchos::RCP<const map_type>& rangeMap,
3422  const bool callFillComplete=true,
3423  const bool tolerant=false,
3424  const bool debug=false)
3425  {
3426  using Teuchos::MatrixMarket::Banner;
3427  using Teuchos::arcp;
3428  using Teuchos::ArrayRCP;
3429  using Teuchos::ArrayView;
3430  using Teuchos::as;
3431  using Teuchos::broadcast;
3432  using Teuchos::Comm;
3433  using Teuchos::null;
3434  using Teuchos::ptr;
3435  using Teuchos::RCP;
3436  using Teuchos::reduceAll;
3437  using Teuchos::Tuple;
3438  using std::cerr;
3439  using std::endl;
3440  typedef Teuchos::ScalarTraits<scalar_type> STS;
3441 
3442  RCP<const Comm<int> > pComm = rowMap->getComm ();
3443  const int myRank = pComm->getRank ();
3444  const int rootRank = 0;
3445  const bool extraDebug = false;
3446 
3447  // Fast checks for invalid input. We can't check other
3448  // attributes of the Maps until we've read in the matrix
3449  // dimensions.
3450  TEUCHOS_TEST_FOR_EXCEPTION(
3451  rowMap.is_null (), std::invalid_argument,
3452  "Row Map must be nonnull.");
3453  TEUCHOS_TEST_FOR_EXCEPTION(
3454  rangeMap.is_null (), std::invalid_argument,
3455  "Range Map must be nonnull.");
3456  TEUCHOS_TEST_FOR_EXCEPTION(
3457  domainMap.is_null (), std::invalid_argument,
3458  "Domain Map must be nonnull.");
3459  TEUCHOS_TEST_FOR_EXCEPTION(
3460  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3461  std::invalid_argument,
3462  "The specified row Map's communicator (rowMap->getComm())"
3463  "differs from the given separately supplied communicator pComm.");
3464  TEUCHOS_TEST_FOR_EXCEPTION(
3465  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3466  std::invalid_argument,
3467  "The specified domain Map's communicator (domainMap->getComm())"
3468  "differs from the given separately supplied communicator pComm.");
3469  TEUCHOS_TEST_FOR_EXCEPTION(
3470  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3471  std::invalid_argument,
3472  "The specified range Map's communicator (rangeMap->getComm())"
3473  "differs from the given separately supplied communicator pComm.");
3474 
3475  // Current line number in the input stream. Various calls
3476  // will modify this depending on the number of lines that are
3477  // read from the input stream. Only Rank 0 modifies this.
3478  size_t lineNumber = 1;
3479 
3480  if (debug && myRank == rootRank) {
3481  cerr << "Matrix Market reader: readSparse:" << endl
3482  << "-- Reading banner line" << endl;
3483  }
3484 
3485  // The "Banner" tells you whether the input stream represents
3486  // a sparse matrix, the symmetry type of the matrix, and the
3487  // type of the data it contains.
3488  //
3489  // pBanner will only be nonnull on MPI Rank 0. It will be
3490  // null on all other MPI processes.
3491  RCP<const Banner> pBanner;
3492  {
3493  // We read and validate the Banner on Proc 0, but broadcast
3494  // the validation result to all processes.
3495  // Teuchos::broadcast doesn't currently work with bool, so
3496  // we use int (true -> 1, false -> 0).
3497  int bannerIsCorrect = 1;
3498  std::ostringstream errMsg;
3499 
3500  if (myRank == rootRank) {
3501  // Read the Banner line from the input stream.
3502  try {
3503  pBanner = readBanner (in, lineNumber, tolerant, debug);
3504  }
3505  catch (std::exception& e) {
3506  errMsg << "Attempt to read the Matrix Market file's Banner line "
3507  "threw an exception: " << e.what();
3508  bannerIsCorrect = 0;
3509  }
3510 
3511  if (bannerIsCorrect) {
3512  // Validate the Banner for the case of a sparse matrix.
3513  // We validate on Proc 0, since it reads the Banner.
3514 
3515  // In intolerant mode, the matrix type must be "coordinate".
3516  if (! tolerant && pBanner->matrixType() != "coordinate") {
3517  bannerIsCorrect = 0;
3518  errMsg << "The Matrix Market input file must contain a "
3519  "\"coordinate\"-format sparse matrix in order to create a "
3520  "Tpetra::CrsMatrix object from it, but the file's matrix "
3521  "type is \"" << pBanner->matrixType() << "\" instead.";
3522  }
3523  // In tolerant mode, we allow the matrix type to be
3524  // anything other than "array" (which would mean that
3525  // the file contains a dense matrix).
3526  if (tolerant && pBanner->matrixType() == "array") {
3527  bannerIsCorrect = 0;
3528  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3529  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3530  "object from it, but the file's matrix type is \"array\" "
3531  "instead. That probably means the file contains dense matrix "
3532  "data.";
3533  }
3534  }
3535  } // Proc 0: Done reading the Banner, hopefully successfully.
3536 
3537  // Broadcast from Proc 0 whether the Banner was read correctly.
3538  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3539 
3540  // If the Banner is invalid, all processes throw an
3541  // exception. Only Proc 0 gets the exception message, but
3542  // that's OK, since the main point is to "stop the world"
3543  // (rather than throw an exception on one process and leave
3544  // the others hanging).
3545  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3546  std::invalid_argument, errMsg.str ());
3547  } // Done reading the Banner line and broadcasting success.
3548  if (debug && myRank == rootRank) {
3549  cerr << "-- Reading dimensions line" << endl;
3550  }
3551 
3552  // Read the matrix dimensions from the Matrix Market metadata.
3553  // dims = (numRows, numCols, numEntries). Proc 0 does the
3554  // reading, but it broadcasts the results to all MPI
3555  // processes. Thus, readCoordDims() is a collective
3556  // operation. It does a collective check for correctness too.
3557  Tuple<global_ordinal_type, 3> dims =
3558  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3559 
3560  if (debug && myRank == rootRank) {
3561  cerr << "-- Making Adder for collecting matrix data" << endl;
3562  }
3563 
3564  // "Adder" object for collecting all the sparse matrix entries
3565  // from the input stream. This is only nonnull on Proc 0.
3566  // The Adder internally converts the one-based indices (native
3567  // Matrix Market format) into zero-based indices.
3568  RCP<adder_type> pAdder =
3569  makeAdder (pComm, pBanner, dims, tolerant, debug);
3570 
3571  if (debug && myRank == rootRank) {
3572  cerr << "-- Reading matrix data" << endl;
3573  }
3574  //
3575  // Read the matrix entries from the input stream on Proc 0.
3576  //
3577  {
3578  // We use readSuccess to broadcast the results of the read
3579  // (succeeded or not) to all MPI processes. Since
3580  // Teuchos::broadcast doesn't currently know how to send
3581  // bools, we convert to int (true -> 1, false -> 0).
3582  int readSuccess = 1;
3583  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3584  if (myRank == rootRank) {
3585  try {
3586  // Reader for "coordinate" format sparse matrix data.
3587  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3588  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3589  reader_type reader (pAdder);
3590 
3591  // Read the sparse matrix entries.
3592  std::pair<bool, std::vector<size_t> > results =
3593  reader.read (in, lineNumber, tolerant, debug);
3594  readSuccess = results.first ? 1 : 0;
3595  }
3596  catch (std::exception& e) {
3597  readSuccess = 0;
3598  errMsg << e.what();
3599  }
3600  }
3601  broadcast (*pComm, rootRank, ptr (&readSuccess));
3602 
3603  // It would be nice to add a "verbose" flag, so that in
3604  // tolerant mode, we could log any bad line number(s) on
3605  // Proc 0. For now, we just throw if the read fails to
3606  // succeed.
3607  //
3608  // Question: If we're in tolerant mode, and if the read did
3609  // not succeed, should we attempt to call fillComplete()?
3610  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3611  "Failed to read the Matrix Market sparse matrix file: "
3612  << errMsg.str());
3613  } // Done reading the matrix entries (stored on Proc 0 for now)
3614 
3615  if (debug && myRank == rootRank) {
3616  cerr << "-- Successfully read the Matrix Market data" << endl;
3617  }
3618 
3619  // In tolerant mode, we need to rebroadcast the matrix
3620  // dimensions, since they may be different after reading the
3621  // actual matrix data. We only need to broadcast the number
3622  // of rows and columns. Only Rank 0 needs to know the actual
3623  // global number of entries, since (a) we need to merge
3624  // duplicates on Rank 0 first anyway, and (b) when we
3625  // distribute the entries, each rank other than Rank 0 will
3626  // only need to know how many entries it owns, not the total
3627  // number of entries.
3628  if (tolerant) {
3629  if (debug && myRank == rootRank) {
3630  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3631  << endl
3632  << "----- Dimensions before: "
3633  << dims[0] << " x " << dims[1]
3634  << endl;
3635  }
3636  // Packed coordinate matrix dimensions (numRows, numCols).
3637  Tuple<global_ordinal_type, 2> updatedDims;
3638  if (myRank == rootRank) {
3639  // If one or more bottom rows of the matrix contain no
3640  // entries, then the Adder will report that the number
3641  // of rows is less than that specified in the
3642  // metadata. We allow this case, and favor the
3643  // metadata so that the zero row(s) will be included.
3644  updatedDims[0] =
3645  std::max (dims[0], pAdder->getAdder()->numRows());
3646  updatedDims[1] = pAdder->getAdder()->numCols();
3647  }
3648  broadcast (*pComm, rootRank, updatedDims);
3649  dims[0] = updatedDims[0];
3650  dims[1] = updatedDims[1];
3651  if (debug && myRank == rootRank) {
3652  cerr << "----- Dimensions after: " << dims[0] << " x "
3653  << dims[1] << endl;
3654  }
3655  }
3656  else {
3657  // In strict mode, we require that the matrix's metadata and
3658  // its actual data agree, at least somewhat. In particular,
3659  // the number of rows must agree, since otherwise we cannot
3660  // distribute the matrix correctly.
3661 
3662  // Teuchos::broadcast() doesn't know how to broadcast bools,
3663  // so we use an int with the standard 1 == true, 0 == false
3664  // encoding.
3665  int dimsMatch = 1;
3666  if (myRank == rootRank) {
3667  // If one or more bottom rows of the matrix contain no
3668  // entries, then the Adder will report that the number of
3669  // rows is less than that specified in the metadata. We
3670  // allow this case, and favor the metadata, but do not
3671  // allow the Adder to think there are more rows in the
3672  // matrix than the metadata says.
3673  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3674  dimsMatch = 0;
3675  }
3676  }
3677  broadcast (*pComm, 0, ptr (&dimsMatch));
3678  if (dimsMatch == 0) {
3679  // We're in an error state anyway, so we might as well
3680  // work a little harder to print an informative error
3681  // message.
3682  //
3683  // Broadcast the Adder's idea of the matrix dimensions
3684  // from Proc 0 to all processes.
3685  Tuple<global_ordinal_type, 2> addersDims;
3686  if (myRank == rootRank) {
3687  addersDims[0] = pAdder->getAdder()->numRows();
3688  addersDims[1] = pAdder->getAdder()->numCols();
3689  }
3690  broadcast (*pComm, 0, addersDims);
3691  TEUCHOS_TEST_FOR_EXCEPTION(
3692  dimsMatch == 0, std::runtime_error,
3693  "The matrix metadata says that the matrix is " << dims[0] << " x "
3694  << dims[1] << ", but the actual data says that the matrix is "
3695  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3696  "data includes more rows than reported in the metadata. This "
3697  "is not allowed when parsing in strict mode. Parse the matrix in "
3698  "tolerant mode to ignore the metadata when it disagrees with the "
3699  "data.");
3700  }
3701  } // Matrix dimensions (# rows, # cols, # entries) agree.
3702 
3703  if (debug && myRank == rootRank) {
3704  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3705  }
3706 
3707  // Now that we've read in all the matrix entries from the
3708  // input stream into the adder on Proc 0, post-process them
3709  // into CSR format (still on Proc 0). This will facilitate
3710  // distributing them to all the processors.
3711  //
3712  // These arrays represent the global matrix data as a CSR
3713  // matrix (with numEntriesPerRow as redundant but convenient
3714  // metadata, since it's computable from rowPtr and vice
3715  // versa). They are valid only on Proc 0.
3716  ArrayRCP<size_t> numEntriesPerRow;
3717  ArrayRCP<size_t> rowPtr;
3718  ArrayRCP<global_ordinal_type> colInd;
3719  ArrayRCP<scalar_type> values;
3720 
3721  // Proc 0 first merges duplicate entries, and then converts
3722  // the coordinate-format matrix data to CSR.
3723  {
3724  int mergeAndConvertSucceeded = 1;
3725  std::ostringstream errMsg;
3726 
3727  if (myRank == rootRank) {
3728  try {
3729  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3730  global_ordinal_type> element_type;
3731 
3732  // Number of rows in the matrix. If we are in tolerant
3733  // mode, we've already synchronized dims with the actual
3734  // matrix data. If in strict mode, we should use dims
3735  // (as read from the file's metadata) rather than the
3736  // matrix data to determine the dimensions. (The matrix
3737  // data will claim fewer rows than the metadata, if one
3738  // or more rows have no entries stored in the file.)
3739  const size_type numRows = dims[0];
3740 
3741  // Additively merge duplicate matrix entries.
3742  pAdder->getAdder()->merge ();
3743 
3744  // Get a temporary const view of the merged matrix entries.
3745  const std::vector<element_type>& entries =
3746  pAdder->getAdder()->getEntries();
3747 
3748  // Number of matrix entries (after merging).
3749  const size_t numEntries = (size_t)entries.size();
3750 
3751  if (debug) {
3752  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3753  << " rows and numEntries=" << numEntries
3754  << " entries." << endl;
3755  }
3756 
3757  // Make space for the CSR matrix data. Converting to
3758  // CSR is easier if we fill numEntriesPerRow with zeros
3759  // at first.
3760  numEntriesPerRow = arcp<size_t> (numRows);
3761  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3762  rowPtr = arcp<size_t> (numRows+1);
3763  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3764  colInd = arcp<global_ordinal_type> (numEntries);
3765  values = arcp<scalar_type> (numEntries);
3766 
3767  // Convert from array-of-structs coordinate format to CSR
3768  // (compressed sparse row) format.
3769  global_ordinal_type prvRow = 0;
3770  size_t curPos = 0;
3771  rowPtr[0] = 0;
3772  for (curPos = 0; curPos < numEntries; ++curPos) {
3773  const element_type& curEntry = entries[curPos];
3774  const global_ordinal_type curRow = curEntry.rowIndex();
3775  TEUCHOS_TEST_FOR_EXCEPTION(
3776  curRow < prvRow, std::logic_error,
3777  "Row indices are out of order, even though they are supposed "
3778  "to be sorted. curRow = " << curRow << ", prvRow = "
3779  << prvRow << ", at curPos = " << curPos << ". Please report "
3780  "this bug to the Tpetra developers.");
3781  if (curRow > prvRow) {
3782  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3783  rowPtr[r] = curPos;
3784  }
3785  prvRow = curRow;
3786  }
3787  numEntriesPerRow[curRow]++;
3788  colInd[curPos] = curEntry.colIndex();
3789  values[curPos] = curEntry.value();
3790  }
3791  // rowPtr has one more entry than numEntriesPerRow. The
3792  // last entry of rowPtr is the number of entries in
3793  // colInd and values.
3794  rowPtr[numRows] = numEntries;
3795  } // Finished conversion to CSR format
3796  catch (std::exception& e) {
3797  mergeAndConvertSucceeded = 0;
3798  errMsg << "Failed to merge sparse matrix entries and convert to "
3799  "CSR format: " << e.what();
3800  }
3801 
3802  if (debug && mergeAndConvertSucceeded) {
3803  // Number of rows in the matrix.
3804  const size_type numRows = dims[0];
3805  const size_type maxToDisplay = 100;
3806 
3807  cerr << "----- Proc 0: numEntriesPerRow[0.."
3808  << (numEntriesPerRow.size()-1) << "] ";
3809  if (numRows > maxToDisplay) {
3810  cerr << "(only showing first and last few entries) ";
3811  }
3812  cerr << "= [";
3813  if (numRows > 0) {
3814  if (numRows > maxToDisplay) {
3815  for (size_type k = 0; k < 2; ++k) {
3816  cerr << numEntriesPerRow[k] << " ";
3817  }
3818  cerr << "... ";
3819  for (size_type k = numRows-2; k < numRows-1; ++k) {
3820  cerr << numEntriesPerRow[k] << " ";
3821  }
3822  }
3823  else {
3824  for (size_type k = 0; k < numRows-1; ++k) {
3825  cerr << numEntriesPerRow[k] << " ";
3826  }
3827  }
3828  cerr << numEntriesPerRow[numRows-1];
3829  } // numRows > 0
3830  cerr << "]" << endl;
3831 
3832  cerr << "----- Proc 0: rowPtr ";
3833  if (numRows > maxToDisplay) {
3834  cerr << "(only showing first and last few entries) ";
3835  }
3836  cerr << "= [";
3837  if (numRows > maxToDisplay) {
3838  for (size_type k = 0; k < 2; ++k) {
3839  cerr << rowPtr[k] << " ";
3840  }
3841  cerr << "... ";
3842  for (size_type k = numRows-2; k < numRows; ++k) {
3843  cerr << rowPtr[k] << " ";
3844  }
3845  }
3846  else {
3847  for (size_type k = 0; k < numRows; ++k) {
3848  cerr << rowPtr[k] << " ";
3849  }
3850  }
3851  cerr << rowPtr[numRows] << "]" << endl;
3852 
3853  cerr << "----- Proc 0: colInd = [";
3854  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3855  cerr << colInd[k] << " ";
3856  }
3857  cerr << "]" << endl;
3858  }
3859  } // if myRank == rootRank
3860  } // Done converting sparse matrix data to CSR format
3861 
3862  // Now we're done with the Adder, so we can release the
3863  // reference ("free" it) to save space. This only actually
3864  // does anything on Rank 0, since pAdder is null on all the
3865  // other MPI processes.
3866  pAdder = null;
3867 
3868  // Verify details of the Maps. Don't count the global number
3869  // of entries in the row Map, since that number doesn't
3870  // correctly count overlap.
3871  if (debug && myRank == rootRank) {
3872  cerr << "-- Verifying Maps" << endl;
3873  }
3874  TEUCHOS_TEST_FOR_EXCEPTION(
3875  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3876  std::invalid_argument,
3877  "The range Map has " << rangeMap->getGlobalNumElements ()
3878  << " entries, but the matrix has a global number of rows " << dims[0]
3879  << ".");
3880  TEUCHOS_TEST_FOR_EXCEPTION(
3881  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3882  std::invalid_argument,
3883  "The domain Map has " << domainMap->getGlobalNumElements ()
3884  << " entries, but the matrix has a global number of columns "
3885  << dims[1] << ".");
3886 
3887  // Create a row Map which is entirely owned on Proc 0.
3888  RCP<Teuchos::FancyOStream> err = debug ?
3889  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3890 
3891  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3892  ArrayView<const global_ordinal_type> myRows =
3893  gatherRowMap->getNodeElementList ();
3894  const size_type myNumRows = myRows.size ();
3895  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3896 
3897  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3898  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3899  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3900  }
3901 
3902  // Create a matrix using this Map, and fill in on Proc 0. We
3903  // know how many entries there are in each row, so we can use
3904  // static profile.
3905  RCP<sparse_matrix_type> A_proc0 =
3906  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow,
3908  if (myRank == rootRank) {
3909  if (debug) {
3910  cerr << "-- Proc 0: Filling gather matrix" << endl;
3911  }
3912  if (debug) {
3913  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3914  }
3915 
3916  // Add Proc 0's matrix entries to the CrsMatrix.
3917  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3918  size_type i = myRows[i_] - indexBase;
3919 
3920  const size_type curPos = as<size_type> (rowPtr[i]);
3921  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3922  ArrayView<global_ordinal_type> curColInd =
3923  colInd.view (curPos, curNumEntries);
3924  ArrayView<scalar_type> curValues =
3925  values.view (curPos, curNumEntries);
3926 
3927  // Modify the column indices in place to have the right index base.
3928  for (size_type k = 0; k < curNumEntries; ++k) {
3929  curColInd[k] += indexBase;
3930  }
3931  if (debug) {
3932  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3933  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3934  }
3935  // Avoid constructing empty views of ArrayRCP objects.
3936  if (curNumEntries > 0) {
3937  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3938  }
3939  }
3940  // Now we can save space by deallocating numEntriesPerRow,
3941  // rowPtr, colInd, and values, since we've already put those
3942  // data in the matrix.
3943  numEntriesPerRow = null;
3944  rowPtr = null;
3945  colInd = null;
3946  values = null;
3947  } // if myRank == rootRank
3948 
3949  RCP<sparse_matrix_type> A;
3950  if (colMap.is_null ()) {
3951  A = rcp (new sparse_matrix_type (rowMap, 0));
3952  } else {
3953  A = rcp (new sparse_matrix_type (rowMap, colMap, 0));
3954  }
3956  export_type exp (gatherRowMap, rowMap);
3957  A->doExport (*A_proc0, exp, INSERT);
3958 
3959  if (callFillComplete) {
3960  A->fillComplete (domainMap, rangeMap);
3961  }
3962 
3963  // We can't get the dimensions of the matrix until after
3964  // fillComplete() is called. Thus, we can't do the sanity
3965  // check (dimensions read from the Matrix Market data,
3966  // vs. dimensions reported by the CrsMatrix) unless the user
3967  // asked us to call fillComplete().
3968  //
3969  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3970  // what one might think it does, so you have to ask the range
3971  // resp. domain map for the number of rows resp. columns.
3972  if (callFillComplete) {
3973  const int numProcs = pComm->getSize ();
3974 
3975  if (extraDebug && debug) {
3976  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3977  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3978  if (myRank == rootRank) {
3979  cerr << "-- Matrix is "
3980  << globalNumRows << " x " << globalNumCols
3981  << " with " << A->getGlobalNumEntries()
3982  << " entries, and index base "
3983  << A->getIndexBase() << "." << endl;
3984  }
3985  pComm->barrier ();
3986  for (int p = 0; p < numProcs; ++p) {
3987  if (myRank == p) {
3988  cerr << "-- Proc " << p << " owns "
3989  << A->getNodeNumCols() << " columns, and "
3990  << A->getNodeNumEntries() << " entries." << endl;
3991  }
3992  pComm->barrier ();
3993  }
3994  } // if (extraDebug && debug)
3995  } // if (callFillComplete)
3996 
3997  if (debug && myRank == rootRank) {
3998  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3999  << endl;
4000  }
4001  return A;
4002  }
4003 
4033  static Teuchos::RCP<multivector_type>
4034  readDenseFile (const std::string& filename,
4035  const Teuchos::RCP<const comm_type>& comm,
4036  Teuchos::RCP<const map_type>& map,
4037  const bool tolerant=false,
4038  const bool debug=false)
4039  {
4040  std::ifstream in;
4041  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4042  in.open (filename.c_str ()); // Destructor closes safely
4043  }
4044  return readDense (in, comm, map, tolerant, debug);
4045  }
4046 
4048  static Teuchos::RCP<multivector_type>
4049  readDenseFile (const std::string& filename,
4050  const Teuchos::RCP<const comm_type>& comm,
4051  const Teuchos::RCP<node_type>& node,
4052  Teuchos::RCP<const map_type>& map,
4053  const bool tolerant=false,
4054  const bool debug=false)
4055  {
4056  std::ifstream in;
4057  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4058  in.open (filename.c_str ()); // Destructor closes safely
4059  }
4060  return readDense (in, comm, node, map, tolerant, debug);
4061  }
4062 
4092  static Teuchos::RCP<vector_type>
4093  readVectorFile (const std::string& filename,
4094  const Teuchos::RCP<const comm_type>& comm,
4095  Teuchos::RCP<const map_type>& map,
4096  const bool tolerant=false,
4097  const bool debug=false)
4098  {
4099  std::ifstream in;
4100  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4101  in.open (filename.c_str ()); // Destructor closes safely
4102  }
4103  return readVector (in, comm, map, tolerant, debug);
4104  }
4105 
4108  static Teuchos::RCP<vector_type>
4109  readVectorFile (const std::string& filename,
4110  const Teuchos::RCP<const comm_type>& comm,
4111  const Teuchos::RCP<node_type>& node,
4112  Teuchos::RCP<const map_type>& map,
4113  const bool tolerant=false,
4114  const bool debug=false)
4115  {
4116  std::ifstream in;
4117  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4118  in.open (filename.c_str ()); // Destructor closes safely
4119  }
4120  return readVector (in, comm, node, map, tolerant, debug);
4121  }
4122 
4190  static Teuchos::RCP<multivector_type>
4191  readDense (std::istream& in,
4192  const Teuchos::RCP<const comm_type>& comm,
4193  Teuchos::RCP<const map_type>& map,
4194  const bool tolerant=false,
4195  const bool debug=false)
4196  {
4197  return readDense (in, comm, Teuchos::null, map, tolerant, debug);
4198  }
4199 
4201  static Teuchos::RCP<multivector_type>
4202  readDense (std::istream& in,
4203  const Teuchos::RCP<const comm_type>& comm,
4204  const Teuchos::RCP<node_type>& node,
4205  Teuchos::RCP<const map_type>& map,
4206  const bool tolerant=false,
4207  const bool debug=false)
4208  {
4209  Teuchos::RCP<Teuchos::FancyOStream> err =
4210  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4211  return readDenseImpl<scalar_type> (in, comm, node, map,
4212  err, tolerant, debug);
4213  }
4214 
4216  static Teuchos::RCP<vector_type>
4217  readVector (std::istream& in,
4218  const Teuchos::RCP<const comm_type>& comm,
4219  Teuchos::RCP<const map_type>& map,
4220  const bool tolerant=false,
4221  const bool debug=false)
4222  {
4223  Teuchos::RCP<Teuchos::FancyOStream> err =
4224  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4225  return readVectorImpl<scalar_type> (in, comm, Teuchos::null, map,
4226  err, tolerant, debug);
4227  }
4228 
4230  static Teuchos::RCP<vector_type>
4231  readVector (std::istream& in,
4232  const Teuchos::RCP<const comm_type>& comm,
4233  const Teuchos::RCP<node_type>& node,
4234  Teuchos::RCP<const map_type>& map,
4235  const bool tolerant=false,
4236  const bool debug=false)
4237  {
4238  Teuchos::RCP<Teuchos::FancyOStream> err =
4239  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4240  return readVectorImpl<scalar_type> (in, comm, node, map,
4241  err, tolerant, debug);
4242  }
4243 
4264  static Teuchos::RCP<const map_type>
4265  readMapFile (const std::string& filename,
4266  const Teuchos::RCP<const comm_type>& comm,
4267  const bool tolerant=false,
4268  const bool debug=false)
4269  {
4270  return readMapFile (filename, comm, Teuchos::null, tolerant, debug);
4271  }
4272 
4275  static Teuchos::RCP<const map_type>
4276  readMapFile (const std::string& filename,
4277  const Teuchos::RCP<const comm_type>& comm,
4278  const Teuchos::RCP<node_type>& node,
4279  const bool tolerant=false,
4280  const bool debug=false)
4281  {
4282  using Teuchos::inOutArg;
4283  using Teuchos::broadcast;
4284  std::ifstream in;
4285 
4286  int success = 1;
4287  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4288  in.open (filename.c_str ()); // Destructor closes safely
4289  if (! in) {
4290  success = 0;
4291  }
4292  }
4293  broadcast<int, int> (*comm, 0, inOutArg (success));
4294  TEUCHOS_TEST_FOR_EXCEPTION(
4295  success == 0, std::runtime_error,
4296  "Tpetra::MatrixMarket::Reader::readMapFile: "
4297  "Failed to read file \"" << filename << "\" on Process 0.");
4298  return readMap (in, comm, node, tolerant, debug);
4299  }
4300 
4301  private:
4302  template<class MultiVectorScalarType>
4303  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4306  node_type> >
4307  readDenseImpl (std::istream& in,
4308  const Teuchos::RCP<const comm_type>& comm,
4309  const Teuchos::RCP<node_type>& node,
4310  Teuchos::RCP<const map_type>& map,
4311  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4312  const bool tolerant=false,
4313  const bool debug=false)
4314  {
4315  using Teuchos::MatrixMarket::Banner;
4316  using Teuchos::MatrixMarket::checkCommentLine;
4317  using Teuchos::ArrayRCP;
4318  using Teuchos::as;
4319  using Teuchos::broadcast;
4320  using Teuchos::outArg;
4321  using Teuchos::RCP;
4322  using Teuchos::Tuple;
4323  using std::endl;
4324  typedef MultiVectorScalarType ST;
4325  typedef local_ordinal_type LO;
4326  typedef global_ordinal_type GO;
4327  typedef node_type NT;
4328  typedef Teuchos::ScalarTraits<ST> STS;
4329  typedef typename STS::magnitudeType MT;
4330  typedef Teuchos::ScalarTraits<MT> STM;
4332 
4333  // Rank 0 is the only (MPI) process allowed to read from the
4334  // input stream.
4335  const int myRank = comm->getRank ();
4336 
4337  if (! err.is_null ()) {
4338  err->pushTab ();
4339  }
4340  if (debug) {
4341  *err << myRank << ": readDenseImpl" << endl;
4342  }
4343  if (! err.is_null ()) {
4344  err->pushTab ();
4345  }
4346 
4347  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4348  // instances be identical and that the Node instances be
4349  // identical. The essential condition is more complicated to
4350  // test and isn't the same for all Node types. Thus, we just
4351  // leave it up to the user.
4352 
4353  // // If map is nonnull, check the precondition that its
4354  // // communicator resp. node equal comm resp. node. Checking
4355  // // now avoids doing a lot of file reading before we detect the
4356  // // violated precondition.
4357  // TEUCHOS_TEST_FOR_EXCEPTION(
4358  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4359  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4360  // "communicator and node must equal the supplied communicator resp. "
4361  // "node.");
4362 
4363  // Process 0 will read in the matrix dimensions from the file,
4364  // and broadcast them to all ranks in the given communicator.
4365  // There are only 2 dimensions in the matrix, but we use the
4366  // third element of the Tuple to encode the banner's reported
4367  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4368  // (same as "real"). We don't allow pattern matrices (i.e.,
4369  // graphs) since they only make sense for sparse data.
4370  Tuple<GO, 3> dims;
4371  dims[0] = 0;
4372  dims[1] = 0;
4373 
4374  // Current line number in the input stream. Only valid on
4375  // Proc 0. Various calls will modify this depending on the
4376  // number of lines that are read from the input stream.
4377  size_t lineNumber = 1;
4378 
4379  // Capture errors and their messages on Proc 0.
4380  std::ostringstream exMsg;
4381  int localBannerReadSuccess = 1;
4382  int localDimsReadSuccess = 1;
4383 
4384  // Only Proc 0 gets to read matrix data from the input stream.
4385  if (myRank == 0) {
4386  if (debug) {
4387  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4388  }
4389 
4390  // The "Banner" tells you whether the input stream
4391  // represents a dense matrix, the symmetry type of the
4392  // matrix, and the type of the data it contains.
4393  RCP<const Banner> pBanner;
4394  try {
4395  pBanner = readBanner (in, lineNumber, tolerant, debug);
4396  } catch (std::exception& e) {
4397  exMsg << e.what ();
4398  localBannerReadSuccess = 0;
4399  }
4400  // Make sure the input stream is the right kind of data.
4401  if (localBannerReadSuccess) {
4402  if (pBanner->matrixType () != "array") {
4403  exMsg << "The Matrix Market file does not contain dense matrix "
4404  "data. Its banner (first) line says that its matrix type is \""
4405  << pBanner->matrixType () << "\", rather that the required "
4406  "\"array\".";
4407  localBannerReadSuccess = 0;
4408  } else if (pBanner->dataType() == "pattern") {
4409  exMsg << "The Matrix Market file's banner (first) "
4410  "line claims that the matrix's data type is \"pattern\". This does "
4411  "not make sense for a dense matrix, yet the file reports the matrix "
4412  "as dense. The only valid data types for a dense matrix are "
4413  "\"real\", \"complex\", and \"integer\".";
4414  localBannerReadSuccess = 0;
4415  } else {
4416  // Encode the data type reported by the Banner as the
4417  // third element of the dimensions Tuple.
4418  dims[2] = encodeDataType (pBanner->dataType ());
4419  }
4420  } // if we successfully read the banner line
4421 
4422  // At this point, we've successfully read the banner line.
4423  // Now read the dimensions line.
4424  if (localBannerReadSuccess) {
4425  if (debug) {
4426  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4427  }
4428  // Keep reading lines from the input stream until we find
4429  // a non-comment line, or until we run out of lines. The
4430  // latter is an error, since every "array" format Matrix
4431  // Market file must have a dimensions line after the
4432  // banner (even if the matrix has zero rows or columns, or
4433  // zero entries).
4434  std::string line;
4435  bool commentLine = true;
4436 
4437  while (commentLine) {
4438  // Test whether it is even valid to read from the input
4439  // stream wrapping the line.
4440  if (in.eof () || in.fail ()) {
4441  exMsg << "Unable to get array dimensions line (at all) from line "
4442  << lineNumber << " of input stream. The input stream "
4443  << "claims that it is "
4444  << (in.eof() ? "at end-of-file." : "in a failed state.");
4445  localDimsReadSuccess = 0;
4446  } else {
4447  // Try to get the next line from the input stream.
4448  if (getline (in, line)) {
4449  ++lineNumber; // We did actually read a line.
4450  }
4451  // Is the current line a comment line? Ignore start
4452  // and size; they are only useful for reading the
4453  // actual matrix entries. (We could use them here as
4454  // an optimization, but we've chosen not to.)
4455  size_t start = 0, size = 0;
4456  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4457  } // whether we failed to read the line at all
4458  } // while the line we just read is a comment line
4459 
4460  //
4461  // Get <numRows> <numCols> from the line we just read.
4462  //
4463  std::istringstream istr (line);
4464 
4465  // Test whether it is even valid to read from the input
4466  // stream wrapping the line.
4467  if (istr.eof () || istr.fail ()) {
4468  exMsg << "Unable to read any data from line " << lineNumber
4469  << " of input; the line should contain the matrix dimensions "
4470  << "\"<numRows> <numCols>\".";
4471  localDimsReadSuccess = 0;
4472  } else { // It's valid to read from the line.
4473  GO theNumRows = 0;
4474  istr >> theNumRows; // Read in the number of rows.
4475  if (istr.fail ()) {
4476  exMsg << "Failed to get number of rows from line "
4477  << lineNumber << " of input; the line should contains the "
4478  << "matrix dimensions \"<numRows> <numCols>\".";
4479  localDimsReadSuccess = 0;
4480  } else { // We successfully read the number of rows
4481  dims[0] = theNumRows; // Save the number of rows
4482  if (istr.eof ()) { // Do we still have data to read?
4483  exMsg << "No more data after number of rows on line "
4484  << lineNumber << " of input; the line should contain the "
4485  << "matrix dimensions \"<numRows> <numCols>\".";
4486  localDimsReadSuccess = 0;
4487  } else { // Still data left to read; read in number of columns.
4488  GO theNumCols = 0;
4489  istr >> theNumCols; // Read in the number of columns
4490  if (istr.fail ()) {
4491  exMsg << "Failed to get number of columns from line "
4492  << lineNumber << " of input; the line should contain "
4493  << "the matrix dimensions \"<numRows> <numCols>\".";
4494  localDimsReadSuccess = 0;
4495  } else { // We successfully read the number of columns
4496  dims[1] = theNumCols; // Save the number of columns
4497  } // if istr.fail ()
4498  } // if istr.eof ()
4499  } // if we read the number of rows
4500  } // if the input stream wrapping the dims line was (in)valid
4501  } // if we successfully read the banner line
4502  } // if (myRank == 0)
4503 
4504  // Broadcast the matrix dimensions, the encoded data type, and
4505  // whether or not Proc 0 succeeded in reading the banner and
4506  // dimensions.
4507  Tuple<GO, 5> bannerDimsReadResult;
4508  if (myRank == 0) {
4509  bannerDimsReadResult[0] = dims[0]; // numRows
4510  bannerDimsReadResult[1] = dims[1]; // numCols
4511  bannerDimsReadResult[2] = dims[2]; // encoded data type
4512  bannerDimsReadResult[3] = localBannerReadSuccess;
4513  bannerDimsReadResult[4] = localDimsReadSuccess;
4514  }
4515  // Broadcast matrix dimensions and the encoded data type from
4516  // Proc 0 to all the MPI processes.
4517  broadcast (*comm, 0, bannerDimsReadResult);
4518 
4519  TEUCHOS_TEST_FOR_EXCEPTION(
4520  bannerDimsReadResult[3] == 0, std::runtime_error,
4521  "Failed to read banner line: " << exMsg.str ());
4522  TEUCHOS_TEST_FOR_EXCEPTION(
4523  bannerDimsReadResult[4] == 0, std::runtime_error,
4524  "Failed to read matrix dimensions line: " << exMsg.str ());
4525  if (myRank != 0) {
4526  dims[0] = bannerDimsReadResult[0];
4527  dims[1] = bannerDimsReadResult[1];
4528  dims[2] = bannerDimsReadResult[2];
4529  }
4530 
4531  // Tpetra objects want the matrix dimensions in these types.
4532  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4533  const size_t numCols = static_cast<size_t> (dims[1]);
4534 
4535  // Make a "Proc 0 owns everything" Map that we will use to
4536  // read in the multivector entries in the correct order on
4537  // Proc 0. This must be a collective
4538  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4539  if (map.is_null ()) {
4540  // The user didn't supply a Map. Make a contiguous
4541  // distributed Map for them, using the read-in multivector
4542  // dimensions.
4543  if (node.is_null ()) {
4544  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4545  } else {
4546  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm, node);
4547  }
4548  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4549  // At this point, map exists and has a nonnull node.
4550  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4551  comm, map->getNode ());
4552  }
4553  else { // The user supplied a Map.
4554  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4555  }
4556 
4557  // Make a multivector X owned entirely by Proc 0.
4558  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4559 
4560  //
4561  // On Proc 0, read the Matrix Market data from the input
4562  // stream into the multivector X.
4563  //
4564  int localReadDataSuccess = 1;
4565  if (myRank == 0) {
4566  try {
4567  if (debug) {
4568  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4569  << endl;
4570  }
4571 
4572  // Make sure that we can get a 1-D view of X.
4573  TEUCHOS_TEST_FOR_EXCEPTION(
4574  ! X->isConstantStride (), std::logic_error,
4575  "Can't get a 1-D view of the entries of the MultiVector X on "
4576  "Process 0, because the stride between the columns of X is not "
4577  "constant. This shouldn't happen because we just created X and "
4578  "haven't filled it in yet. Please report this bug to the Tpetra "
4579  "developers.");
4580 
4581  // Get a writeable 1-D view of the entries of X. Rank 0
4582  // owns all of them. The view will expire at the end of
4583  // scope, so (if necessary) it will be written back to X
4584  // at this time.
4585  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4586  TEUCHOS_TEST_FOR_EXCEPTION(
4587  as<global_size_t> (X_view.size ()) < numRows * numCols,
4588  std::logic_error,
4589  "The view of X has size " << X_view << " which is not enough to "
4590  "accommodate the expected number of entries numRows*numCols = "
4591  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4592  "Please report this bug to the Tpetra developers.");
4593  const size_t stride = X->getStride ();
4594 
4595  // The third element of the dimensions Tuple encodes the data
4596  // type reported by the Banner: "real" == 0, "complex" == 1,
4597  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4598  // allow dense matrices to be pattern matrices, so dims[2] ==
4599  // 0 or 1. We've already checked for this above.
4600  const bool isComplex = (dims[2] == 1);
4601  size_type count = 0, curRow = 0, curCol = 0;
4602 
4603  std::string line;
4604  while (getline (in, line)) {
4605  ++lineNumber;
4606  // Is the current line a comment line? If it's not,
4607  // line.substr(start,size) contains the data.
4608  size_t start = 0, size = 0;
4609  const bool commentLine =
4610  checkCommentLine (line, start, size, lineNumber, tolerant);
4611  if (! commentLine) {
4612  // Make sure we have room in which to put the new matrix
4613  // entry. We check this only after checking for a
4614  // comment line, because there may be one or more
4615  // comment lines at the end of the file. In tolerant
4616  // mode, we simply ignore any extra data.
4617  if (count >= X_view.size()) {
4618  if (tolerant) {
4619  break;
4620  }
4621  else {
4622  TEUCHOS_TEST_FOR_EXCEPTION(
4623  count >= X_view.size(),
4624  std::runtime_error,
4625  "The Matrix Market input stream has more data in it than "
4626  "its metadata reported. Current line number is "
4627  << lineNumber << ".");
4628  }
4629  }
4630 
4631  // mfh 19 Dec 2012: Ignore everything up to the initial
4632  // colon. writeDense() has the option to print out the
4633  // global row index in front of each entry, followed by
4634  // a colon and space.
4635  {
4636  const size_t pos = line.substr (start, size).find (':');
4637  if (pos != std::string::npos) {
4638  start = pos+1;
4639  }
4640  }
4641  std::istringstream istr (line.substr (start, size));
4642  // Does the line contain anything at all? Can we
4643  // safely read from the input stream wrapping the
4644  // line?
4645  if (istr.eof() || istr.fail()) {
4646  // In tolerant mode, simply ignore the line.
4647  if (tolerant) {
4648  break;
4649  }
4650  // We repeat the full test here so the exception
4651  // message is more informative.
4652  TEUCHOS_TEST_FOR_EXCEPTION(
4653  ! tolerant && (istr.eof() || istr.fail()),
4654  std::runtime_error,
4655  "Line " << lineNumber << " of the Matrix Market file is "
4656  "empty, or we cannot read from it for some other reason.");
4657  }
4658  // Current matrix entry to read in.
4659  ST val = STS::zero();
4660  // Real and imaginary parts of the current matrix entry.
4661  // The imaginary part is zero if the matrix is real-valued.
4662  MT real = STM::zero(), imag = STM::zero();
4663 
4664  // isComplex refers to the input stream's data, not to
4665  // the scalar type S. It's OK to read real-valued
4666  // data into a matrix storing complex-valued data; in
4667  // that case, all entries' imaginary parts are zero.
4668  if (isComplex) {
4669  // STS::real() and STS::imag() return a copy of
4670  // their respective components, not a writeable
4671  // reference. Otherwise we could just assign to
4672  // them using the istream extraction operator (>>).
4673  // That's why we have separate magnitude type "real"
4674  // and "imag" variables.
4675 
4676  // Attempt to read the real part of the current entry.
4677  istr >> real;
4678  if (istr.fail()) {
4679  TEUCHOS_TEST_FOR_EXCEPTION(
4680  ! tolerant && istr.eof(), std::runtime_error,
4681  "Failed to get the real part of a complex-valued matrix "
4682  "entry from line " << lineNumber << " of the Matrix Market "
4683  "file.");
4684  // In tolerant mode, just skip bad lines.
4685  if (tolerant) {
4686  break;
4687  }
4688  } else if (istr.eof()) {
4689  TEUCHOS_TEST_FOR_EXCEPTION(
4690  ! tolerant && istr.eof(), std::runtime_error,
4691  "Missing imaginary part of a complex-valued matrix entry "
4692  "on line " << lineNumber << " of the Matrix Market file.");
4693  // In tolerant mode, let any missing imaginary part be 0.
4694  } else {
4695  // Attempt to read the imaginary part of the current
4696  // matrix entry.
4697  istr >> imag;
4698  TEUCHOS_TEST_FOR_EXCEPTION(
4699  ! tolerant && istr.fail(), std::runtime_error,
4700  "Failed to get the imaginary part of a complex-valued "
4701  "matrix entry from line " << lineNumber << " of the "
4702  "Matrix Market file.");
4703  // In tolerant mode, let any missing or corrupted
4704  // imaginary part be 0.
4705  }
4706  } else { // Matrix Market file contains real-valued data.
4707  // Attempt to read the current matrix entry.
4708  istr >> real;
4709  TEUCHOS_TEST_FOR_EXCEPTION(
4710  ! tolerant && istr.fail(), std::runtime_error,
4711  "Failed to get a real-valued matrix entry from line "
4712  << lineNumber << " of the Matrix Market file.");
4713  // In tolerant mode, simply ignore the line if
4714  // we failed to read a matrix entry.
4715  if (istr.fail() && tolerant) {
4716  break;
4717  }
4718  }
4719  // In tolerant mode, we simply let pass through whatever
4720  // data we got.
4721  TEUCHOS_TEST_FOR_EXCEPTION(
4722  ! tolerant && istr.fail(), std::runtime_error,
4723  "Failed to read matrix data from line " << lineNumber
4724  << " of the Matrix Market file.");
4725 
4726  // Assign val = ST(real, imag).
4727  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4728 
4729  curRow = count % numRows;
4730  curCol = count / numRows;
4731  X_view[curRow + curCol*stride] = val;
4732  ++count;
4733  } // if not a comment line
4734  } // while there are still lines in the file, get the next one
4735 
4736  TEUCHOS_TEST_FOR_EXCEPTION(
4737  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4738  std::runtime_error,
4739  "The Matrix Market metadata reports that the dense matrix is "
4740  << numRows << " x " << numCols << ", and thus has "
4741  << numRows*numCols << " total entries, but we only found " << count
4742  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4743  } catch (std::exception& e) {
4744  exMsg << e.what ();
4745  localReadDataSuccess = 0;
4746  }
4747  } // if (myRank == 0)
4748 
4749  if (debug) {
4750  *err << myRank << ": readDenseImpl: done reading data" << endl;
4751  }
4752 
4753  // Synchronize on whether Proc 0 successfully read the data.
4754  int globalReadDataSuccess = localReadDataSuccess;
4755  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4756  TEUCHOS_TEST_FOR_EXCEPTION(
4757  globalReadDataSuccess == 0, std::runtime_error,
4758  "Failed to read the multivector's data: " << exMsg.str ());
4759 
4760  // If there's only one MPI process and the user didn't supply
4761  // a Map (i.e., pMap is null), we're done. Set pMap to the
4762  // Map used to distribute X, and return X.
4763  if (comm->getSize () == 1 && map.is_null ()) {
4764  map = proc0Map;
4765  if (! err.is_null ()) {
4766  err->popTab ();
4767  }
4768  if (debug) {
4769  *err << myRank << ": readDenseImpl: done" << endl;
4770  }
4771  if (! err.is_null ()) {
4772  err->popTab ();
4773  }
4774  return X;
4775  }
4776 
4777  if (debug) {
4778  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4779  }
4780 
4781  // Make a multivector Y with the distributed map pMap.
4782  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4783 
4784  if (debug) {
4785  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4786  }
4787 
4788  // Make an Export object that will export X to Y. First
4789  // argument is the source map, second argument is the target
4790  // map.
4791  Export<LO, GO, NT> exporter (proc0Map, map, err);
4792 
4793  if (debug) {
4794  *err << myRank << ": readDenseImpl: Exporting" << endl;
4795  }
4796  // Export X into Y.
4797  Y->doExport (*X, exporter, INSERT);
4798 
4799  if (! err.is_null ()) {
4800  err->popTab ();
4801  }
4802  if (debug) {
4803  *err << myRank << ": readDenseImpl: done" << endl;
4804  }
4805  if (! err.is_null ()) {
4806  err->popTab ();
4807  }
4808 
4809  // Y is distributed over all process(es) in the communicator.
4810  return Y;
4811  }
4812 
4813 
4814  template<class VectorScalarType>
4815  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4818  node_type> >
4819  readVectorImpl (std::istream& in,
4820  const Teuchos::RCP<const comm_type>& comm,
4821  const Teuchos::RCP<node_type>& node, // allowed to be null
4822  Teuchos::RCP<const map_type>& map,
4823  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4824  const bool tolerant=false,
4825  const bool debug=false)
4826  {
4827  using Teuchos::MatrixMarket::Banner;
4828  using Teuchos::MatrixMarket::checkCommentLine;
4829  using Teuchos::as;
4830  using Teuchos::broadcast;
4831  using Teuchos::outArg;
4832  using Teuchos::RCP;
4833  using Teuchos::Tuple;
4834  using std::endl;
4835  typedef VectorScalarType ST;
4836  typedef local_ordinal_type LO;
4837  typedef global_ordinal_type GO;
4838  typedef node_type NT;
4839  typedef Teuchos::ScalarTraits<ST> STS;
4840  typedef typename STS::magnitudeType MT;
4841  typedef Teuchos::ScalarTraits<MT> STM;
4842  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4843 
4844  // Rank 0 is the only (MPI) process allowed to read from the
4845  // input stream.
4846  const int myRank = comm->getRank ();
4847 
4848  if (! err.is_null ()) {
4849  err->pushTab ();
4850  }
4851  if (debug) {
4852  *err << myRank << ": readVectorImpl" << endl;
4853  }
4854  if (! err.is_null ()) {
4855  err->pushTab ();
4856  }
4857 
4858  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4859  // instances be identical and that the Node instances be
4860  // identical. The essential condition is more complicated to
4861  // test and isn't the same for all Node types. Thus, we just
4862  // leave it up to the user.
4863 
4864  // // If map is nonnull, check the precondition that its
4865  // // communicator resp. node equal comm resp. node. Checking
4866  // // now avoids doing a lot of file reading before we detect the
4867  // // violated precondition.
4868  // TEUCHOS_TEST_FOR_EXCEPTION(
4869  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4870  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4871  // "communicator and node must equal the supplied communicator resp. "
4872  // "node.");
4873 
4874  // Process 0 will read in the matrix dimensions from the file,
4875  // and broadcast them to all ranks in the given communicator.
4876  // There are only 2 dimensions in the matrix, but we use the
4877  // third element of the Tuple to encode the banner's reported
4878  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4879  // (same as "real"). We don't allow pattern matrices (i.e.,
4880  // graphs) since they only make sense for sparse data.
4881  Tuple<GO, 3> dims;
4882  dims[0] = 0;
4883  dims[1] = 0;
4884 
4885  // Current line number in the input stream. Only valid on
4886  // Proc 0. Various calls will modify this depending on the
4887  // number of lines that are read from the input stream.
4888  size_t lineNumber = 1;
4889 
4890  // Capture errors and their messages on Proc 0.
4891  std::ostringstream exMsg;
4892  int localBannerReadSuccess = 1;
4893  int localDimsReadSuccess = 1;
4894 
4895  // Only Proc 0 gets to read matrix data from the input stream.
4896  if (myRank == 0) {
4897  if (debug) {
4898  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4899  }
4900 
4901  // The "Banner" tells you whether the input stream
4902  // represents a dense matrix, the symmetry type of the
4903  // matrix, and the type of the data it contains.
4904  RCP<const Banner> pBanner;
4905  try {
4906  pBanner = readBanner (in, lineNumber, tolerant, debug);
4907  } catch (std::exception& e) {
4908  exMsg << e.what ();
4909  localBannerReadSuccess = 0;
4910  }
4911  // Make sure the input stream is the right kind of data.
4912  if (localBannerReadSuccess) {
4913  if (pBanner->matrixType () != "array") {
4914  exMsg << "The Matrix Market file does not contain dense matrix "
4915  "data. Its banner (first) line says that its matrix type is \""
4916  << pBanner->matrixType () << "\", rather that the required "
4917  "\"array\".";
4918  localBannerReadSuccess = 0;
4919  } else if (pBanner->dataType() == "pattern") {
4920  exMsg << "The Matrix Market file's banner (first) "
4921  "line claims that the matrix's data type is \"pattern\". This does "
4922  "not make sense for a dense matrix, yet the file reports the matrix "
4923  "as dense. The only valid data types for a dense matrix are "
4924  "\"real\", \"complex\", and \"integer\".";
4925  localBannerReadSuccess = 0;
4926  } else {
4927  // Encode the data type reported by the Banner as the
4928  // third element of the dimensions Tuple.
4929  dims[2] = encodeDataType (pBanner->dataType ());
4930  }
4931  } // if we successfully read the banner line
4932 
4933  // At this point, we've successfully read the banner line.
4934  // Now read the dimensions line.
4935  if (localBannerReadSuccess) {
4936  if (debug) {
4937  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4938  }
4939  // Keep reading lines from the input stream until we find
4940  // a non-comment line, or until we run out of lines. The
4941  // latter is an error, since every "array" format Matrix
4942  // Market file must have a dimensions line after the
4943  // banner (even if the matrix has zero rows or columns, or
4944  // zero entries).
4945  std::string line;
4946  bool commentLine = true;
4947 
4948  while (commentLine) {
4949  // Test whether it is even valid to read from the input
4950  // stream wrapping the line.
4951  if (in.eof () || in.fail ()) {
4952  exMsg << "Unable to get array dimensions line (at all) from line "
4953  << lineNumber << " of input stream. The input stream "
4954  << "claims that it is "
4955  << (in.eof() ? "at end-of-file." : "in a failed state.");
4956  localDimsReadSuccess = 0;
4957  } else {
4958  // Try to get the next line from the input stream.
4959  if (getline (in, line)) {
4960  ++lineNumber; // We did actually read a line.
4961  }
4962  // Is the current line a comment line? Ignore start
4963  // and size; they are only useful for reading the
4964  // actual matrix entries. (We could use them here as
4965  // an optimization, but we've chosen not to.)
4966  size_t start = 0, size = 0;
4967  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4968  } // whether we failed to read the line at all
4969  } // while the line we just read is a comment line
4970 
4971  //
4972  // Get <numRows> <numCols> from the line we just read.
4973  //
4974  std::istringstream istr (line);
4975 
4976  // Test whether it is even valid to read from the input
4977  // stream wrapping the line.
4978  if (istr.eof () || istr.fail ()) {
4979  exMsg << "Unable to read any data from line " << lineNumber
4980  << " of input; the line should contain the matrix dimensions "
4981  << "\"<numRows> <numCols>\".";
4982  localDimsReadSuccess = 0;
4983  } else { // It's valid to read from the line.
4984  GO theNumRows = 0;
4985  istr >> theNumRows; // Read in the number of rows.
4986  if (istr.fail ()) {
4987  exMsg << "Failed to get number of rows from line "
4988  << lineNumber << " of input; the line should contains the "
4989  << "matrix dimensions \"<numRows> <numCols>\".";
4990  localDimsReadSuccess = 0;
4991  } else { // We successfully read the number of rows
4992  dims[0] = theNumRows; // Save the number of rows
4993  if (istr.eof ()) { // Do we still have data to read?
4994  exMsg << "No more data after number of rows on line "
4995  << lineNumber << " of input; the line should contain the "
4996  << "matrix dimensions \"<numRows> <numCols>\".";
4997  localDimsReadSuccess = 0;
4998  } else { // Still data left to read; read in number of columns.
4999  GO theNumCols = 0;
5000  istr >> theNumCols; // Read in the number of columns
5001  if (istr.fail ()) {
5002  exMsg << "Failed to get number of columns from line "
5003  << lineNumber << " of input; the line should contain "
5004  << "the matrix dimensions \"<numRows> <numCols>\".";
5005  localDimsReadSuccess = 0;
5006  } else { // We successfully read the number of columns
5007  dims[1] = theNumCols; // Save the number of columns
5008  } // if istr.fail ()
5009  } // if istr.eof ()
5010  } // if we read the number of rows
5011  } // if the input stream wrapping the dims line was (in)valid
5012  } // if we successfully read the banner line
5013  } // if (myRank == 0)
5014 
5015  // Check if file has a Vector
5016  if (dims[1]!=1) {
5017  exMsg << "File does not contain a 1D Vector";
5018  localDimsReadSuccess = 0;
5019  }
5020 
5021  // Broadcast the matrix dimensions, the encoded data type, and
5022  // whether or not Proc 0 succeeded in reading the banner and
5023  // dimensions.
5024  Tuple<GO, 5> bannerDimsReadResult;
5025  if (myRank == 0) {
5026  bannerDimsReadResult[0] = dims[0]; // numRows
5027  bannerDimsReadResult[1] = dims[1]; // numCols
5028  bannerDimsReadResult[2] = dims[2]; // encoded data type
5029  bannerDimsReadResult[3] = localBannerReadSuccess;
5030  bannerDimsReadResult[4] = localDimsReadSuccess;
5031  }
5032 
5033  // Broadcast matrix dimensions and the encoded data type from
5034  // Proc 0 to all the MPI processes.
5035  broadcast (*comm, 0, bannerDimsReadResult);
5036 
5037  TEUCHOS_TEST_FOR_EXCEPTION(
5038  bannerDimsReadResult[3] == 0, std::runtime_error,
5039  "Failed to read banner line: " << exMsg.str ());
5040  TEUCHOS_TEST_FOR_EXCEPTION(
5041  bannerDimsReadResult[4] == 0, std::runtime_error,
5042  "Failed to read matrix dimensions line: " << exMsg.str ());
5043  if (myRank != 0) {
5044  dims[0] = bannerDimsReadResult[0];
5045  dims[1] = bannerDimsReadResult[1];
5046  dims[2] = bannerDimsReadResult[2];
5047  }
5048 
5049  // Tpetra objects want the matrix dimensions in these types.
5050  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
5051  const size_t numCols = static_cast<size_t> (dims[1]);
5052 
5053  // Make a "Proc 0 owns everything" Map that we will use to
5054  // read in the multivector entries in the correct order on
5055  // Proc 0. This must be a collective
5056  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
5057  if (map.is_null ()) {
5058  // The user didn't supply a Map. Make a contiguous
5059  // distributed Map for them, using the read-in multivector
5060  // dimensions.
5061  if (node.is_null ()) {
5062  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
5063  } else {
5064  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm, node);
5065  }
5066  const size_t localNumRows = (myRank == 0) ? numRows : 0;
5067  // At this point, map exists and has a nonnull node.
5068  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
5069  comm, map->getNode ());
5070  }
5071  else { // The user supplied a Map.
5072  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
5073  }
5074 
5075  // Make a multivector X owned entirely by Proc 0.
5076  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
5077 
5078  //
5079  // On Proc 0, read the Matrix Market data from the input
5080  // stream into the multivector X.
5081  //
5082  int localReadDataSuccess = 1;
5083  if (myRank == 0) {
5084  try {
5085  if (debug) {
5086  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
5087  << endl;
5088  }
5089 
5090  // Make sure that we can get a 1-D view of X.
5091  TEUCHOS_TEST_FOR_EXCEPTION(
5092  ! X->isConstantStride (), std::logic_error,
5093  "Can't get a 1-D view of the entries of the MultiVector X on "
5094  "Process 0, because the stride between the columns of X is not "
5095  "constant. This shouldn't happen because we just created X and "
5096  "haven't filled it in yet. Please report this bug to the Tpetra "
5097  "developers.");
5098 
5099  // Get a writeable 1-D view of the entries of X. Rank 0
5100  // owns all of them. The view will expire at the end of
5101  // scope, so (if necessary) it will be written back to X
5102  // at this time.
5103  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
5104  TEUCHOS_TEST_FOR_EXCEPTION(
5105  as<global_size_t> (X_view.size ()) < numRows * numCols,
5106  std::logic_error,
5107  "The view of X has size " << X_view << " which is not enough to "
5108  "accommodate the expected number of entries numRows*numCols = "
5109  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
5110  "Please report this bug to the Tpetra developers.");
5111  const size_t stride = X->getStride ();
5112 
5113  // The third element of the dimensions Tuple encodes the data
5114  // type reported by the Banner: "real" == 0, "complex" == 1,
5115  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
5116  // allow dense matrices to be pattern matrices, so dims[2] ==
5117  // 0 or 1. We've already checked for this above.
5118  const bool isComplex = (dims[2] == 1);
5119  size_type count = 0, curRow = 0, curCol = 0;
5120 
5121  std::string line;
5122  while (getline (in, line)) {
5123  ++lineNumber;
5124  // Is the current line a comment line? If it's not,
5125  // line.substr(start,size) contains the data.
5126  size_t start = 0, size = 0;
5127  const bool commentLine =
5128  checkCommentLine (line, start, size, lineNumber, tolerant);
5129  if (! commentLine) {
5130  // Make sure we have room in which to put the new matrix
5131  // entry. We check this only after checking for a
5132  // comment line, because there may be one or more
5133  // comment lines at the end of the file. In tolerant
5134  // mode, we simply ignore any extra data.
5135  if (count >= X_view.size()) {
5136  if (tolerant) {
5137  break;
5138  }
5139  else {
5140  TEUCHOS_TEST_FOR_EXCEPTION(
5141  count >= X_view.size(),
5142  std::runtime_error,
5143  "The Matrix Market input stream has more data in it than "
5144  "its metadata reported. Current line number is "
5145  << lineNumber << ".");
5146  }
5147  }
5148 
5149  // mfh 19 Dec 2012: Ignore everything up to the initial
5150  // colon. writeDense() has the option to print out the
5151  // global row index in front of each entry, followed by
5152  // a colon and space.
5153  {
5154  const size_t pos = line.substr (start, size).find (':');
5155  if (pos != std::string::npos) {
5156  start = pos+1;
5157  }
5158  }
5159  std::istringstream istr (line.substr (start, size));
5160  // Does the line contain anything at all? Can we
5161  // safely read from the input stream wrapping the
5162  // line?
5163  if (istr.eof() || istr.fail()) {
5164  // In tolerant mode, simply ignore the line.
5165  if (tolerant) {
5166  break;
5167  }
5168  // We repeat the full test here so the exception
5169  // message is more informative.
5170  TEUCHOS_TEST_FOR_EXCEPTION(
5171  ! tolerant && (istr.eof() || istr.fail()),
5172  std::runtime_error,
5173  "Line " << lineNumber << " of the Matrix Market file is "
5174  "empty, or we cannot read from it for some other reason.");
5175  }
5176  // Current matrix entry to read in.
5177  ST val = STS::zero();
5178  // Real and imaginary parts of the current matrix entry.
5179  // The imaginary part is zero if the matrix is real-valued.
5180  MT real = STM::zero(), imag = STM::zero();
5181 
5182  // isComplex refers to the input stream's data, not to
5183  // the scalar type S. It's OK to read real-valued
5184  // data into a matrix storing complex-valued data; in
5185  // that case, all entries' imaginary parts are zero.
5186  if (isComplex) {
5187  // STS::real() and STS::imag() return a copy of
5188  // their respective components, not a writeable
5189  // reference. Otherwise we could just assign to
5190  // them using the istream extraction operator (>>).
5191  // That's why we have separate magnitude type "real"
5192  // and "imag" variables.
5193 
5194  // Attempt to read the real part of the current entry.
5195  istr >> real;
5196  if (istr.fail()) {
5197  TEUCHOS_TEST_FOR_EXCEPTION(
5198  ! tolerant && istr.eof(), std::runtime_error,
5199  "Failed to get the real part of a complex-valued matrix "
5200  "entry from line " << lineNumber << " of the Matrix Market "
5201  "file.");
5202  // In tolerant mode, just skip bad lines.
5203  if (tolerant) {
5204  break;
5205  }
5206  } else if (istr.eof()) {
5207  TEUCHOS_TEST_FOR_EXCEPTION(
5208  ! tolerant && istr.eof(), std::runtime_error,
5209  "Missing imaginary part of a complex-valued matrix entry "
5210  "on line " << lineNumber << " of the Matrix Market file.");
5211  // In tolerant mode, let any missing imaginary part be 0.
5212  } else {
5213  // Attempt to read the imaginary part of the current
5214  // matrix entry.
5215  istr >> imag;
5216  TEUCHOS_TEST_FOR_EXCEPTION(
5217  ! tolerant && istr.fail(), std::runtime_error,
5218  "Failed to get the imaginary part of a complex-valued "
5219  "matrix entry from line " << lineNumber << " of the "
5220  "Matrix Market file.");
5221  // In tolerant mode, let any missing or corrupted
5222  // imaginary part be 0.
5223  }
5224  } else { // Matrix Market file contains real-valued data.
5225  // Attempt to read the current matrix entry.
5226  istr >> real;
5227  TEUCHOS_TEST_FOR_EXCEPTION(
5228  ! tolerant && istr.fail(), std::runtime_error,
5229  "Failed to get a real-valued matrix entry from line "
5230  << lineNumber << " of the Matrix Market file.");
5231  // In tolerant mode, simply ignore the line if
5232  // we failed to read a matrix entry.
5233  if (istr.fail() && tolerant) {
5234  break;
5235  }
5236  }
5237  // In tolerant mode, we simply let pass through whatever
5238  // data we got.
5239  TEUCHOS_TEST_FOR_EXCEPTION(
5240  ! tolerant && istr.fail(), std::runtime_error,
5241  "Failed to read matrix data from line " << lineNumber
5242  << " of the Matrix Market file.");
5243 
5244  // Assign val = ST(real, imag).
5245  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5246 
5247  curRow = count % numRows;
5248  curCol = count / numRows;
5249  X_view[curRow + curCol*stride] = val;
5250  ++count;
5251  } // if not a comment line
5252  } // while there are still lines in the file, get the next one
5253 
5254  TEUCHOS_TEST_FOR_EXCEPTION(
5255  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5256  std::runtime_error,
5257  "The Matrix Market metadata reports that the dense matrix is "
5258  << numRows << " x " << numCols << ", and thus has "
5259  << numRows*numCols << " total entries, but we only found " << count
5260  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5261  } catch (std::exception& e) {
5262  exMsg << e.what ();
5263  localReadDataSuccess = 0;
5264  }
5265  } // if (myRank == 0)
5266 
5267  if (debug) {
5268  *err << myRank << ": readVectorImpl: done reading data" << endl;
5269  }
5270 
5271  // Synchronize on whether Proc 0 successfully read the data.
5272  int globalReadDataSuccess = localReadDataSuccess;
5273  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5274  TEUCHOS_TEST_FOR_EXCEPTION(
5275  globalReadDataSuccess == 0, std::runtime_error,
5276  "Failed to read the multivector's data: " << exMsg.str ());
5277 
5278  // If there's only one MPI process and the user didn't supply
5279  // a Map (i.e., pMap is null), we're done. Set pMap to the
5280  // Map used to distribute X, and return X.
5281  if (comm->getSize () == 1 && map.is_null ()) {
5282  map = proc0Map;
5283  if (! err.is_null ()) {
5284  err->popTab ();
5285  }
5286  if (debug) {
5287  *err << myRank << ": readVectorImpl: done" << endl;
5288  }
5289  if (! err.is_null ()) {
5290  err->popTab ();
5291  }
5292  return X;
5293  }
5294 
5295  if (debug) {
5296  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5297  }
5298 
5299  // Make a multivector Y with the distributed map pMap.
5300  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5301 
5302  if (debug) {
5303  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5304  }
5305 
5306  // Make an Export object that will export X to Y. First
5307  // argument is the source map, second argument is the target
5308  // map.
5309  Export<LO, GO, NT> exporter (proc0Map, map, err);
5310 
5311  if (debug) {
5312  *err << myRank << ": readVectorImpl: Exporting" << endl;
5313  }
5314  // Export X into Y.
5315  Y->doExport (*X, exporter, INSERT);
5316 
5317  if (! err.is_null ()) {
5318  err->popTab ();
5319  }
5320  if (debug) {
5321  *err << myRank << ": readVectorImpl: done" << endl;
5322  }
5323  if (! err.is_null ()) {
5324  err->popTab ();
5325  }
5326 
5327  // Y is distributed over all process(es) in the communicator.
5328  return Y;
5329  }
5330 
5331  public:
5352  static Teuchos::RCP<const map_type>
5353  readMap (std::istream& in,
5354  const Teuchos::RCP<const comm_type>& comm,
5355  const bool tolerant=false,
5356  const bool debug=false)
5357  {
5358  Teuchos::RCP<Teuchos::FancyOStream> err =
5359  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5360  return readMap (in, comm, err, tolerant, debug);
5361  }
5362 
5365  static Teuchos::RCP<const map_type>
5366  readMap (std::istream& in,
5367  const Teuchos::RCP<const comm_type>& comm,
5368  const Teuchos::RCP<node_type>& node,
5369  const bool tolerant=false,
5370  const bool debug=false)
5371  {
5372  Teuchos::RCP<Teuchos::FancyOStream> err =
5373  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5374  return readMap (in, comm, node, err, tolerant, debug);
5375  }
5376 
5402  static Teuchos::RCP<const map_type>
5403  readMap (std::istream& in,
5404  const Teuchos::RCP<const comm_type>& comm,
5405  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5406  const bool tolerant=false,
5407  const bool debug=false)
5408  {
5409  return readMap (in, comm, Teuchos::null, err, tolerant, debug);
5410  }
5411 
5414  static Teuchos::RCP<const map_type>
5415  readMap (std::istream& in,
5416  const Teuchos::RCP<const comm_type>& comm,
5417  const Teuchos::RCP<node_type>& node,
5418  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5419  const bool tolerant=false,
5420  const bool debug=false)
5421  {
5422  using Teuchos::arcp;
5423  using Teuchos::Array;
5424  using Teuchos::ArrayRCP;
5425  using Teuchos::as;
5426  using Teuchos::broadcast;
5427  using Teuchos::Comm;
5428  using Teuchos::CommRequest;
5429  using Teuchos::inOutArg;
5430  using Teuchos::ireceive;
5431  using Teuchos::outArg;
5432  using Teuchos::RCP;
5433  using Teuchos::receive;
5434  using Teuchos::reduceAll;
5435  using Teuchos::REDUCE_MIN;
5436  using Teuchos::isend;
5437  using Teuchos::SerialComm;
5438  using Teuchos::toString;
5439  using Teuchos::wait;
5440  using std::endl;
5441  typedef Tpetra::global_size_t GST;
5442  typedef ptrdiff_t int_type; // Can hold int and GO
5443  typedef local_ordinal_type LO;
5444  typedef global_ordinal_type GO;
5445  typedef node_type NT;
5447 
5448  const int numProcs = comm->getSize ();
5449  const int myRank = comm->getRank ();
5450 
5451  if (err.is_null ()) {
5452  err->pushTab ();
5453  }
5454  if (debug) {
5455  std::ostringstream os;
5456  os << myRank << ": readMap: " << endl;
5457  *err << os.str ();
5458  }
5459  if (err.is_null ()) {
5460  err->pushTab ();
5461  }
5462 
5463  // Tag for receive-size / send-size messages. writeMap used
5464  // tags 1337 and 1338; we count up from there.
5465  const int sizeTag = 1339;
5466  // Tag for receive-data / send-data messages.
5467  const int dataTag = 1340;
5468 
5469  // These are for sends on Process 0, and for receives on all
5470  // other processes. sizeReq is for the {receive,send}-size
5471  // message, and dataReq is for the message containing the
5472  // actual GIDs to belong to the receiving process.
5473  RCP<CommRequest<int> > sizeReq;
5474  RCP<CommRequest<int> > dataReq;
5475 
5476  // Each process will have to receive the number of GIDs to
5477  // expect. Thus, we can post the receives now, and cancel
5478  // them if something should go wrong in the meantime.
5479  ArrayRCP<int_type> numGidsToRecv (1);
5480  numGidsToRecv[0] = 0;
5481  if (myRank != 0) {
5482  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5483  }
5484 
5485  int readSuccess = 1;
5486  std::ostringstream exMsg;
5487  RCP<MV> data; // Will only be valid on Proc 0
5488  if (myRank == 0) {
5489  // If we want to reuse readDenseImpl, we have to make a
5490  // communicator that only contains Proc 0. Otherwise,
5491  // readDenseImpl will redistribute the data to all
5492  // processes. While we eventually want that, neither we nor
5493  // readDenseImpl know the correct Map to use at the moment.
5494  // That depends on the second column of the multivector.
5495  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5496  try {
5497  RCP<const map_type> dataMap;
5498  // This is currently the only place where we use the
5499  // 'tolerant' argument. Later, if we want to be clever,
5500  // we could have tolerant mode allow PIDs out of order.
5501  data = readDenseImpl<GO> (in, proc0Comm, node, dataMap,
5502  err, tolerant, debug);
5503  (void) dataMap; // Silence "unused" warnings
5504  if (data.is_null ()) {
5505  readSuccess = 0;
5506  exMsg << "readDenseImpl() returned null." << endl;
5507  }
5508  } catch (std::exception& e) {
5509  readSuccess = 0;
5510  exMsg << e.what () << endl;
5511  }
5512  }
5513 
5514  // Map from PID to all the GIDs for that PID.
5515  // Only populated on Process 0.
5516  std::map<int, Array<GO> > pid2gids;
5517 
5518  // The index base must be the global minimum GID.
5519  // We will compute this on Process 0 and broadcast,
5520  // so that all processes can set up the Map.
5521  int_type globalNumGIDs = 0;
5522 
5523  // The index base must be the global minimum GID.
5524  // We will compute this on Process 0 and broadcast,
5525  // so that all processes can set up the Map.
5526  GO indexBase = 0;
5527 
5528  // Process 0: If the above read of the MultiVector succeeded,
5529  // extract the GIDs and PIDs into pid2gids, and find the
5530  // global min GID.
5531  if (myRank == 0 && readSuccess == 1) {
5532  if (data->getNumVectors () == 2) { // Map format 1.0
5533  ArrayRCP<const GO> GIDs = data->getData (0);
5534  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5535  globalNumGIDs = GIDs.size ();
5536 
5537  // Start computing the global min GID, while collecting
5538  // the GIDs for each PID.
5539  if (globalNumGIDs > 0) {
5540  const int pid = static_cast<int> (PIDs[0]);
5541 
5542  if (pid < 0 || pid >= numProcs) {
5543  readSuccess = 0;
5544  exMsg << "Tpetra::MatrixMarket::readMap: "
5545  << "Encountered invalid PID " << pid << "." << endl;
5546  }
5547  else {
5548  const GO gid = GIDs[0];
5549  pid2gids[pid].push_back (gid);
5550  indexBase = gid; // the current min GID
5551  }
5552  }
5553  if (readSuccess == 1) {
5554  // Collect the rest of the GIDs for each PID, and compute
5555  // the global min GID.
5556  for (size_type k = 1; k < globalNumGIDs; ++k) {
5557  const int pid = static_cast<int> (PIDs[k]);
5558  if (pid < 0 || pid >= numProcs) {
5559  readSuccess = 0;
5560  exMsg << "Tpetra::MatrixMarket::readMap: "
5561  << "Encountered invalid PID " << pid << "." << endl;
5562  }
5563  else {
5564  const int_type gid = GIDs[k];
5565  pid2gids[pid].push_back (gid);
5566  if (gid < indexBase) {
5567  indexBase = gid; // the current min GID
5568  }
5569  }
5570  }
5571  }
5572  }
5573  else if (data->getNumVectors () == 1) { // Map format 2.0
5574  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5575  readSuccess = 0;
5576  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5577  "wrong format (for Map format 2.0). The global number of rows "
5578  "in the MultiVector must be even (divisible by 2)." << endl;
5579  }
5580  else {
5581  ArrayRCP<const GO> theData = data->getData (0);
5582  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5583  static_cast<GO> (2);
5584 
5585  // Start computing the global min GID, while
5586  // collecting the GIDs for each PID.
5587  if (globalNumGIDs > 0) {
5588  const int pid = static_cast<int> (theData[1]);
5589  if (pid < 0 || pid >= numProcs) {
5590  readSuccess = 0;
5591  exMsg << "Tpetra::MatrixMarket::readMap: "
5592  << "Encountered invalid PID " << pid << "." << endl;
5593  }
5594  else {
5595  const GO gid = theData[0];
5596  pid2gids[pid].push_back (gid);
5597  indexBase = gid; // the current min GID
5598  }
5599  }
5600  // Collect the rest of the GIDs for each PID, and
5601  // compute the global min GID.
5602  for (int_type k = 1; k < globalNumGIDs; ++k) {
5603  const int pid = static_cast<int> (theData[2*k + 1]);
5604  if (pid < 0 || pid >= numProcs) {
5605  readSuccess = 0;
5606  exMsg << "Tpetra::MatrixMarket::readMap: "
5607  << "Encountered invalid PID " << pid << "." << endl;
5608  }
5609  else {
5610  const GO gid = theData[2*k];
5611  pid2gids[pid].push_back (gid);
5612  if (gid < indexBase) {
5613  indexBase = gid; // the current min GID
5614  }
5615  }
5616  } // for each GID
5617  } // if the amount of data is correct
5618  }
5619  else {
5620  readSuccess = 0;
5621  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5622  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5623  "the old Map format 1.0).";
5624  }
5625  } // myRank is zero
5626 
5627  // Broadcast the indexBase, the global number of GIDs, and the
5628  // current success status. Use int_type for all of these.
5629  {
5630  int_type readResults[3];
5631  readResults[0] = static_cast<int_type> (indexBase);
5632  readResults[1] = static_cast<int_type> (globalNumGIDs);
5633  readResults[2] = static_cast<int_type> (readSuccess);
5634  broadcast<int, int_type> (*comm, 0, 3, readResults);
5635 
5636  indexBase = static_cast<GO> (readResults[0]);
5637  globalNumGIDs = static_cast<int_type> (readResults[1]);
5638  readSuccess = static_cast<int> (readResults[2]);
5639  }
5640 
5641  // Unwinding the stack will invoke sizeReq's destructor, which
5642  // will cancel the receive-size request on all processes that
5643  // posted it.
5644  TEUCHOS_TEST_FOR_EXCEPTION(
5645  readSuccess != 1, std::runtime_error,
5646  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5647  "following exception message: " << exMsg.str ());
5648 
5649  if (myRank == 0) {
5650  // Proc 0: Send each process' number of GIDs to that process.
5651  for (int p = 1; p < numProcs; ++p) {
5652  ArrayRCP<int_type> numGidsToSend (1);
5653 
5654  typename std::map<int, Array<GO> >::const_iterator it = pid2gids.find (p);
5655  if (it == pid2gids.end ()) {
5656  numGidsToSend[0] = 0;
5657  } else {
5658  numGidsToSend[0] = it->second.size ();
5659  }
5660  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5661  wait<int> (*comm, outArg (sizeReq));
5662  }
5663  }
5664  else {
5665  // Wait on the receive-size message to finish.
5666  wait<int> (*comm, outArg (sizeReq));
5667  }
5668 
5669  // Allocate / get the array for my GIDs.
5670  // Only Process 0 will have its actual GIDs at this point.
5671  ArrayRCP<GO> myGids;
5672  int_type myNumGids = 0;
5673  if (myRank == 0) {
5674  GO* myGidsRaw = NULL;
5675 
5676  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5677  if (it != pid2gids.end ()) {
5678  myGidsRaw = it->second.getRawPtr ();
5679  myNumGids = it->second.size ();
5680  // Nonowning ArrayRCP just views the Array.
5681  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5682  }
5683  }
5684  else { // myRank != 0
5685  myNumGids = numGidsToRecv[0];
5686  myGids = arcp<GO> (myNumGids);
5687  }
5688 
5689  if (myRank != 0) {
5690  // Post receive for data, now that we know how much data we
5691  // will receive. Only post receive if my process actually
5692  // has nonzero GIDs.
5693  if (myNumGids > 0) {
5694  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5695  }
5696  }
5697 
5698  for (int p = 1; p < numProcs; ++p) {
5699  if (myRank == 0) {
5700  ArrayRCP<GO> sendGids; // to send to Process p
5701  GO* sendGidsRaw = NULL;
5702  int_type numSendGids = 0;
5703 
5704  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5705  if (it != pid2gids.end ()) {
5706  numSendGids = it->second.size ();
5707  sendGidsRaw = it->second.getRawPtr ();
5708  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5709  }
5710  // Only send if that process actually has nonzero GIDs.
5711  if (numSendGids > 0) {
5712  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5713  }
5714  wait<int> (*comm, outArg (dataReq));
5715  }
5716  else if (myRank == p) {
5717  // Wait on my receive of GIDs to finish.
5718  wait<int> (*comm, outArg (dataReq));
5719  }
5720  } // for each process rank p in 1, 2, ..., numProcs-1
5721 
5722  if (debug) {
5723  std::ostringstream os;
5724  os << myRank << ": readMap: creating Map" << endl;
5725  *err << os.str ();
5726  }
5727  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5728  RCP<const map_type> newMap;
5729 
5730  // Create the Map; test whether the constructor threw. This
5731  // avoids deadlock and makes error reporting more readable.
5732 
5733  int lclSuccess = 1;
5734  int gblSuccess = 0; // output argument
5735  std::ostringstream errStrm;
5736  try {
5737  if (node.is_null ()) {
5738  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5739  }
5740  else {
5741  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm, node));
5742  }
5743  }
5744  catch (std::exception& e) {
5745  lclSuccess = 0;
5746  errStrm << "Process " << comm->getRank () << " threw an exception: "
5747  << e.what () << std::endl;
5748  }
5749  catch (...) {
5750  lclSuccess = 0;
5751  errStrm << "Process " << comm->getRank () << " threw an exception "
5752  "not a subclass of std::exception" << std::endl;
5753  }
5754  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5755  lclSuccess, Teuchos::outArg (gblSuccess));
5756  if (gblSuccess != 1) {
5757  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5758  }
5759  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5760 
5761  if (err.is_null ()) {
5762  err->popTab ();
5763  }
5764  if (debug) {
5765  std::ostringstream os;
5766  os << myRank << ": readMap: done" << endl;
5767  *err << os.str ();
5768  }
5769  if (err.is_null ()) {
5770  err->popTab ();
5771  }
5772  return newMap;
5773  }
5774 
5775  private:
5776 
5787  static int
5788  encodeDataType (const std::string& dataType)
5789  {
5790  if (dataType == "real" || dataType == "integer") {
5791  return 0;
5792  } else if (dataType == "complex") {
5793  return 1;
5794  } else if (dataType == "pattern") {
5795  return 2;
5796  } else {
5797  // We should never get here, since Banner validates the
5798  // reported data type and ensures it is one of the accepted
5799  // values.
5800  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5801  "Unrecognized Matrix Market data type \"" << dataType
5802  << "\". We should never get here. "
5803  "Please report this bug to the Tpetra developers.");
5804  }
5805  }
5806  };
5807 
5836  template<class SparseMatrixType>
5837  class Writer {
5838  public:
5840  typedef SparseMatrixType sparse_matrix_type;
5841  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5842 
5844  typedef typename SparseMatrixType::scalar_type scalar_type;
5846  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5852  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5854  typedef typename SparseMatrixType::node_type node_type;
5855 
5857  typedef MultiVector<scalar_type,
5860  node_type> multivector_type;
5865 
5868 
5900  static void
5901  writeSparseFile (const std::string& filename,
5902  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5903  const std::string& matrixName,
5904  const std::string& matrixDescription,
5905  const bool debug=false)
5906  {
5907  TEUCHOS_TEST_FOR_EXCEPTION(
5908  pMatrix.is_null (), std::invalid_argument,
5909  "The input matrix is null.");
5910  Teuchos::RCP<const Teuchos::Comm<int> > comm = pMatrix->getComm ();
5911  TEUCHOS_TEST_FOR_EXCEPTION(
5912  comm.is_null (), std::invalid_argument,
5913  "The input matrix's communicator (Teuchos::Comm object) is null.");
5914  const int myRank = comm->getRank ();
5915  std::ofstream out;
5916 
5917 
5918  // Only open the file on Rank 0.
5919  if (myRank == 0) {
5920  out.open (filename.c_str ());
5921  }
5922  writeSparse (out, pMatrix, matrixName, matrixDescription, debug);
5923  // We can rely on the destructor of the output stream to close
5924  // the file on scope exit, even if writeSparse() throws an
5925  // exception.
5926  }
5927 
5948  static void
5949  writeSparseFile (const std::string& filename,
5950  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5951  const bool debug=false)
5952  {
5953  writeSparseFile (filename, pMatrix, "", "", debug);
5954  }
5955 
5986  static void
5987  writeSparse (std::ostream& out,
5988  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5989  const std::string& matrixName,
5990  const std::string& matrixDescription,
5991  const bool debug=false)
5992  {
5993  using Teuchos::ArrayView;
5994  using Teuchos::Comm;
5995  using Teuchos::FancyOStream;
5996  using Teuchos::getFancyOStream;
5997  using Teuchos::null;
5998  using Teuchos::RCP;
5999  using Teuchos::rcpFromRef;
6000  using std::cerr;
6001  using std::endl;
6002  typedef scalar_type ST;
6003  typedef local_ordinal_type LO;
6004  typedef global_ordinal_type GO;
6005  typedef typename Teuchos::ScalarTraits<ST> STS;
6006  typedef typename ArrayView<const LO>::const_iterator lo_iter;
6007  typedef typename ArrayView<const GO>::const_iterator go_iter;
6008  typedef typename ArrayView<const ST>::const_iterator st_iter;
6009 
6010  TEUCHOS_TEST_FOR_EXCEPTION(
6011  pMatrix.is_null (), std::invalid_argument,
6012  "The input matrix is null.");
6013 
6014  // Make the output stream write floating-point numbers in
6015  // scientific notation. It will politely put the output
6016  // stream back to its state on input, when this scope
6017  // terminates.
6018  Teuchos::SetScientific<ST> sci (out);
6019 
6020  // Get the matrix's communicator.
6021  RCP<const Comm<int> > comm = pMatrix->getComm ();
6022  TEUCHOS_TEST_FOR_EXCEPTION(
6023  comm.is_null (), std::invalid_argument,
6024  "The input matrix's communicator (Teuchos::Comm object) is null.");
6025  const int myRank = comm->getRank ();
6026 
6027  // Optionally, make a stream for debugging output.
6028  RCP<FancyOStream> err =
6029  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6030  if (debug) {
6031  std::ostringstream os;
6032  os << myRank << ": writeSparse" << endl;
6033  *err << os.str ();
6034  comm->barrier ();
6035  os << "-- " << myRank << ": past barrier" << endl;
6036  *err << os.str ();
6037  }
6038 
6039  // Whether to print debugging output to stderr.
6040  const bool debugPrint = debug && myRank == 0;
6041 
6042  RCP<const map_type> rowMap = pMatrix->getRowMap ();
6043  RCP<const map_type> colMap = pMatrix->getColMap ();
6044  RCP<const map_type> domainMap = pMatrix->getDomainMap ();
6045  RCP<const map_type> rangeMap = pMatrix->getRangeMap ();
6046 
6047  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6048  const global_size_t numCols = domainMap->getGlobalNumElements ();
6049 
6050  if (debug && myRank == 0) {
6051  std::ostringstream os;
6052  os << "-- Input sparse matrix is:"
6053  << "---- " << numRows << " x " << numCols << endl
6054  << "---- "
6055  << (pMatrix->isGloballyIndexed() ? "Globally" : "Locally")
6056  << " indexed." << endl
6057  << "---- Its row map has " << rowMap->getGlobalNumElements ()
6058  << " elements." << endl
6059  << "---- Its col map has " << colMap->getGlobalNumElements ()
6060  << " elements." << endl;
6061  *err << os.str ();
6062  }
6063  // Make the "gather" row map, where Proc 0 owns all rows and
6064  // the other procs own no rows.
6065  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6066  if (debug) {
6067  std::ostringstream os;
6068  os << "-- " << myRank << ": making gatherRowMap" << endl;
6069  *err << os.str ();
6070  }
6071  RCP<const map_type> gatherRowMap =
6072  Details::computeGatherMap (rowMap, err, debug);
6073 
6074  // Since the matrix may in general be non-square, we need to
6075  // make a column map as well. In this case, the column map
6076  // contains all the columns of the original matrix, because we
6077  // are gathering the whole matrix onto Proc 0. We call
6078  // computeGatherMap to preserve the original order of column
6079  // indices over all the processes.
6080  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6081  RCP<const map_type> gatherColMap =
6082  Details::computeGatherMap (colMap, err, debug);
6083 
6084  // Current map is the source map, gather map is the target map.
6085  typedef Import<LO, GO, node_type> import_type;
6086  import_type importer (rowMap, gatherRowMap);
6087 
6088  // Create a new CrsMatrix to hold the result of the import.
6089  // The constructor needs a column map as well as a row map,
6090  // for the case that the matrix is not square.
6091  RCP<sparse_matrix_type> newMatrix =
6092  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
6093  static_cast<size_t> (0)));
6094  // Import the sparse matrix onto Proc 0.
6095  newMatrix->doImport (*pMatrix, importer, INSERT);
6096 
6097  // fillComplete() needs the domain and range maps for the case
6098  // that the matrix is not square.
6099  {
6100  RCP<const map_type> gatherDomainMap =
6101  rcp (new map_type (numCols, localNumCols,
6102  domainMap->getIndexBase (),
6103  comm));
6104  RCP<const map_type> gatherRangeMap =
6105  rcp (new map_type (numRows, localNumRows,
6106  rangeMap->getIndexBase (),
6107  comm));
6108  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
6109  }
6110 
6111  if (debugPrint) {
6112  cerr << "-- Output sparse matrix is:"
6113  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
6114  << " x "
6115  << newMatrix->getDomainMap ()->getGlobalNumElements ()
6116  << " with "
6117  << newMatrix->getGlobalNumEntries () << " entries;" << endl
6118  << "---- "
6119  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
6120  << " indexed." << endl
6121  << "---- Its row map has "
6122  << newMatrix->getRowMap ()->getGlobalNumElements ()
6123  << " elements, with index base "
6124  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
6125  << "---- Its col map has "
6126  << newMatrix->getColMap ()->getGlobalNumElements ()
6127  << " elements, with index base "
6128  << newMatrix->getColMap ()->getIndexBase () << "." << endl
6129  << "---- Element count of output matrix's column Map may differ "
6130  << "from that of the input matrix's column Map, if some columns "
6131  << "of the matrix contain no entries." << endl;
6132  }
6133 
6134  //
6135  // Print the metadata and the matrix entries on Rank 0.
6136  //
6137  if (myRank == 0) {
6138  // Print the Matrix Market banner line. CrsMatrix stores
6139  // data nonsymmetrically ("general"). This implies that
6140  // readSparse() on a symmetrically stored input file,
6141  // followed by writeSparse() on the resulting sparse matrix,
6142  // will result in an output file with a different banner
6143  // line than the original input file.
6144  out << "%%MatrixMarket matrix coordinate "
6145  << (STS::isComplex ? "complex" : "real")
6146  << " general" << endl;
6147 
6148  // Print comments (the matrix name and / or description).
6149  if (matrixName != "") {
6150  printAsComment (out, matrixName);
6151  }
6152  if (matrixDescription != "") {
6153  printAsComment (out, matrixDescription);
6154  }
6155 
6156  // Print the Matrix Market header (# rows, # columns, #
6157  // nonzeros). Use the range resp. domain map for the number
6158  // of rows resp. columns, since Tpetra::CrsMatrix uses the
6159  // column map for the number of columns. That only
6160  // corresponds to the "linear-algebraic" number of columns
6161  // when the column map is uniquely owned (a.k.a. one-to-one),
6162  // which only happens if the matrix is (block) diagonal.
6163  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
6164  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
6165  << newMatrix->getGlobalNumEntries () << endl;
6166 
6167  // The Matrix Market format expects one-based row and column
6168  // indices. We'll convert the indices on output from
6169  // whatever index base they use to one-based indices.
6170  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6171  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
6172  //
6173  // Print the entries of the matrix.
6174  //
6175  // newMatrix can never be globally indexed, since we called
6176  // fillComplete() on it. We include code for both cases
6177  // (globally or locally indexed) just in case that ever
6178  // changes.
6179  if (newMatrix->isGloballyIndexed()) {
6180  // We know that the "gather" row Map is contiguous, so we
6181  // don't need to get the list of GIDs.
6182  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6183  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6184  for (GO globalRowIndex = minAllGlobalIndex;
6185  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6186  ++globalRowIndex) {
6187  ArrayView<const GO> ind;
6188  ArrayView<const ST> val;
6189  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6190  go_iter indIter = ind.begin ();
6191  st_iter valIter = val.begin ();
6192  for (; indIter != ind.end() && valIter != val.end();
6193  ++indIter, ++valIter) {
6194  const GO globalColIndex = *indIter;
6195  // Convert row and column indices to 1-based.
6196  // This works because the global index type is signed.
6197  out << (globalRowIndex + 1 - rowIndexBase) << " "
6198  << (globalColIndex + 1 - colIndexBase) << " ";
6199  if (STS::isComplex) {
6200  out << STS::real (*valIter) << " " << STS::imag (*valIter);
6201  } else {
6202  out << *valIter;
6203  }
6204  out << endl;
6205  } // For each entry in the current row
6206  } // For each row of the "gather" matrix
6207  } else { // newMatrix is locally indexed
6208  typedef Teuchos::OrdinalTraits<GO> OTG;
6209  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6210  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6211  ++localRowIndex) {
6212  // Convert from local to global row index.
6213  const GO globalRowIndex =
6214  gatherRowMap->getGlobalElement (localRowIndex);
6215  TEUCHOS_TEST_FOR_EXCEPTION(
6216  globalRowIndex == OTG::invalid(), std::logic_error,
6217  "Failed to convert the supposed local row index "
6218  << localRowIndex << " into a global row index. "
6219  "Please report this bug to the Tpetra developers.");
6220  ArrayView<const LO> ind;
6221  ArrayView<const ST> val;
6222  newMatrix->getLocalRowView (localRowIndex, ind, val);
6223  lo_iter indIter = ind.begin ();
6224  st_iter valIter = val.begin ();
6225  for (; indIter != ind.end() && valIter != val.end();
6226  ++indIter, ++valIter) {
6227  // Convert the column index from local to global.
6228  const GO globalColIndex =
6229  newMatrix->getColMap()->getGlobalElement (*indIter);
6230  TEUCHOS_TEST_FOR_EXCEPTION(
6231  globalColIndex == OTG::invalid(), std::logic_error,
6232  "On local row " << localRowIndex << " of the sparse matrix: "
6233  "Failed to convert the supposed local column index "
6234  << *indIter << " into a global column index. Please report "
6235  "this bug to the Tpetra developers.");
6236  // Convert row and column indices to 1-based.
6237  // This works because the global index type is signed.
6238  out << (globalRowIndex + 1 - rowIndexBase) << " "
6239  << (globalColIndex + 1 - colIndexBase) << " ";
6240  if (STS::isComplex) {
6241  out << STS::real (*valIter) << " " << STS::imag (*valIter);
6242  } else {
6243  out << *valIter;
6244  }
6245  out << endl;
6246  } // For each entry in the current row
6247  } // For each row of the "gather" matrix
6248  } // Whether the "gather" matrix is locally or globally indexed
6249  } // If my process' rank is 0
6250  }
6251 
6252 
6283  static void
6284  writeSparseGraph (std::ostream& out,
6285  const crs_graph_type& graph,
6286  const std::string& graphName,
6287  const std::string& graphDescription,
6288  const bool debug=false)
6289  {
6290  using Teuchos::ArrayView;
6291  using Teuchos::Comm;
6292  using Teuchos::FancyOStream;
6293  using Teuchos::getFancyOStream;
6294  using Teuchos::null;
6295  using Teuchos::RCP;
6296  using Teuchos::rcpFromRef;
6297  using std::cerr;
6298  using std::endl;
6299  typedef local_ordinal_type LO;
6300  typedef global_ordinal_type GO;
6301 
6302  // Get the graph's communicator. Processes on which the
6303  // graph's Map or communicator is null don't participate in
6304  // this operation. This function shouldn't even be called on
6305  // those processes.
6306  auto rowMap = graph.getRowMap ();
6307  if (rowMap.is_null ()) {
6308  return;
6309  }
6310  auto comm = rowMap->getComm ();
6311  if (comm.is_null ()) {
6312  return;
6313  }
6314  const int myRank = comm->getRank ();
6315 
6316  // Optionally, make a stream for debugging output.
6317  RCP<FancyOStream> err =
6318  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6319  if (debug) {
6320  std::ostringstream os;
6321  os << myRank << ": writeSparseGraph" << endl;
6322  *err << os.str ();
6323  comm->barrier ();
6324  os << "-- " << myRank << ": past barrier" << endl;
6325  *err << os.str ();
6326  }
6327 
6328  // Whether to print debugging output to stderr.
6329  const bool debugPrint = debug && myRank == 0;
6330 
6331  // We've already gotten the rowMap above.
6332  auto colMap = graph.getColMap ();
6333  auto domainMap = graph.getDomainMap ();
6334  auto rangeMap = graph.getRangeMap ();
6335 
6336  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6337  const global_size_t numCols = domainMap->getGlobalNumElements ();
6338 
6339  if (debug && myRank == 0) {
6340  std::ostringstream os;
6341  os << "-- Input sparse graph is:"
6342  << "---- " << numRows << " x " << numCols << " with "
6343  << graph.getGlobalNumEntries () << " entries;" << endl
6344  << "---- "
6345  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6346  << " indexed." << endl
6347  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6348  << " elements." << endl
6349  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6350  << " elements." << endl;
6351  *err << os.str ();
6352  }
6353  // Make the "gather" row map, where Proc 0 owns all rows and
6354  // the other procs own no rows.
6355  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6356  if (debug) {
6357  std::ostringstream os;
6358  os << "-- " << myRank << ": making gatherRowMap" << endl;
6359  *err << os.str ();
6360  }
6361  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6362 
6363  // Since the graph may in general be non-square, we need to
6364  // make a column map as well. In this case, the column map
6365  // contains all the columns of the original graph, because we
6366  // are gathering the whole graph onto Proc 0. We call
6367  // computeGatherMap to preserve the original order of column
6368  // indices over all the processes.
6369  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6370  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6371 
6372  // Current map is the source map, gather map is the target map.
6373  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6374 
6375  // Create a new CrsGraph to hold the result of the import.
6376  // The constructor needs a column map as well as a row map,
6377  // for the case that the graph is not square.
6378  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6379  static_cast<size_t> (0));
6380  // Import the sparse graph onto Proc 0.
6381  newGraph.doImport (graph, importer, INSERT);
6382 
6383  // fillComplete() needs the domain and range maps for the case
6384  // that the graph is not square.
6385  {
6386  RCP<const map_type> gatherDomainMap =
6387  rcp (new map_type (numCols, localNumCols,
6388  domainMap->getIndexBase (),
6389  comm));
6390  RCP<const map_type> gatherRangeMap =
6391  rcp (new map_type (numRows, localNumRows,
6392  rangeMap->getIndexBase (),
6393  comm));
6394  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6395  }
6396 
6397  if (debugPrint) {
6398  cerr << "-- Output sparse graph is:"
6399  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6400  << " x "
6401  << newGraph.getDomainMap ()->getGlobalNumElements ()
6402  << " with "
6403  << newGraph.getGlobalNumEntries () << " entries;" << endl
6404  << "---- "
6405  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6406  << " indexed." << endl
6407  << "---- Its row map has "
6408  << newGraph.getRowMap ()->getGlobalNumElements ()
6409  << " elements, with index base "
6410  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6411  << "---- Its col map has "
6412  << newGraph.getColMap ()->getGlobalNumElements ()
6413  << " elements, with index base "
6414  << newGraph.getColMap ()->getIndexBase () << "." << endl
6415  << "---- Element count of output graph's column Map may differ "
6416  << "from that of the input matrix's column Map, if some columns "
6417  << "of the matrix contain no entries." << endl;
6418  }
6419 
6420  //
6421  // Print the metadata and the graph entries on Process 0 of
6422  // the graph's communicator.
6423  //
6424  if (myRank == 0) {
6425  // Print the Matrix Market banner line. CrsGraph stores
6426  // data nonsymmetrically ("general"). This implies that
6427  // readSparseGraph() on a symmetrically stored input file,
6428  // followed by writeSparseGraph() on the resulting sparse
6429  // graph, will result in an output file with a different
6430  // banner line than the original input file.
6431  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6432 
6433  // Print comments (the graph name and / or description).
6434  if (graphName != "") {
6435  printAsComment (out, graphName);
6436  }
6437  if (graphDescription != "") {
6438  printAsComment (out, graphDescription);
6439  }
6440 
6441  // Print the Matrix Market header (# rows, # columns, #
6442  // stored entries). Use the range resp. domain map for the
6443  // number of rows resp. columns, since Tpetra::CrsGraph uses
6444  // the column map for the number of columns. That only
6445  // corresponds to the "linear-algebraic" number of columns
6446  // when the column map is uniquely owned
6447  // (a.k.a. one-to-one), which only happens if the graph is
6448  // block diagonal (one block per process).
6449  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6450  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6451  << newGraph.getGlobalNumEntries () << endl;
6452 
6453  // The Matrix Market format expects one-based row and column
6454  // indices. We'll convert the indices on output from
6455  // whatever index base they use to one-based indices.
6456  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6457  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6458  //
6459  // Print the entries of the graph.
6460  //
6461  // newGraph can never be globally indexed, since we called
6462  // fillComplete() on it. We include code for both cases
6463  // (globally or locally indexed) just in case that ever
6464  // changes.
6465  if (newGraph.isGloballyIndexed ()) {
6466  // We know that the "gather" row Map is contiguous, so we
6467  // don't need to get the list of GIDs.
6468  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6469  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6470  for (GO globalRowIndex = minAllGlobalIndex;
6471  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6472  ++globalRowIndex) {
6473  ArrayView<const GO> ind;
6474  newGraph.getGlobalRowView (globalRowIndex, ind);
6475  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6476  const GO globalColIndex = *indIter;
6477  // Convert row and column indices to 1-based.
6478  // This works because the global index type is signed.
6479  out << (globalRowIndex + 1 - rowIndexBase) << " "
6480  << (globalColIndex + 1 - colIndexBase) << " ";
6481  out << endl;
6482  } // For each entry in the current row
6483  } // For each row of the "gather" graph
6484  }
6485  else { // newGraph is locally indexed
6486  typedef Teuchos::OrdinalTraits<GO> OTG;
6487  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6488  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6489  ++localRowIndex) {
6490  // Convert from local to global row index.
6491  const GO globalRowIndex =
6492  gatherRowMap->getGlobalElement (localRowIndex);
6493  TEUCHOS_TEST_FOR_EXCEPTION
6494  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6495  "to convert the supposed local row index " << localRowIndex <<
6496  " into a global row index. Please report this bug to the "
6497  "Tpetra developers.");
6498  ArrayView<const LO> ind;
6499  newGraph.getLocalRowView (localRowIndex, ind);
6500  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6501  // Convert the column index from local to global.
6502  const GO globalColIndex =
6503  newGraph.getColMap ()->getGlobalElement (*indIter);
6504  TEUCHOS_TEST_FOR_EXCEPTION(
6505  globalColIndex == OTG::invalid(), std::logic_error,
6506  "On local row " << localRowIndex << " of the sparse graph: "
6507  "Failed to convert the supposed local column index "
6508  << *indIter << " into a global column index. Please report "
6509  "this bug to the Tpetra developers.");
6510  // Convert row and column indices to 1-based.
6511  // This works because the global index type is signed.
6512  out << (globalRowIndex + 1 - rowIndexBase) << " "
6513  << (globalColIndex + 1 - colIndexBase) << " ";
6514  out << endl;
6515  } // For each entry in the current row
6516  } // For each row of the "gather" graph
6517  } // Whether the "gather" graph is locally or globally indexed
6518  } // If my process' rank is 0
6519  }
6520 
6526  static void
6527  writeSparseGraph (std::ostream& out,
6528  const crs_graph_type& graph,
6529  const bool debug=false)
6530  {
6531  writeSparseGraph (out, graph, "", "", debug);
6532  }
6533 
6568  static void
6569  writeSparseGraphFile (const std::string& filename,
6570  const crs_graph_type& graph,
6571  const std::string& graphName,
6572  const std::string& graphDescription,
6573  const bool debug=false)
6574  {
6575  auto comm = graph.getComm ();
6576  if (comm.is_null ()) {
6577  // Processes on which the communicator is null shouldn't
6578  // even call this function. The convention is that
6579  // processes on which the object's communicator is null do
6580  // not participate in collective operations involving the
6581  // object.
6582  return;
6583  }
6584  const int myRank = comm->getRank ();
6585  std::ofstream out;
6586 
6587  // Only open the file on Process 0.
6588  if (myRank == 0) {
6589  out.open (filename.c_str ());
6590  }
6591  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6592  // We can rely on the destructor of the output stream to close
6593  // the file on scope exit, even if writeSparseGraph() throws
6594  // an exception.
6595  }
6596 
6601  static void
6602  writeSparseGraphFile (const std::string& filename,
6603  const crs_graph_type& graph,
6604  const bool debug=false)
6605  {
6606  writeSparseGraphFile (filename, graph, "", "", debug);
6607  }
6608 
6617  static void
6618  writeSparseGraphFile (const std::string& filename,
6619  const Teuchos::RCP<const crs_graph_type>& pGraph,
6620  const std::string& graphName,
6621  const std::string& graphDescription,
6622  const bool debug=false)
6623  {
6624  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6625  }
6626 
6636  static void
6637  writeSparseGraphFile (const std::string& filename,
6638  const Teuchos::RCP<const crs_graph_type>& pGraph,
6639  const bool debug=false)
6640  {
6641  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6642  }
6643 
6666  static void
6667  writeSparse (std::ostream& out,
6668  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6669  const bool debug=false)
6670  {
6671  writeSparse (out, pMatrix, "", "", debug);
6672  }
6673 
6702  static void
6703  writeDenseFile (const std::string& filename,
6704  const multivector_type& X,
6705  const std::string& matrixName,
6706  const std::string& matrixDescription,
6707  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6708  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6709  {
6710  const int myRank = X.getMap ().is_null () ? 0 :
6711  (X.getMap ()->getComm ().is_null () ? 0 :
6712  X.getMap ()->getComm ()->getRank ());
6713  std::ofstream out;
6714 
6715  if (myRank == 0) { // Only open the file on Process 0.
6716  out.open (filename.c_str());
6717  }
6718 
6719  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6720  // We can rely on the destructor of the output stream to close
6721  // the file on scope exit, even if writeDense() throws an
6722  // exception.
6723  }
6724 
6730  static void
6731  writeDenseFile (const std::string& filename,
6732  const Teuchos::RCP<const multivector_type>& X,
6733  const std::string& matrixName,
6734  const std::string& matrixDescription,
6735  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6736  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6737  {
6738  TEUCHOS_TEST_FOR_EXCEPTION(
6739  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6740  "writeDenseFile: The input MultiVector X is null.");
6741  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6742  }
6743 
6749  static void
6750  writeDenseFile (const std::string& filename,
6751  const multivector_type& X,
6752  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6753  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6754  {
6755  writeDenseFile (filename, X, "", "", err, dbg);
6756  }
6757 
6763  static void
6764  writeDenseFile (const std::string& filename,
6765  const Teuchos::RCP<const multivector_type>& X,
6766  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6767  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6768  {
6769  TEUCHOS_TEST_FOR_EXCEPTION(
6770  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6771  "writeDenseFile: The input MultiVector X is null.");
6772  writeDenseFile (filename, *X, err, dbg);
6773  }
6774 
6775 
6806  static void
6807  writeDense (std::ostream& out,
6808  const multivector_type& X,
6809  const std::string& matrixName,
6810  const std::string& matrixDescription,
6811  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6812  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6813  {
6814  using Teuchos::Comm;
6815  using Teuchos::outArg;
6816  using Teuchos::REDUCE_MAX;
6817  using Teuchos::reduceAll;
6818  using Teuchos::RCP;
6819  using std::endl;
6820 
6821  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6822  Teuchos::null : X.getMap ()->getComm ();
6823  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6824 
6825  // If the caller provides a nonnull debug output stream, we
6826  // print debugging output to it. This is a local thing; we
6827  // don't have to check across processes.
6828  const bool debug = ! dbg.is_null ();
6829  if (debug) {
6830  dbg->pushTab ();
6831  std::ostringstream os;
6832  os << myRank << ": writeDense" << endl;
6833  *dbg << os.str ();
6834  dbg->pushTab ();
6835  }
6836  // Print the Matrix Market header.
6837  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6838 
6839  // Print each column one at a time. This is a (perhaps)
6840  // temporary fix for Bug 6288.
6841  const size_t numVecs = X.getNumVectors ();
6842  for (size_t j = 0; j < numVecs; ++j) {
6843  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6844  }
6845 
6846  if (debug) {
6847  dbg->popTab ();
6848  std::ostringstream os;
6849  os << myRank << ": writeDense: Done" << endl;
6850  *dbg << os.str ();
6851  dbg->popTab ();
6852  }
6853  }
6854 
6855  private:
6856 
6882  static void
6883  writeDenseHeader (std::ostream& out,
6884  const multivector_type& X,
6885  const std::string& matrixName,
6886  const std::string& matrixDescription,
6887  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6888  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6889  {
6890  using Teuchos::Comm;
6891  using Teuchos::outArg;
6892  using Teuchos::RCP;
6893  using Teuchos::REDUCE_MAX;
6894  using Teuchos::reduceAll;
6895  using std::endl;
6896  typedef typename multivector_type::scalar_type scalar_type;
6897  typedef Teuchos::ScalarTraits<scalar_type> STS;
6898  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
6899 
6900  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6901  Teuchos::null : X.getMap ()->getComm ();
6902  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6903  int lclErr = 0; // whether this MPI process has seen an error
6904  int gblErr = 0; // whether we know if some MPI process has seen an error
6905 
6906  // If the caller provides a nonnull debug output stream, we
6907  // print debugging output to it. This is a local thing; we
6908  // don't have to check across processes.
6909  const bool debug = ! dbg.is_null ();
6910 
6911  if (debug) {
6912  dbg->pushTab ();
6913  std::ostringstream os;
6914  os << myRank << ": writeDenseHeader" << endl;
6915  *dbg << os.str ();
6916  dbg->pushTab ();
6917  }
6918 
6919  //
6920  // Process 0: Write the MatrixMarket header.
6921  //
6922  if (myRank == 0) {
6923  try {
6924  // Print the Matrix Market header. MultiVector stores data
6925  // nonsymmetrically, hence "general" in the banner line.
6926  // Print first to a temporary string output stream, and then
6927  // write it to the main output stream, so that at least the
6928  // header output has transactional semantics. We can't
6929  // guarantee transactional semantics for the whole output,
6930  // since that would not be memory scalable. (This could be
6931  // done in the file system by using a temporary file; we
6932  // don't do this, but users could.)
6933  std::ostringstream hdr;
6934  {
6935  std::string dataType;
6936  if (STS::isComplex) {
6937  dataType = "complex";
6938  } else if (STS::isOrdinal) {
6939  dataType = "integer";
6940  } else {
6941  dataType = "real";
6942  }
6943  hdr << "%%MatrixMarket matrix array " << dataType << " general"
6944  << endl;
6945  }
6946 
6947  // Print comments (the matrix name and / or description).
6948  if (matrixName != "") {
6949  printAsComment (hdr, matrixName);
6950  }
6951  if (matrixDescription != "") {
6952  printAsComment (hdr, matrixDescription);
6953  }
6954  // Print the Matrix Market dimensions header for dense matrices.
6955  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
6956 
6957  // Write the MatrixMarket header to the output stream.
6958  out << hdr.str ();
6959  } catch (std::exception& e) {
6960  if (! err.is_null ()) {
6961  *err << prefix << "While writing the Matrix Market header, "
6962  "Process 0 threw an exception: " << e.what () << endl;
6963  }
6964  lclErr = 1;
6965  }
6966  } // if I am Process 0
6967 
6968  // Establish global agreement on the error state. It wouldn't
6969  // be good for other processes to keep going, if Process 0
6970  // finds out that it can't write to the given output stream.
6971  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
6972  TEUCHOS_TEST_FOR_EXCEPTION(
6973  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
6974  "which prevented this method from completing.");
6975 
6976  if (debug) {
6977  dbg->popTab ();
6978  *dbg << myRank << ": writeDenseHeader: Done" << endl;
6979  dbg->popTab ();
6980  }
6981  }
6982 
7000  static void
7001  writeDenseColumn (std::ostream& out,
7002  const multivector_type& X,
7003  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7004  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7005  {
7006  using Teuchos::arcp;
7007  using Teuchos::Array;
7008  using Teuchos::ArrayRCP;
7009  using Teuchos::ArrayView;
7010  using Teuchos::Comm;
7011  using Teuchos::CommRequest;
7012  using Teuchos::ireceive;
7013  using Teuchos::isend;
7014  using Teuchos::outArg;
7015  using Teuchos::REDUCE_MAX;
7016  using Teuchos::reduceAll;
7017  using Teuchos::RCP;
7018  using Teuchos::TypeNameTraits;
7019  using Teuchos::wait;
7020  using std::endl;
7021  typedef typename multivector_type::scalar_type scalar_type;
7022  typedef Teuchos::ScalarTraits<scalar_type> STS;
7023 
7024  const Comm<int>& comm = * (X.getMap ()->getComm ());
7025  const int myRank = comm.getRank ();
7026  const int numProcs = comm.getSize ();
7027  int lclErr = 0; // whether this MPI process has seen an error
7028  int gblErr = 0; // whether we know if some MPI process has seen an error
7029 
7030  // If the caller provides a nonnull debug output stream, we
7031  // print debugging output to it. This is a local thing; we
7032  // don't have to check across processes.
7033  const bool debug = ! dbg.is_null ();
7034 
7035  if (debug) {
7036  dbg->pushTab ();
7037  std::ostringstream os;
7038  os << myRank << ": writeDenseColumn" << endl;
7039  *dbg << os.str ();
7040  dbg->pushTab ();
7041  }
7042 
7043  // Make the output stream write floating-point numbers in
7044  // scientific notation. It will politely put the output
7045  // stream back to its state on input, when this scope
7046  // terminates.
7047  Teuchos::SetScientific<scalar_type> sci (out);
7048 
7049  const size_t myNumRows = X.getLocalLength ();
7050  const size_t numCols = X.getNumVectors ();
7051  // Use a different tag for the "size" messages than for the
7052  // "data" messages, in order to help us debug any mix-ups.
7053  const int sizeTag = 1337;
7054  const int dataTag = 1338;
7055 
7056  // Process 0 pipelines nonblocking receives with file output.
7057  //
7058  // Constraints:
7059  // - Process 0 can't post a receive for another process'
7060  // actual data, until it posts and waits on the receive
7061  // from that process with the amount of data to receive.
7062  // (We could just post receives with a max data size, but
7063  // I feel uncomfortable about that.)
7064  // - The C++ standard library doesn't allow nonblocking
7065  // output to an std::ostream. (Thus, we have to start a
7066  // receive or send before starting the write, and hope
7067  // that MPI completes it in the background.)
7068  //
7069  // Process 0: Post receive-size receives from Processes 1 and 2.
7070  // Process 1: Post send-size send to Process 0.
7071  // Process 2: Post send-size send to Process 0.
7072  //
7073  // All processes: Pack my entries.
7074  //
7075  // Process 1:
7076  // - Post send-data send to Process 0.
7077  // - Wait on my send-size send to Process 0.
7078  //
7079  // Process 0:
7080  // - Print MatrixMarket header.
7081  // - Print my entries.
7082  // - Wait on receive-size receive from Process 1.
7083  // - Post receive-data receive from Process 1.
7084  //
7085  // For each process p = 1, 2, ... numProcs-1:
7086  // If I am Process 0:
7087  // - Post receive-size receive from Process p + 2
7088  // - Wait on receive-size receive from Process p + 1
7089  // - Post receive-data receive from Process p + 1
7090  // - Wait on receive-data receive from Process p
7091  // - Write data from Process p.
7092  // Else if I am Process p:
7093  // - Wait on my send-data send.
7094  // Else if I am Process p+1:
7095  // - Post send-data send to Process 0.
7096  // - Wait on my send-size send.
7097  // Else if I am Process p+2:
7098  // - Post send-size send to Process 0.
7099  //
7100  // Pipelining has three goals here:
7101  // 1. Overlap communication (the receives) with file I/O
7102  // 2. Give Process 0 a chance to prepost some receives,
7103  // before sends show up, by packing local data before
7104  // posting sends
7105  // 3. Don't post _all_ receives or _all_ sends, because that
7106  // wouldn't be memory scalable. (Just because we can't
7107  // see how much memory MPI consumes, doesn't mean that it
7108  // doesn't consume any!)
7109 
7110  // These are used on every process. sendReqSize[0] holds the
7111  // number of rows on this process, and sendReqBuf holds this
7112  // process' data. Process 0 packs into sendReqBuf, but
7113  // doesn't send; it only uses that for printing. All other
7114  // processes send both of these to Process 0.
7115  RCP<CommRequest<int> > sendReqSize, sendReqData;
7116 
7117  // These are used only on Process 0, for received data. Keep
7118  // 3 of each, and treat the arrays as circular buffers. When
7119  // receiving from Process p, the corresponding array index
7120  // here is p % 3.
7121  Array<ArrayRCP<size_t> > recvSizeBufs (3);
7122  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
7123  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7124  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7125 
7126  // Buffer for nonblocking send of the "send size."
7127  ArrayRCP<size_t> sendDataSize (1);
7128  sendDataSize[0] = myNumRows;
7129 
7130  if (myRank == 0) {
7131  if (debug) {
7132  std::ostringstream os;
7133  os << myRank << ": Post receive-size receives from "
7134  "Procs 1 and 2: tag = " << sizeTag << endl;
7135  *dbg << os.str ();
7136  }
7137  // Process 0: Post receive-size receives from Processes 1 and 2.
7138  recvSizeBufs[0].resize (1);
7139  // Set these three to an invalid value as a flag. If we
7140  // don't get these messages, then the invalid value will
7141  // remain, so we can test for it.
7142  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7143  recvSizeBufs[1].resize (1);
7144  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7145  recvSizeBufs[2].resize (1);
7146  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7147  if (numProcs > 1) {
7148  recvSizeReqs[1] =
7149  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
7150  }
7151  if (numProcs > 2) {
7152  recvSizeReqs[2] =
7153  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
7154  }
7155  }
7156  else if (myRank == 1 || myRank == 2) {
7157  if (debug) {
7158  std::ostringstream os;
7159  os << myRank << ": Post send-size send: size = "
7160  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7161  *dbg << os.str ();
7162  }
7163  // Prime the pipeline by having Processes 1 and 2 start
7164  // their send-size sends. We don't want _all_ the processes
7165  // to start their send-size sends, because that wouldn't be
7166  // memory scalable.
7167  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7168  }
7169  else {
7170  if (debug) {
7171  std::ostringstream os;
7172  os << myRank << ": Not posting my send-size send yet" << endl;
7173  *dbg << os.str ();
7174  }
7175  }
7176 
7177  //
7178  // Pack my entries, in column-major order.
7179  //
7180  if (debug) {
7181  std::ostringstream os;
7182  os << myRank << ": Pack my entries" << endl;
7183  *dbg << os.str ();
7184  }
7185  ArrayRCP<scalar_type> sendDataBuf;
7186  try {
7187  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7188  X.get1dCopy (sendDataBuf (), myNumRows);
7189  }
7190  catch (std::exception& e) {
7191  lclErr = 1;
7192  if (! err.is_null ()) {
7193  std::ostringstream os;
7194  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7195  "entries threw an exception: " << e.what () << endl;
7196  *err << os.str ();
7197  }
7198  }
7199  if (debug) {
7200  std::ostringstream os;
7201  os << myRank << ": Done packing my entries" << endl;
7202  *dbg << os.str ();
7203  }
7204 
7205  //
7206  // Process 1: post send-data send to Process 0.
7207  //
7208  if (myRank == 1) {
7209  if (debug) {
7210  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7211  << endl;
7212  }
7213  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7214  }
7215 
7216  //
7217  // Process 0: Write my entries.
7218  //
7219  if (myRank == 0) {
7220  if (debug) {
7221  std::ostringstream os;
7222  os << myRank << ": Write my entries" << endl;
7223  *dbg << os.str ();
7224  }
7225 
7226  // Write Process 0's data to the output stream.
7227  // Matrix Market prints dense matrices in column-major order.
7228  const size_t printNumRows = myNumRows;
7229  ArrayView<const scalar_type> printData = sendDataBuf ();
7230  const size_t printStride = printNumRows;
7231  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7232  lclErr = 1;
7233  if (! err.is_null ()) {
7234  std::ostringstream os;
7235  os << "Process " << myRank << ": My MultiVector data's size "
7236  << printData.size () << " does not match my local dimensions "
7237  << printStride << " x " << numCols << "." << endl;
7238  *err << os.str ();
7239  }
7240  }
7241  else {
7242  // Matrix Market dense format wants one number per line.
7243  // It wants each complex number as two real numbers (real
7244  // resp. imaginary parts) with a space between.
7245  for (size_t col = 0; col < numCols; ++col) {
7246  for (size_t row = 0; row < printNumRows; ++row) {
7247  if (STS::isComplex) {
7248  out << STS::real (printData[row + col * printStride]) << " "
7249  << STS::imag (printData[row + col * printStride]) << endl;
7250  } else {
7251  out << printData[row + col * printStride] << endl;
7252  }
7253  }
7254  }
7255  }
7256  }
7257 
7258  if (myRank == 0) {
7259  // Wait on receive-size receive from Process 1.
7260  const int recvRank = 1;
7261  const int circBufInd = recvRank % 3;
7262  if (debug) {
7263  std::ostringstream os;
7264  os << myRank << ": Wait on receive-size receive from Process "
7265  << recvRank << endl;
7266  *dbg << os.str ();
7267  }
7268  if (numProcs > 1) {
7269  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7270 
7271  // We received the number of rows of data. (The data
7272  // come in two columns.)
7273  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7274  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7275  lclErr = 1;
7276  if (! err.is_null ()) {
7277  std::ostringstream os;
7278  os << myRank << ": Result of receive-size receive from Process "
7279  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7280  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7281  "This should never happen, and suggests that the receive never "
7282  "got posted. Please report this bug to the Tpetra developers."
7283  << endl;
7284  *err << os.str ();
7285  }
7286 
7287  // If we're going to continue after error, set the
7288  // number of rows to receive to a reasonable size. This
7289  // may cause MPI_ERR_TRUNCATE if the sending process is
7290  // sending more than 0 rows, but that's better than MPI
7291  // overflowing due to the huge positive value that is
7292  // Teuchos::OrdinalTraits<size_t>::invalid().
7293  recvNumRows = 0;
7294  }
7295 
7296  // Post receive-data receive from Process 1.
7297  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7298  if (debug) {
7299  std::ostringstream os;
7300  os << myRank << ": Post receive-data receive from Process "
7301  << recvRank << ": tag = " << dataTag << ", buffer size = "
7302  << recvDataBufs[circBufInd].size () << endl;
7303  *dbg << os.str ();
7304  }
7305  if (! recvSizeReqs[circBufInd].is_null ()) {
7306  lclErr = 1;
7307  if (! err.is_null ()) {
7308  std::ostringstream os;
7309  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7310  "null, before posting the receive-data receive from Process "
7311  << recvRank << ". This should never happen. Please report "
7312  "this bug to the Tpetra developers." << endl;
7313  *err << os.str ();
7314  }
7315  }
7316  recvDataReqs[circBufInd] =
7317  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7318  recvRank, dataTag, comm);
7319  } // numProcs > 1
7320  }
7321  else if (myRank == 1) {
7322  // Wait on my send-size send.
7323  if (debug) {
7324  std::ostringstream os;
7325  os << myRank << ": Wait on my send-size send" << endl;
7326  *dbg << os.str ();
7327  }
7328  wait<int> (comm, outArg (sendReqSize));
7329  }
7330 
7331  //
7332  // Pipeline loop
7333  //
7334  for (int p = 1; p < numProcs; ++p) {
7335  if (myRank == 0) {
7336  if (p + 2 < numProcs) {
7337  // Post receive-size receive from Process p + 2.
7338  const int recvRank = p + 2;
7339  const int circBufInd = recvRank % 3;
7340  if (debug) {
7341  std::ostringstream os;
7342  os << myRank << ": Post receive-size receive from Process "
7343  << recvRank << ": tag = " << sizeTag << endl;
7344  *dbg << os.str ();
7345  }
7346  if (! recvSizeReqs[circBufInd].is_null ()) {
7347  lclErr = 1;
7348  if (! err.is_null ()) {
7349  std::ostringstream os;
7350  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7351  << "null, for the receive-size receive from Process "
7352  << recvRank << "! This may mean that this process never "
7353  << "finished waiting for the receive from Process "
7354  << (recvRank - 3) << "." << endl;
7355  *err << os.str ();
7356  }
7357  }
7358  recvSizeReqs[circBufInd] =
7359  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7360  recvRank, sizeTag, comm);
7361  }
7362 
7363  if (p + 1 < numProcs) {
7364  const int recvRank = p + 1;
7365  const int circBufInd = recvRank % 3;
7366 
7367  // Wait on receive-size receive from Process p + 1.
7368  if (debug) {
7369  std::ostringstream os;
7370  os << myRank << ": Wait on receive-size receive from Process "
7371  << recvRank << endl;
7372  *dbg << os.str ();
7373  }
7374  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7375 
7376  // We received the number of rows of data. (The data
7377  // come in two columns.)
7378  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7379  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7380  lclErr = 1;
7381  if (! err.is_null ()) {
7382  std::ostringstream os;
7383  os << myRank << ": Result of receive-size receive from Process "
7384  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7385  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7386  "This should never happen, and suggests that the receive never "
7387  "got posted. Please report this bug to the Tpetra developers."
7388  << endl;
7389  *err << os.str ();
7390  }
7391  // If we're going to continue after error, set the
7392  // number of rows to receive to a reasonable size.
7393  // This may cause MPI_ERR_TRUNCATE if the sending
7394  // process sends more than 0 rows, but that's better
7395  // than MPI overflowing due to the huge positive value
7396  // Teuchos::OrdinalTraits<size_t>::invalid().
7397  recvNumRows = 0;
7398  }
7399 
7400  // Post receive-data receive from Process p + 1.
7401  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7402  if (debug) {
7403  std::ostringstream os;
7404  os << myRank << ": Post receive-data receive from Process "
7405  << recvRank << ": tag = " << dataTag << ", buffer size = "
7406  << recvDataBufs[circBufInd].size () << endl;
7407  *dbg << os.str ();
7408  }
7409  if (! recvDataReqs[circBufInd].is_null ()) {
7410  lclErr = 1;
7411  if (! err.is_null ()) {
7412  std::ostringstream os;
7413  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7414  << "null, for the receive-data receive from Process "
7415  << recvRank << "! This may mean that this process never "
7416  << "finished waiting for the receive from Process "
7417  << (recvRank - 3) << "." << endl;
7418  *err << os.str ();
7419  }
7420  }
7421  recvDataReqs[circBufInd] =
7422  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7423  recvRank, dataTag, comm);
7424  }
7425 
7426  // Wait on receive-data receive from Process p.
7427  const int recvRank = p;
7428  const int circBufInd = recvRank % 3;
7429  if (debug) {
7430  std::ostringstream os;
7431  os << myRank << ": Wait on receive-data receive from Process "
7432  << recvRank << endl;
7433  *dbg << os.str ();
7434  }
7435  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7436 
7437  // Write Process p's data. Number of rows lives in
7438  // recvSizeBufs[circBufInd], and the actual data live in
7439  // recvDataBufs[circBufInd]. Do this after posting receives,
7440  // in order to expose overlap of comm. with file I/O.
7441  if (debug) {
7442  std::ostringstream os;
7443  os << myRank << ": Write entries from Process " << recvRank
7444  << endl;
7445  *dbg << os.str () << endl;
7446  }
7447  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7448  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7449  lclErr = 1;
7450  if (! err.is_null ()) {
7451  std::ostringstream os;
7452  os << myRank << ": Result of receive-size receive from Process "
7453  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7454  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7455  << ". This should never happen, and suggests that its "
7456  "receive-size receive was never posted. "
7457  "Please report this bug to the Tpetra developers." << endl;
7458  *err << os.str ();
7459  }
7460  // If we're going to continue after error, set the
7461  // number of rows to print to a reasonable size.
7462  printNumRows = 0;
7463  }
7464  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7465  lclErr = 1;
7466  if (! err.is_null ()) {
7467  std::ostringstream os;
7468  os << myRank << ": Result of receive-size receive from Proc "
7469  << recvRank << " was " << printNumRows << " > 0, but "
7470  "recvDataBufs[" << circBufInd << "] is null. This should "
7471  "never happen. Please report this bug to the Tpetra "
7472  "developers." << endl;
7473  *err << os.str ();
7474  }
7475  // If we're going to continue after error, set the
7476  // number of rows to print to a reasonable size.
7477  printNumRows = 0;
7478  }
7479 
7480  // Write the received data to the output stream.
7481  // Matrix Market prints dense matrices in column-major order.
7482  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7483  const size_t printStride = printNumRows;
7484  // Matrix Market dense format wants one number per line.
7485  // It wants each complex number as two real numbers (real
7486  // resp. imaginary parts) with a space between.
7487  for (size_t col = 0; col < numCols; ++col) {
7488  for (size_t row = 0; row < printNumRows; ++row) {
7489  if (STS::isComplex) {
7490  out << STS::real (printData[row + col * printStride]) << " "
7491  << STS::imag (printData[row + col * printStride]) << endl;
7492  } else {
7493  out << printData[row + col * printStride] << endl;
7494  }
7495  }
7496  }
7497  }
7498  else if (myRank == p) { // Process p
7499  // Wait on my send-data send.
7500  if (debug) {
7501  std::ostringstream os;
7502  os << myRank << ": Wait on my send-data send" << endl;
7503  *dbg << os.str ();
7504  }
7505  wait<int> (comm, outArg (sendReqData));
7506  }
7507  else if (myRank == p + 1) { // Process p + 1
7508  // Post send-data send to Process 0.
7509  if (debug) {
7510  std::ostringstream os;
7511  os << myRank << ": Post send-data send: tag = " << dataTag
7512  << endl;
7513  *dbg << os.str ();
7514  }
7515  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7516  // Wait on my send-size send.
7517  if (debug) {
7518  std::ostringstream os;
7519  os << myRank << ": Wait on my send-size send" << endl;
7520  *dbg << os.str ();
7521  }
7522  wait<int> (comm, outArg (sendReqSize));
7523  }
7524  else if (myRank == p + 2) { // Process p + 2
7525  // Post send-size send to Process 0.
7526  if (debug) {
7527  std::ostringstream os;
7528  os << myRank << ": Post send-size send: size = "
7529  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7530  *dbg << os.str ();
7531  }
7532  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7533  }
7534  }
7535 
7536  // Establish global agreement on the error state.
7537  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7538  TEUCHOS_TEST_FOR_EXCEPTION(
7539  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7540  "experienced some kind of error and was unable to complete.");
7541 
7542  if (debug) {
7543  dbg->popTab ();
7544  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7545  dbg->popTab ();
7546  }
7547  }
7548 
7549  public:
7550 
7556  static void
7557  writeDense (std::ostream& out,
7558  const Teuchos::RCP<const multivector_type>& X,
7559  const std::string& matrixName,
7560  const std::string& matrixDescription,
7561  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7562  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7563  {
7564  TEUCHOS_TEST_FOR_EXCEPTION(
7565  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7566  "writeDense: The input MultiVector X is null.");
7567  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7568  }
7569 
7575  static void
7576  writeDense (std::ostream& out,
7577  const multivector_type& X,
7578  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7579  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7580  {
7581  writeDense (out, X, "", "", err, dbg);
7582  }
7583 
7589  static void
7590  writeDense (std::ostream& out,
7591  const Teuchos::RCP<const multivector_type>& X,
7592  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7593  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7594  {
7595  TEUCHOS_TEST_FOR_EXCEPTION(
7596  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7597  "writeDense: The input MultiVector X is null.");
7598  writeDense (out, *X, "", "", err, dbg);
7599  }
7600 
7620  static void
7621  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7622  {
7623  Teuchos::RCP<Teuchos::FancyOStream> err =
7624  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7625  writeMap (out, map, err, debug);
7626  }
7627 
7636  static void
7637  writeMap (std::ostream& out,
7638  const map_type& map,
7639  const Teuchos::RCP<Teuchos::FancyOStream>& err,
7640  const bool debug=false)
7641  {
7642  using Teuchos::Array;
7643  using Teuchos::ArrayRCP;
7644  using Teuchos::ArrayView;
7645  using Teuchos::Comm;
7646  using Teuchos::CommRequest;
7647  using Teuchos::ireceive;
7648  using Teuchos::isend;
7649  using Teuchos::RCP;
7650  using Teuchos::TypeNameTraits;
7651  using Teuchos::wait;
7652  using std::endl;
7653  typedef global_ordinal_type GO;
7654  typedef int pid_type;
7655 
7656  // Treat the Map as a 1-column "multivector." This differs
7657  // from the previous two-column format, in which column 0 held
7658  // the GIDs, and column 1 held the corresponding PIDs. It
7659  // differs because printing that format requires knowing the
7660  // entire first column -- that is, all the GIDs -- in advance.
7661  // Sending messages from each process one at a time saves
7662  // memory, but it means that Process 0 doesn't ever have all
7663  // the GIDs at once.
7664  //
7665  // We pack the entries as ptrdiff_t, since this should be the
7666  // biggest signed built-in integer type that can hold any GO
7667  // or pid_type (= int) quantity without overflow. Test this
7668  // assumption at run time.
7669  typedef ptrdiff_t int_type;
7670  TEUCHOS_TEST_FOR_EXCEPTION(
7671  sizeof (GO) > sizeof (int_type), std::logic_error,
7672  "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7673  << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7674  << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7675  TEUCHOS_TEST_FOR_EXCEPTION(
7676  sizeof (pid_type) > sizeof (int_type), std::logic_error,
7677  "The (MPI) process rank type pid_type=" <<
7678  TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7679  "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7680  " = " << sizeof (ptrdiff_t) << ".");
7681 
7682  const Comm<int>& comm = * (map.getComm ());
7683  const int myRank = comm.getRank ();
7684  const int numProcs = comm.getSize ();
7685 
7686  if (! err.is_null ()) {
7687  err->pushTab ();
7688  }
7689  if (debug) {
7690  std::ostringstream os;
7691  os << myRank << ": writeMap" << endl;
7692  *err << os.str ();
7693  }
7694  if (! err.is_null ()) {
7695  err->pushTab ();
7696  }
7697 
7698  const size_t myNumRows = map.getNodeNumElements ();
7699  // Use a different tag for the "size" messages than for the
7700  // "data" messages, in order to help us debug any mix-ups.
7701  const int sizeTag = 1337;
7702  const int dataTag = 1338;
7703 
7704  // Process 0 pipelines nonblocking receives with file output.
7705  //
7706  // Constraints:
7707  // - Process 0 can't post a receive for another process'
7708  // actual data, until it posts and waits on the receive
7709  // from that process with the amount of data to receive.
7710  // (We could just post receives with a max data size, but
7711  // I feel uncomfortable about that.)
7712  // - The C++ standard library doesn't allow nonblocking
7713  // output to an std::ostream.
7714  //
7715  // Process 0: Post receive-size receives from Processes 1 and 2.
7716  // Process 1: Post send-size send to Process 0.
7717  // Process 2: Post send-size send to Process 0.
7718  //
7719  // All processes: Pack my GIDs and PIDs.
7720  //
7721  // Process 1:
7722  // - Post send-data send to Process 0.
7723  // - Wait on my send-size send to Process 0.
7724  //
7725  // Process 0:
7726  // - Print MatrixMarket header.
7727  // - Print my GIDs and PIDs.
7728  // - Wait on receive-size receive from Process 1.
7729  // - Post receive-data receive from Process 1.
7730  //
7731  // For each process p = 1, 2, ... numProcs-1:
7732  // If I am Process 0:
7733  // - Post receive-size receive from Process p + 2
7734  // - Wait on receive-size receive from Process p + 1
7735  // - Post receive-data receive from Process p + 1
7736  // - Wait on receive-data receive from Process p
7737  // - Write data from Process p.
7738  // Else if I am Process p:
7739  // - Wait on my send-data send.
7740  // Else if I am Process p+1:
7741  // - Post send-data send to Process 0.
7742  // - Wait on my send-size send.
7743  // Else if I am Process p+2:
7744  // - Post send-size send to Process 0.
7745  //
7746  // Pipelining has three goals here:
7747  // 1. Overlap communication (the receives) with file I/O
7748  // 2. Give Process 0 a chance to prepost some receives,
7749  // before sends show up, by packing local data before
7750  // posting sends
7751  // 3. Don't post _all_ receives or _all_ sends, because that
7752  // wouldn't be memory scalable. (Just because we can't
7753  // see how much memory MPI consumes, doesn't mean that it
7754  // doesn't consume any!)
7755 
7756  // These are used on every process. sendReqSize[0] holds the
7757  // number of rows on this process, and sendReqBuf holds this
7758  // process' data. Process 0 packs into sendReqBuf, but
7759  // doesn't send; it only uses that for printing. All other
7760  // processes send both of these to Process 0.
7761  RCP<CommRequest<int> > sendReqSize, sendReqData;
7762 
7763  // These are used only on Process 0, for received data. Keep
7764  // 3 of each, and treat the arrays as circular buffers. When
7765  // receiving from Process p, the corresponding array index
7766  // here is p % 3.
7767  Array<ArrayRCP<int_type> > recvSizeBufs (3);
7768  Array<ArrayRCP<int_type> > recvDataBufs (3);
7769  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7770  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7771 
7772  // Buffer for nonblocking send of the "send size."
7773  ArrayRCP<int_type> sendDataSize (1);
7774  sendDataSize[0] = myNumRows;
7775 
7776  if (myRank == 0) {
7777  if (debug) {
7778  std::ostringstream os;
7779  os << myRank << ": Post receive-size receives from "
7780  "Procs 1 and 2: tag = " << sizeTag << endl;
7781  *err << os.str ();
7782  }
7783  // Process 0: Post receive-size receives from Processes 1 and 2.
7784  recvSizeBufs[0].resize (1);
7785  (recvSizeBufs[0])[0] = -1; // error flag
7786  recvSizeBufs[1].resize (1);
7787  (recvSizeBufs[1])[0] = -1; // error flag
7788  recvSizeBufs[2].resize (1);
7789  (recvSizeBufs[2])[0] = -1; // error flag
7790  if (numProcs > 1) {
7791  recvSizeReqs[1] =
7792  ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7793  }
7794  if (numProcs > 2) {
7795  recvSizeReqs[2] =
7796  ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7797  }
7798  }
7799  else if (myRank == 1 || myRank == 2) {
7800  if (debug) {
7801  std::ostringstream os;
7802  os << myRank << ": Post send-size send: size = "
7803  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7804  *err << os.str ();
7805  }
7806  // Prime the pipeline by having Processes 1 and 2 start
7807  // their send-size sends. We don't want _all_ the processes
7808  // to start their send-size sends, because that wouldn't be
7809  // memory scalable.
7810  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7811  }
7812  else {
7813  if (debug) {
7814  std::ostringstream os;
7815  os << myRank << ": Not posting my send-size send yet" << endl;
7816  *err << os.str ();
7817  }
7818  }
7819 
7820  //
7821  // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7822  // consecutively, for better locality.
7823  //
7824 
7825  if (debug) {
7826  std::ostringstream os;
7827  os << myRank << ": Pack my GIDs and PIDs" << endl;
7828  *err << os.str ();
7829  }
7830 
7831  ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7832 
7833  if (map.isContiguous ()) {
7834  const int_type myMinGblIdx =
7835  static_cast<int_type> (map.getMinGlobalIndex ());
7836  for (size_t k = 0; k < myNumRows; ++k) {
7837  const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7838  const int_type pid = static_cast<int_type> (myRank);
7839  sendDataBuf[2*k] = gid;
7840  sendDataBuf[2*k+1] = pid;
7841  }
7842  }
7843  else {
7844  ArrayView<const GO> myGblInds = map.getNodeElementList ();
7845  for (size_t k = 0; k < myNumRows; ++k) {
7846  const int_type gid = static_cast<int_type> (myGblInds[k]);
7847  const int_type pid = static_cast<int_type> (myRank);
7848  sendDataBuf[2*k] = gid;
7849  sendDataBuf[2*k+1] = pid;
7850  }
7851  }
7852 
7853  if (debug) {
7854  std::ostringstream os;
7855  os << myRank << ": Done packing my GIDs and PIDs" << endl;
7856  *err << os.str ();
7857  }
7858 
7859  if (myRank == 1) {
7860  // Process 1: post send-data send to Process 0.
7861  if (debug) {
7862  *err << myRank << ": Post send-data send: tag = " << dataTag
7863  << endl;
7864  }
7865  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7866  }
7867 
7868  if (myRank == 0) {
7869  if (debug) {
7870  *err << myRank << ": Write MatrixMarket header" << endl;
7871  }
7872 
7873  // Process 0: Write the MatrixMarket header.
7874  // Description section explains each column.
7875  std::ostringstream hdr;
7876 
7877  // Print the Matrix Market header. MultiVector stores data
7878  // nonsymmetrically, hence "general" in the banner line.
7879  hdr << "%%MatrixMarket matrix array integer general" << endl
7880  << "% Format: Version 2.0" << endl
7881  << "%" << endl
7882  << "% This file encodes a Tpetra::Map." << endl
7883  << "% It is stored as a dense vector, with twice as many " << endl
7884  << "% entries as the global number of GIDs (global indices)." << endl
7885  << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7886  << "% is the rank of the process owning that GID." << endl
7887  << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
7888  out << hdr.str ();
7889 
7890  if (debug) {
7891  std::ostringstream os;
7892  os << myRank << ": Write my GIDs and PIDs" << endl;
7893  *err << os.str ();
7894  }
7895 
7896  // Write Process 0's data to the output stream.
7897  // Matrix Market prints dense matrices in column-major order.
7898  const int_type printNumRows = myNumRows;
7899  ArrayView<const int_type> printData = sendDataBuf ();
7900  for (int_type k = 0; k < printNumRows; ++k) {
7901  const int_type gid = printData[2*k];
7902  const int_type pid = printData[2*k+1];
7903  out << gid << endl << pid << endl;
7904  }
7905  }
7906 
7907  if (myRank == 0) {
7908  // Wait on receive-size receive from Process 1.
7909  const int recvRank = 1;
7910  const int circBufInd = recvRank % 3;
7911  if (debug) {
7912  std::ostringstream os;
7913  os << myRank << ": Wait on receive-size receive from Process "
7914  << recvRank << endl;
7915  *err << os.str ();
7916  }
7917  if (numProcs > 1) {
7918  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7919 
7920  // We received the number of rows of data. (The data
7921  // come in two columns.)
7922  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7923  if (debug && recvNumRows == -1) {
7924  std::ostringstream os;
7925  os << myRank << ": Result of receive-size receive from Process "
7926  << recvRank << " is -1. This should never happen, and "
7927  "suggests that the receive never got posted. Please report "
7928  "this bug to the Tpetra developers." << endl;
7929  *err << os.str ();
7930  }
7931 
7932  // Post receive-data receive from Process 1.
7933  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7934  if (debug) {
7935  std::ostringstream os;
7936  os << myRank << ": Post receive-data receive from Process "
7937  << recvRank << ": tag = " << dataTag << ", buffer size = "
7938  << recvDataBufs[circBufInd].size () << endl;
7939  *err << os.str ();
7940  }
7941  if (! recvSizeReqs[circBufInd].is_null ()) {
7942  std::ostringstream os;
7943  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7944  "null, before posting the receive-data receive from Process "
7945  << recvRank << ". This should never happen. Please report "
7946  "this bug to the Tpetra developers." << endl;
7947  *err << os.str ();
7948  }
7949  recvDataReqs[circBufInd] =
7950  ireceive<int, int_type> (recvDataBufs[circBufInd],
7951  recvRank, dataTag, comm);
7952  } // numProcs > 1
7953  }
7954  else if (myRank == 1) {
7955  // Wait on my send-size send.
7956  if (debug) {
7957  std::ostringstream os;
7958  os << myRank << ": Wait on my send-size send" << endl;
7959  *err << os.str ();
7960  }
7961  wait<int> (comm, outArg (sendReqSize));
7962  }
7963 
7964  //
7965  // Pipeline loop
7966  //
7967  for (int p = 1; p < numProcs; ++p) {
7968  if (myRank == 0) {
7969  if (p + 2 < numProcs) {
7970  // Post receive-size receive from Process p + 2.
7971  const int recvRank = p + 2;
7972  const int circBufInd = recvRank % 3;
7973  if (debug) {
7974  std::ostringstream os;
7975  os << myRank << ": Post receive-size receive from Process "
7976  << recvRank << ": tag = " << sizeTag << endl;
7977  *err << os.str ();
7978  }
7979  if (! recvSizeReqs[circBufInd].is_null ()) {
7980  std::ostringstream os;
7981  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7982  << "null, for the receive-size receive from Process "
7983  << recvRank << "! This may mean that this process never "
7984  << "finished waiting for the receive from Process "
7985  << (recvRank - 3) << "." << endl;
7986  *err << os.str ();
7987  }
7988  recvSizeReqs[circBufInd] =
7989  ireceive<int, int_type> (recvSizeBufs[circBufInd],
7990  recvRank, sizeTag, comm);
7991  }
7992 
7993  if (p + 1 < numProcs) {
7994  const int recvRank = p + 1;
7995  const int circBufInd = recvRank % 3;
7996 
7997  // Wait on receive-size receive from Process p + 1.
7998  if (debug) {
7999  std::ostringstream os;
8000  os << myRank << ": Wait on receive-size receive from Process "
8001  << recvRank << endl;
8002  *err << os.str ();
8003  }
8004  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
8005 
8006  // We received the number of rows of data. (The data
8007  // come in two columns.)
8008  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
8009  if (debug && recvNumRows == -1) {
8010  std::ostringstream os;
8011  os << myRank << ": Result of receive-size receive from Process "
8012  << recvRank << " is -1. This should never happen, and "
8013  "suggests that the receive never got posted. Please report "
8014  "this bug to the Tpetra developers." << endl;
8015  *err << os.str ();
8016  }
8017 
8018  // Post receive-data receive from Process p + 1.
8019  recvDataBufs[circBufInd].resize (recvNumRows * 2);
8020  if (debug) {
8021  std::ostringstream os;
8022  os << myRank << ": Post receive-data receive from Process "
8023  << recvRank << ": tag = " << dataTag << ", buffer size = "
8024  << recvDataBufs[circBufInd].size () << endl;
8025  *err << os.str ();
8026  }
8027  if (! recvDataReqs[circBufInd].is_null ()) {
8028  std::ostringstream os;
8029  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
8030  << "null, for the receive-data receive from Process "
8031  << recvRank << "! This may mean that this process never "
8032  << "finished waiting for the receive from Process "
8033  << (recvRank - 3) << "." << endl;
8034  *err << os.str ();
8035  }
8036  recvDataReqs[circBufInd] =
8037  ireceive<int, int_type> (recvDataBufs[circBufInd],
8038  recvRank, dataTag, comm);
8039  }
8040 
8041  // Wait on receive-data receive from Process p.
8042  const int recvRank = p;
8043  const int circBufInd = recvRank % 3;
8044  if (debug) {
8045  std::ostringstream os;
8046  os << myRank << ": Wait on receive-data receive from Process "
8047  << recvRank << endl;
8048  *err << os.str ();
8049  }
8050  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
8051 
8052  // Write Process p's data. Number of rows lives in
8053  // recvSizeBufs[circBufInd], and the actual data live in
8054  // recvDataBufs[circBufInd]. Do this after posting receives,
8055  // in order to expose overlap of comm. with file I/O.
8056  if (debug) {
8057  std::ostringstream os;
8058  os << myRank << ": Write GIDs and PIDs from Process "
8059  << recvRank << endl;
8060  *err << os.str () << endl;
8061  }
8062  const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
8063  if (debug && printNumRows == -1) {
8064  std::ostringstream os;
8065  os << myRank << ": Result of receive-size receive from Process "
8066  << recvRank << " was -1. This should never happen, and "
8067  "suggests that its receive-size receive was never posted. "
8068  "Please report this bug to the Tpetra developers." << endl;
8069  *err << os.str ();
8070  }
8071  if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
8072  std::ostringstream os;
8073  os << myRank << ": Result of receive-size receive from Proc "
8074  << recvRank << " was " << printNumRows << " > 0, but "
8075  "recvDataBufs[" << circBufInd << "] is null. This should "
8076  "never happen. Please report this bug to the Tpetra "
8077  "developers." << endl;
8078  *err << os.str ();
8079  }
8080  ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
8081  for (int_type k = 0; k < printNumRows; ++k) {
8082  const int_type gid = printData[2*k];
8083  const int_type pid = printData[2*k+1];
8084  out << gid << endl << pid << endl;
8085  }
8086  }
8087  else if (myRank == p) { // Process p
8088  // Wait on my send-data send.
8089  if (debug) {
8090  std::ostringstream os;
8091  os << myRank << ": Wait on my send-data send" << endl;
8092  *err << os.str ();
8093  }
8094  wait<int> (comm, outArg (sendReqData));
8095  }
8096  else if (myRank == p + 1) { // Process p + 1
8097  // Post send-data send to Process 0.
8098  if (debug) {
8099  std::ostringstream os;
8100  os << myRank << ": Post send-data send: tag = " << dataTag
8101  << endl;
8102  *err << os.str ();
8103  }
8104  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
8105  // Wait on my send-size send.
8106  if (debug) {
8107  std::ostringstream os;
8108  os << myRank << ": Wait on my send-size send" << endl;
8109  *err << os.str ();
8110  }
8111  wait<int> (comm, outArg (sendReqSize));
8112  }
8113  else if (myRank == p + 2) { // Process p + 2
8114  // Post send-size send to Process 0.
8115  if (debug) {
8116  std::ostringstream os;
8117  os << myRank << ": Post send-size send: size = "
8118  << sendDataSize[0] << ", tag = " << sizeTag << endl;
8119  *err << os.str ();
8120  }
8121  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
8122  }
8123  }
8124 
8125  if (! err.is_null ()) {
8126  err->popTab ();
8127  }
8128  if (debug) {
8129  *err << myRank << ": writeMap: Done" << endl;
8130  }
8131  if (! err.is_null ()) {
8132  err->popTab ();
8133  }
8134  }
8135 
8137  static void
8138  writeMapFile (const std::string& filename,
8139  const map_type& map)
8140  {
8141  const int myRank = map.getComm ()->getRank ();
8142  std::ofstream out;
8143  if (myRank == 0) { // Only open the file on Proc 0.
8144  out.open (filename.c_str());
8145  }
8146  writeMap (out, map);
8147  // We can rely on the destructor of the output stream to close
8148  // the file on scope exit, even if writeDense() throws an
8149  // exception.
8150  }
8151 
8152  private:
8176  static void
8177  printAsComment (std::ostream& out, const std::string& str)
8178  {
8179  using std::endl;
8180  std::istringstream inpstream (str);
8181  std::string line;
8182 
8183  while (getline (inpstream, line)) {
8184  if (! line.empty()) {
8185  // Note that getline() doesn't store '\n', so we have to
8186  // append the endline ourselves.
8187  if (line[0] == '%') { // Line starts with a comment character.
8188  out << line << endl;
8189  }
8190  else { // Line doesn't start with a comment character.
8191  out << "%% " << line << endl;
8192  }
8193  }
8194  }
8195  }
8196 
8197  public:
8198 
8217  static void
8218  writeOperator(const std::string& fileName, operator_type const &A) {
8219  Teuchos::ParameterList pl;
8220  writeOperator(fileName, A, pl);
8221  }
8222 
8243  static void
8244  writeOperator (std::ostream& out, const operator_type& A) {
8245  Teuchos::ParameterList pl;
8246  writeOperator (out, A, pl);
8247  }
8248 
8285  static void
8286  writeOperator (const std::string& fileName,
8287  const operator_type& A,
8288  const Teuchos::ParameterList& params)
8289  {
8290  std::ofstream out;
8291  std::string tmpFile = "__TMP__" + fileName;
8292  const int myRank = A.getDomainMap()->getComm()->getRank();
8293  bool precisionChanged=false;
8294  int oldPrecision;
8295  // The number of nonzero entries in a Tpetra::Operator is
8296  // unknown until probing is completed. In order to write a
8297  // MatrixMarket header, we write the matrix to a temporary
8298  // file.
8299  //
8300  // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8301  // TEMPORARY FILE.
8302  if (myRank==0) {
8303  if (std::ifstream(tmpFile))
8304  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8305  "writeOperator: temporary file " << tmpFile << " already exists");
8306  out.open(tmpFile.c_str());
8307  if (params.isParameter("precision")) {
8308  oldPrecision = out.precision(params.get<int>("precision"));
8309  precisionChanged=true;
8310  }
8311  }
8312 
8313  const std::string header = writeOperatorImpl(out, A, params);
8314 
8315  if (myRank==0) {
8316  if (precisionChanged)
8317  out.precision(oldPrecision);
8318  out.close();
8319  out.open(fileName.c_str(), std::ios::binary);
8320  bool printMatrixMarketHeader = true;
8321  if (params.isParameter("print MatrixMarket header"))
8322  printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8323  if (printMatrixMarketHeader && myRank == 0) {
8324  // Write header to final file.
8325  out << header;
8326  }
8327  // Append matrix from temporary to final file.
8328  std::ifstream src(tmpFile, std::ios_base::binary);
8329  out << src.rdbuf();
8330  src.close();
8331  // Delete the temporary file.
8332  remove(tmpFile.c_str());
8333  }
8334  }
8335 
8374  static void
8375  writeOperator (std::ostream& out,
8376  const operator_type& A,
8377  const Teuchos::ParameterList& params)
8378  {
8379  const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8380 
8381  // The number of nonzero entries in a Tpetra::Operator is
8382  // unknown until probing is completed. In order to write a
8383  // MatrixMarket header, we write the matrix to a temporary
8384  // output stream.
8385  //
8386  // NOTE (mfh 23 May 2015): Writing to a temporary output
8387  // stream may double the memory usage, depending on whether
8388  // 'out' is a file stream or an in-memory output stream (e.g.,
8389  // std::ostringstream). It might be wise to use a temporary
8390  // file instead. However, please look carefully at POSIX
8391  // functions for safe creation of temporary files. Don't just
8392  // prepend "__TMP__" to the filename and hope for the best.
8393  // Furthermore, it should be valid to call the std::ostream
8394  // overload of this method even when Process 0 does not have
8395  // access to a file system.
8396  std::ostringstream tmpOut;
8397  if (myRank == 0) {
8398  if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8399  (void) tmpOut.precision (params.get<int> ("precision"));
8400  }
8401  }
8402 
8403  const std::string header = writeOperatorImpl (tmpOut, A, params);
8404 
8405  if (myRank == 0) {
8406  bool printMatrixMarketHeader = true;
8407  if (params.isParameter ("print MatrixMarket header") &&
8408  params.isType<bool> ("print MatrixMarket header")) {
8409  printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8410  }
8411  if (printMatrixMarketHeader && myRank == 0) {
8412  out << header; // write header to final output stream
8413  }
8414  // Append matrix from temporary output stream to final output stream.
8415  //
8416  // NOTE (mfh 23 May 2015) This might use a lot of memory.
8417  // However, we should not use temporary files in this
8418  // method. Since it does not access the file system (unlike
8419  // the overload that takes a file name), it should not
8420  // require the file system at all.
8421  //
8422  // If memory usage becomes a problem, one thing we could do
8423  // is write the entries of the Operator one column (or a few
8424  // columns) at a time. The Matrix Market sparse format does
8425  // not impose an order on its entries, so it would be OK to
8426  // write them in that order.
8427  out << tmpOut.str ();
8428  }
8429  }
8430 
8431  private:
8432 
8440  static std::string
8441  writeOperatorImpl (std::ostream& os,
8442  const operator_type& A,
8443  const Teuchos::ParameterList& params)
8444  {
8445  using Teuchos::RCP;
8446  using Teuchos::rcp;
8447  using Teuchos::ArrayRCP;
8448  using Teuchos::Array;
8449 
8450  typedef local_ordinal_type LO;
8451  typedef global_ordinal_type GO;
8452  typedef scalar_type Scalar;
8453  typedef Teuchos::OrdinalTraits<LO> TLOT;
8454  typedef Teuchos::OrdinalTraits<GO> TGOT;
8455  typedef Tpetra::Import<LO, GO, node_type> import_type;
8456  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
8457 
8458  const map_type& domainMap = *(A.getDomainMap());
8459  RCP<const map_type> rangeMap = A.getRangeMap();
8460  RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8461  const int myRank = comm->getRank();
8462  const size_t numProcs = comm->getSize();
8463 
8464  size_t numMVs = 10;
8465  if (params.isParameter("probing size"))
8466  numMVs = params.get<int>("probing size");
8467 
8468  GO globalNnz = 0;
8469  GO minColGid = domainMap.getMinAllGlobalIndex();
8470  GO maxColGid = domainMap.getMaxAllGlobalIndex();
8471  // Rather than replicating the domainMap on all processors, we instead
8472  // iterate from the min GID to the max GID. If the map is gappy,
8473  // there will be invalid GIDs, i.e., GIDs no one has. This will require
8474  // unnecessary matvecs against potentially zero vectors.
8475  GO numGlobElts = maxColGid - minColGid + TGOT::one();
8476  GO numChunks = numGlobElts / numMVs;
8477  GO rem = numGlobElts % numMVs;
8478  GO indexBase = rangeMap->getIndexBase();
8479 
8480  int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8481  if (params.isParameter("zero-based indexing")) {
8482  if (params.get<bool>("zero-based indexing") == true)
8483  offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8484  }
8485 
8486  // Create map that replicates the range map on pid 0 and is empty for all other pids
8487  size_t numLocalRangeEntries = rangeMap->getNodeNumElements();
8488 
8489  // Create contiguous source map
8490  RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8491  indexBase, comm));
8492  // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8493  mv_type_go allGids(allGidsMap,1);
8494  Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8495 
8496  for (size_t i=0; i<numLocalRangeEntries; i++)
8497  allGidsData[i] = rangeMap->getGlobalElement(i);
8498  allGidsData = Teuchos::null;
8499 
8500  // Create target map that is nontrivial only on pid 0
8501  GO numTargetMapEntries=TGOT::zero();
8502  Teuchos::Array<GO> importGidList;
8503  if (myRank==0) {
8504  numTargetMapEntries = rangeMap->getGlobalNumElements();
8505  importGidList.reserve(numTargetMapEntries);
8506  for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8507  } else {
8508  importGidList.reserve(numTargetMapEntries);
8509  }
8510  RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8511 
8512  // Import all rangeMap GIDs to pid 0
8513  import_type gidImporter(allGidsMap, importGidMap);
8514  mv_type_go importedGids(importGidMap, 1);
8515  importedGids.doImport(allGids, gidImporter, INSERT);
8516 
8517  // The following import map will be non-trivial only on pid 0.
8518  ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8519  RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8520 
8521  // Importer from original range map to pid 0
8522  import_type importer(rangeMap, importMap);
8523  // Target vector on pid 0
8524  RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8525 
8526  RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8527  RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8528 
8529  Array<GO> globalColsArray, localColsArray;
8530  globalColsArray.reserve(numMVs);
8531  localColsArray.reserve(numMVs);
8532 
8533  ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8534  for (size_t i=0; i<numMVs; ++i)
8535  eiData[i] = ei->getDataNonConst(i);
8536 
8537  // //////////////////////////////////////
8538  // Discover A by chunks
8539  // //////////////////////////////////////
8540  for (GO k=0; k<numChunks; ++k) {
8541  for (size_t j=0; j<numMVs; ++j ) {
8542  //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8543  GO curGlobalCol = minColGid + k*numMVs + j;
8544  globalColsArray.push_back(curGlobalCol);
8545  //TODO extract the g2l map outside of this loop loop
8546  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8547  if (curLocalCol != TLOT::invalid()) {
8548  eiData[j][curLocalCol] = TGOT::one();
8549  localColsArray.push_back(curLocalCol);
8550  }
8551  }
8552  //TODO Do the views eiData need to be released prior to the matvec?
8553 
8554  // probe
8555  A.apply(*ei,*colsA);
8556 
8557  colsOnPid0->doImport(*colsA,importer,INSERT);
8558 
8559  if (myRank==0)
8560  globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8561  globalColsArray, offsetToUseInPrinting);
8562 
8563  //zero out the ei's
8564  for (size_t j=0; j<numMVs; ++j ) {
8565  for (int i=0; i<localColsArray.size(); ++i)
8566  eiData[j][localColsArray[i]] = TGOT::zero();
8567  }
8568  globalColsArray.clear();
8569  localColsArray.clear();
8570 
8571  }
8572 
8573  // //////////////////////////////////////
8574  // Handle leftover part of A
8575  // //////////////////////////////////////
8576  if (rem > 0) {
8577  for (int j=0; j<rem; ++j ) {
8578  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8579  globalColsArray.push_back(curGlobalCol);
8580  //TODO extract the g2l map outside of this loop loop
8581  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8582  if (curLocalCol != TLOT::invalid()) {
8583  eiData[j][curLocalCol] = TGOT::one();
8584  localColsArray.push_back(curLocalCol);
8585  }
8586  }
8587  //TODO Do the views eiData need to be released prior to the matvec?
8588 
8589  // probe
8590  A.apply(*ei,*colsA);
8591 
8592  colsOnPid0->doImport(*colsA,importer,INSERT);
8593  if (myRank==0)
8594  globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8595  globalColsArray, offsetToUseInPrinting);
8596 
8597  //zero out the ei's
8598  for (int j=0; j<rem; ++j ) {
8599  for (int i=0; i<localColsArray.size(); ++i)
8600  eiData[j][localColsArray[i]] = TGOT::zero();
8601  }
8602  globalColsArray.clear();
8603  localColsArray.clear();
8604 
8605  }
8606 
8607  // Return the Matrix Market header. It includes the header
8608  // line (that starts with "%%"), some comments, and the triple
8609  // of matrix dimensions and number of nonzero entries. We
8610  // don't actually print this here, because we don't know the
8611  // number of nonzero entries until after probing.
8612  std::ostringstream oss;
8613  if (myRank == 0) {
8614  oss << "%%MatrixMarket matrix coordinate ";
8615  if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8616  oss << "complex";
8617  } else {
8618  oss << "real";
8619  }
8620  oss << " general" << std::endl;
8621  oss << "% Tpetra::Operator" << std::endl;
8622  std::time_t now = std::time(NULL);
8623  oss << "% time stamp: " << ctime(&now);
8624  oss << "% written from " << numProcs << " processes" << std::endl;
8625  size_t numRows = rangeMap->getGlobalNumElements();
8626  size_t numCols = domainMap.getGlobalNumElements();
8627  oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8628  }
8629 
8630  return oss.str ();
8631  }
8632 
8633  static global_ordinal_type
8634  writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8635  Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8636  Teuchos::Array<global_ordinal_type> const &colsArray,
8637  global_ordinal_type const & indexBase) {
8638 
8639  typedef global_ordinal_type GO;
8640  typedef scalar_type Scalar;
8641  typedef Teuchos::ScalarTraits<Scalar> STS;
8642 
8643  GO nnz=0;
8644  const Scalar zero = STS::zero();
8645  const size_t numRows = colsA.getGlobalLength();
8646  for (size_t j=0; j<numCols; ++j) {
8647  Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8648  const GO J = colsArray[j];
8649  for (size_t i=0; i<numRows; ++i) {
8650  const Scalar val = curCol[i];
8651  if (val!=zero) {
8652  os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8653  ++nnz;
8654  }
8655  }
8656  }
8657 
8658  return nnz;
8659 
8660  }
8661 
8662  public:
8663 
8664  }; // class Writer
8665 
8666  } // namespace MatrixMarket
8667 } // namespace Tpetra
8668 
8669 #endif // __MatrixMarket_Tpetra_hpp
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
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...
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, const bool tolerant=false, const bool debug=false)
Variant of readMap (above) that takes an explicit Node instance.
void getGlobalRowView(const GlobalOrdinal gblRow, Teuchos::ArrayView< const GlobalOrdinal > &gblColInds) const override
Get a const, non-persisting view of the given global row&#39;s global column indices, as a Teuchos::Array...
GlobalOrdinal getMaxAllGlobalIndex() const
The maximum global index over all processes in the communicator.
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)
Print the sparse matrix in Matrix Market format, with comments.
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.
Scalar scalar_type
This class&#39; first template parameter; the type of each entry in the MultiVector.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y...
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
A distributed dense vector.
global_size_t getGlobalLength() const
Global number of rows in the multivector.
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Variant of readSparseFile above that takes a Node object.
SparseMatrixType::local_ordinal_type local_ordinal_type
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.
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.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Variant of readSparseGraphFile (filename, comm, constructorParams, fillCompleteParams, tolerant, debug) that takes a Node object.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
GlobalOrdinal getMinAllGlobalIndex() const
The minimum global index over all processes in the communicator.
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
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Variant of the above readSparse() method that takes a Kokkos Node.
virtual void apply(const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const =0
Computes the operator-multivector application.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
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.
size_t getLocalLength() const
Local number of rows on the calling process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, CombineMode CM)
Import data into this object using an Import object ("forward mode").
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
static 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.
size_t getNumVectors() const
Number of columns in the multivector.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, const bool tolerant=false, const bool debug=false)
Variant of readMapFile (above) that takes an explicit Node instance.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps. ...
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Variant of readDenseMatrix (see above) that takes a Node.
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator, in rank order.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments...
size_t global_size_t
Global size_t object.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
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...
Insert new values that don&#39;t currently exist.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Variant of the above readSparseGraph() method that takes a Kokkos Node.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Variant of readMap (above) that takes an explicit Node instance.
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::ArrayRCP< const Scalar > getData(size_t j) const
Const view of the local values in a particular vector of this multivector.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Variant of readSparseGraph() above that takes a Node object.
GlobalOrdinal getMinGlobalIndex() const
The minimum global index owned by the calling process.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
From a distributed map build a map with all GIDs on the root node.
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.
bool isGloballyIndexed() const override
If graph indices are in the global range, this function returns true. Otherwise, this function return...
LocalOrdinal getLocalElement(GlobalOrdinal globalIndex) const
The local index corresponding to the given global index.
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.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Teuchos::ArrayView< const GlobalOrdinal > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream...
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments...
void getLocalRowView(const LocalOrdinal lclRow, Teuchos::ArrayView< const LocalOrdinal > &lclColInds) const override
Get a const, non-persisting view of the given local row&#39;s local column indices, as a Teuchos::ArrayVi...
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)
Print the sparse matrix in Matrix Market format, with comments.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Like readVectorFile() (see above), but with a supplied Node object.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Variant of readSparse() above that takes a Node object.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
static 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.
Abstract interface for operators (e.g., matrices and preconditioners).
SparseMatrixType sparse_matrix_type
This class&#39; template parameter; a specialization of CrsMatrix.
A parallel distribution of indices over processes.
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 Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Variant of readDense (see above) that takes a Node.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
Matrix Market file reader for CrsMatrix and MultiVector.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< node_type > &node, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream, with a supplied Node.
Matrix Market file writer for CrsMatrix and MultiVector.
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
void get1dCopy(const Teuchos::ArrayView< Scalar > &A, const size_t LDA) const
Fill the given array with a copy of this multivector&#39;s local values.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< node_type > &pNode, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Variant of readSparseFile that takes a Node object.
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp...
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< node_type > &node, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Variant of readSparseGraphFile (filename, comm, callFillComplete, tolerant, debug) that takes a Node ...
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.