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