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 
193 
195  typedef MultiVector<scalar_type,
199 
201  typedef Vector<scalar_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,
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
1602  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
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
1612  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
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,
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
Tpetra::MatrixMarket::Reader::sparse_matrix_type
SparseMatrixType sparse_matrix_type
This class' template parameter; a specialization of CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:168
Tpetra::MatrixMarket::Reader::readMapFile
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.
Definition: MatrixMarket_Tpetra.hpp:4276
Tpetra::MatrixMarket::Reader::sparse_graph_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:192
Tpetra::Classes::CrsGraph::getRangeMap
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Definition: Tpetra_CrsGraph_def.hpp:931
MatrixMarket
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp....
Tpetra::MatrixMarket::Reader::readSparse
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.
Definition: MatrixMarket_Tpetra.hpp:2295
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
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).
Definition: MatrixMarket_Tpetra.hpp:6569
Tpetra::MatrixMarket::Reader::readSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:2036
Tpetra::StaticProfile
Definition: Tpetra_ConfigDefs.hpp:131
Tpetra::MatrixMarket::Writer::writeSparse
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.
Definition: MatrixMarket_Tpetra.hpp:5987
Tpetra::MatrixMarket::Writer::writeSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:5901
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.
Definition: MatrixMarket_Tpetra.hpp:8218
Tpetra::MatrixMarket::Reader::readSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:1964
Tpetra::Classes::CrsGraph::getDomainMap
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
Definition: Tpetra_CrsGraph_def.hpp:922
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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.
Definition: MatrixMarket_Tpetra.hpp:1828
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
Definition: MatrixMarket_Tpetra.hpp:8375
Tpetra::MatrixMarket::Reader::readSparse
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.
Definition: MatrixMarket_Tpetra.hpp:3417
Tpetra::MatrixMarket::Reader::readVector
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.
Definition: MatrixMarket_Tpetra.hpp:4231
Tpetra::Classes::DistObject::doImport
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, CombineMode CM)
Import data into this object using an Import object ("forward mode").
Definition: Tpetra_DistObject_def.hpp:252
Tpetra::MatrixMarket::Reader::readMapFile
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.
Definition: MatrixMarket_Tpetra.hpp:4265
Tpetra::MatrixMarket::Writer::multivector_type
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5860
Tpetra::MatrixMarket::Reader::global_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
Definition: MatrixMarket_Tpetra.hpp:185
Tpetra::MatrixMarket::Reader::readVectorFile
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.
Definition: MatrixMarket_Tpetra.hpp:4109
Tpetra::Classes::Map::getGlobalNumElements
global_size_t getGlobalNumElements() const
The number of elements in this Map.
Definition: Tpetra_Map_decl.hpp:569
Tpetra::MatrixMarket::Writer::writeDense
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.
Definition: MatrixMarket_Tpetra.hpp:7590
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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,...
Definition: MatrixMarket_Tpetra.hpp:1750
Tpetra::MatrixMarket::Reader::readSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:2145
Tpetra::MatrixMarket::Writer::map_type
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5862
Tpetra::MatrixMarket::Reader
Matrix Market file reader for CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:165
Tpetra::Classes::CrsGraph::getGlobalRowView
void getGlobalRowView(const GlobalOrdinal gblRow, Teuchos::ArrayView< const GlobalOrdinal > &gblColInds) const override
Get a const, non-persisting view of the given global row's global column indices, as a Teuchos::Array...
Definition: Tpetra_CrsGraph_def.hpp:3025
Tpetra::Classes::Map::getMinGlobalIndex
GlobalOrdinal getMinGlobalIndex() const
The minimum global index owned by the calling process.
Definition: Tpetra_Map_decl.hpp:623
Tpetra::MatrixMarket::Reader::readSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:2159
Tpetra::Classes::CrsGraph::fillComplete
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.
Definition: Tpetra_CrsGraph_def.hpp:3785
Tpetra::MatrixMarket::Writer::writeDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:6750
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
Definition: MatrixMarket_Tpetra.hpp:8286
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
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...
Definition: MatrixMarket_Tpetra.hpp:6618
Tpetra::MatrixMarket::Writer
Matrix Market file writer for CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:5837
Tpetra::MatrixMarket::Reader::readSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:2090
Tpetra::MatrixMarket::Writer::writeDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:6731
Tpetra::Details::gathervPrint
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,...
Definition: Tpetra_Details_gathervPrint.cpp:52
Tpetra::MatrixMarket::Reader::readMap
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.
Definition: MatrixMarket_Tpetra.hpp:5366
Tpetra::Classes::Operator::getDomainMap
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....
Tpetra::Classes::DistObject::getMap
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Definition: Tpetra_DistObject_decl.hpp:510
Tpetra::Classes::CrsGraph::isGloballyIndexed
bool isGloballyIndexed() const override
If graph indices are in the global range, this function returns true. Otherwise, this function return...
Definition: Tpetra_CrsGraph_def.hpp:1156
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
Definition: MatrixMarket_Tpetra.hpp:8244
Tpetra::MatrixMarket::Reader::readSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:2213
Tpetra::MatrixMarket::Reader::readSparse
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.
Definition: MatrixMarket_Tpetra.hpp:2284
Tpetra::MatrixMarket::Writer::writeMapFile
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
Definition: MatrixMarket_Tpetra.hpp:8138
Tpetra::MatrixMarket::Writer::writeSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:6284
Tpetra::Classes::MultiVector::scalar_type
Scalar scalar_type
This class' first template parameter; the type of each entry in the MultiVector.
Definition: Tpetra_MultiVector_decl.hpp:398
Tpetra::DynamicProfile
Definition: Tpetra_ConfigDefs.hpp:132
Tpetra::MatrixMarket::Writer::writeSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:5949
Tpetra::MatrixMarket::Reader::readDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:4034
Tpetra::MatrixMarket::Reader::local_ordinal_type
SparseMatrixType::local_ordinal_type local_ordinal_type
Definition: MatrixMarket_Tpetra.hpp:176
Tpetra::MatrixMarket::Reader::readVector
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.
Definition: MatrixMarket_Tpetra.hpp:4217
Tpetra::MatrixMarket::Reader::readSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:2079
Tpetra::MatrixMarket::Reader::readSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:1978
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
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.
Definition: MatrixMarket_Tpetra.hpp:6602
Tpetra::Classes::MultiVector::getVector
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.
Definition: Tpetra_MultiVector_def.hpp:3717
Tpetra::MatrixMarket::Reader::readMap
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.
Definition: MatrixMarket_Tpetra.hpp:5353
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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.
Definition: MatrixMarket_Tpetra.hpp:1730
Tpetra::MatrixMarket::Writer::writeSparse
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.
Definition: MatrixMarket_Tpetra.hpp:6667
Tpetra::MatrixMarket::Reader::readSparse
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.
Definition: MatrixMarket_Tpetra.hpp:2848
Tpetra::MatrixMarket::Reader::multivector_type
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:198
Tpetra::Classes::Import
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Definition: Tpetra_Import_decl.hpp:115
Tpetra::MatrixMarket::Reader::scalar_type
SparseMatrixType::scalar_type scalar_type
Definition: MatrixMarket_Tpetra.hpp:173
Tpetra::MatrixMarket::Writer::writeDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:6764
Tpetra::MatrixMarket::Writer::global_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:5852
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
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,...
Definition: MatrixMarket_Tpetra.hpp:6637
Tpetra::MatrixMarket::Reader::readSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:1914
Tpetra::MatrixMarket::Writer::writeDense
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.
Definition: MatrixMarket_Tpetra.hpp:7557
Tpetra::MatrixMarket::Reader::readSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:1901
Tpetra::Classes::MultiVector
One or more distributed dense vectors.
Definition: Tpetra_MultiVector_decl.hpp:389
Tpetra::MatrixMarket::Writer::writeSparseGraph
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.
Definition: MatrixMarket_Tpetra.hpp:6527
Tpetra::Classes::CrsGraph::getGlobalNumEntries
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Definition: Tpetra_CrsGraph_def.hpp:999
Tpetra::Classes::CrsGraph::getLocalRowView
void getLocalRowView(const LocalOrdinal lclRow, Teuchos::ArrayView< const LocalOrdinal > &lclColInds) const override
Get a const, non-persisting view of the given local row's local column indices, as a Teuchos::ArrayVi...
Definition: Tpetra_CrsGraph_def.hpp:2987
Tpetra::MatrixMarket::Writer::writeMap
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
Definition: MatrixMarket_Tpetra.hpp:7621
Tpetra::MatrixMarket::Writer::writeDense
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.
Definition: MatrixMarket_Tpetra.hpp:7576
Tpetra::Classes::Map::getNodeElementList
Teuchos::ArrayView< const GlobalOrdinal > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
Definition: Tpetra_Map_def.hpp:1515
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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 ...
Definition: MatrixMarket_Tpetra.hpp:1665
Tpetra::MatrixMarket::Writer::writeDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:6703
Tpetra::Classes::MultiVector::getNumVectors
size_t getNumVectors() const
Number of columns in the multivector.
Definition: Tpetra_MultiVector_def.hpp:1739
Tpetra::MatrixMarket::Reader::readDense
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.
Definition: MatrixMarket_Tpetra.hpp:4191
Tpetra::MatrixMarket::Writer::sparse_matrix_type
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:5840
Tpetra::MatrixMarket::Writer::scalar_type
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
Definition: MatrixMarket_Tpetra.hpp:5844
Tpetra::Classes::Map
A parallel distribution of indices over processes.
Definition: Tpetra_Map_decl.hpp:247
Tpetra::Classes::CrsGraph::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
Definition: Tpetra_CrsGraph_def.hpp:1219
Tpetra::MatrixMarket::Writer::local_ordinal_type
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
Definition: MatrixMarket_Tpetra.hpp:5846
Tpetra::MatrixMarket::Writer::crs_graph_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5864
Tpetra::Classes::Map::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Definition: Tpetra_Map_def.hpp:1967
Tpetra::Classes::Map::getNodeNumElements
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Definition: Tpetra_Map_decl.hpp:578
Tpetra::MatrixMarket::Writer::writeMap
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.
Definition: MatrixMarket_Tpetra.hpp:7637
Tpetra::Classes::CrsGraph::getRowMap
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
Definition: Tpetra_CrsGraph_def.hpp:904
Tpetra::MatrixMarket::Reader::readDense
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.
Definition: MatrixMarket_Tpetra.hpp:4202
Tpetra::MatrixMarket::Reader::readMap
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.
Definition: MatrixMarket_Tpetra.hpp:5415
Tpetra::global_size_t
size_t global_size_t
Global size_t object.
Definition: Tpetra_ConfigDefs.hpp:109
Tpetra::MatrixMarket::Reader::node_type
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:187
Tpetra::MatrixMarket::Reader::readDenseFile
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.
Definition: MatrixMarket_Tpetra.hpp:4049
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra_ComputeGatherMap.hpp
From a distributed map build a map with all GIDs on the root node.
Tpetra::MatrixMarket::Reader::readSparse
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.
Definition: MatrixMarket_Tpetra.hpp:2861
Tpetra::MatrixMarket::Reader::vector_type
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:204
Tpetra::Classes::Export
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Definition: Tpetra_Export_decl.hpp:124
Tpetra::MatrixMarket::Writer::writeDense
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.
Definition: MatrixMarket_Tpetra.hpp:6807
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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.
Definition: MatrixMarket_Tpetra.hpp:1647
Tpetra::MatrixMarket::Reader::readMap
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.
Definition: MatrixMarket_Tpetra.hpp:5403
Tpetra::Classes::CrsGraph::getColMap
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
Definition: Tpetra_CrsGraph_def.hpp:913
Tpetra::Classes::Map::isContiguous
bool isContiguous() const
True if this Map is distributed contiguously, else false.
Definition: Tpetra_Map_def.hpp:1157
Tpetra::Classes::Operator
Abstract interface for operators (e.g., matrices and preconditioners).
Definition: Tpetra_Operator.hpp:86
Tpetra::MatrixMarket::Writer::node_type
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:5854
Tpetra::INSERT
Insert new values that don't currently exist.
Definition: Tpetra_CombineMode.hpp:96
Tpetra::Classes::CrsGraph
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Definition: Tpetra_CrsGraph_decl.hpp:259
Tpetra::MatrixMarket::Reader::readVectorFile
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.
Definition: MatrixMarket_Tpetra.hpp:4093
Tpetra::Classes::Vector
A distributed dense vector.
Definition: Tpetra_Vector_decl.hpp:82