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