Tpetra parallel linear algebra  Version of the Day
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef __MatrixMarket_Tpetra_hpp
43 #define __MatrixMarket_Tpetra_hpp
44 
56 #include "Tpetra_Details_gathervPrint.hpp"
57 #include "Tpetra_CrsMatrix.hpp"
58 #include "Tpetra_Operator.hpp"
59 #include "Tpetra_Vector.hpp"
61 #include "Teuchos_MatrixMarket_Raw_Adder.hpp"
62 #include "Teuchos_MatrixMarket_Raw_Graph_Adder.hpp"
63 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
64 #include "Teuchos_MatrixMarket_SymmetrizingGraphAdder.hpp"
65 #include "Teuchos_MatrixMarket_assignScalar.hpp"
66 #include "Teuchos_MatrixMarket_Banner.hpp"
67 #include "Teuchos_MatrixMarket_CoordDataReader.hpp"
68 #include "Teuchos_SetScientific.hpp"
69 
70 #include <algorithm>
71 #include <fstream>
72 #include <iostream>
73 #include <iterator>
74 #include <vector>
75 #include <stdexcept>
76 #include <numeric>
77 
78 namespace Tpetra {
108  namespace MatrixMarket {
164  template<class SparseMatrixType>
165  class Reader {
166  public:
168  typedef SparseMatrixType sparse_matrix_type;
169  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
170 
173  typedef typename SparseMatrixType::scalar_type scalar_type;
176  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
184  typedef typename SparseMatrixType::global_ordinal_type
187  typedef typename SparseMatrixType::node_type node_type;
188 
193 
195  typedef MultiVector<scalar_type,
199 
201  typedef Vector<scalar_type,
205 
206  typedef Teuchos::Comm<int> comm_type;
208 
209 #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
Tpetra::MatrixMarket::Reader::sparse_matrix_type
SparseMatrixType sparse_matrix_type
This class' template parameter; a specialization of CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:168
Tpetra::Map::getMinGlobalIndex
GlobalOrdinal getMinGlobalIndex() const
The minimum global index owned by the calling process.
Definition: Tpetra_Map_decl.hpp:663
Tpetra::MatrixMarket::Reader::sparse_graph_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:192
Tpetra::MatrixMarket::Writer::writeSparseFile
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
Definition: MatrixMarket_Tpetra.hpp:5964
MatrixMarket
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp....
Tpetra::CrsGraph::getLocalRowView
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's local column indices, as a Teuchos::ArrayVi...
Definition: Tpetra_CrsGraph_def.hpp:3074
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
Definition: MatrixMarket_Tpetra.hpp:6600
Tpetra::MatrixMarket::Reader::readSparseGraph
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
Definition: MatrixMarket_Tpetra.hpp:2049
Tpetra::CrsGraph::getDomainMap
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
Definition: Tpetra_CrsGraph_def.hpp:1116
Tpetra::MatrixMarket::Writer::writeSparse
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
Definition: MatrixMarket_Tpetra.hpp:6272
Tpetra::MatrixMarket::Writer::writeSparseFile
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
Definition: MatrixMarket_Tpetra.hpp:5931
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.
Definition: MatrixMarket_Tpetra.hpp:8256
Tpetra::MatrixMarket::Reader::readSparseGraph
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:1974
Tpetra::CrsGraph::isGloballyIndexed
bool isGloballyIndexed() const override
Whether the graph's column indices are stored as global indices.
Definition: Tpetra_CrsGraph_def.hpp:1334
Tpetra::MatrixMarket::Reader::readSparseGraphFile
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file, with provided Maps.
Definition: MatrixMarket_Tpetra.hpp:1835
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
Definition: MatrixMarket_Tpetra.hpp:8413
Tpetra::MatrixMarket::Reader::readSparse
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
Definition: MatrixMarket_Tpetra.hpp:3437
Tpetra::Export
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Definition: Tpetra_Export_decl.hpp:124
Tpetra::MatrixMarket::Reader::readMapFile
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:4283
Tpetra::MatrixMarket::Writer::multivector_type
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5865
Tpetra::Map::getNodeElementList
Teuchos::ArrayView< const GlobalOrdinal > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
Definition: Tpetra_Map_def.hpp:1650
Tpetra::MatrixMarket::Reader::global_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
Definition: MatrixMarket_Tpetra.hpp:185
Tpetra::MultiVector
One or more distributed dense vectors.
Definition: Tpetra_MultiVector_decl.hpp:425
Tpetra::MatrixMarket::Writer::writeDense
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Definition: MatrixMarket_Tpetra.hpp:7628
Tpetra::MatrixMarket::Reader::readSparseFile
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:2160
Tpetra::MatrixMarket::Writer::map_type
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5867
Tpetra::MatrixMarket::Writer::writeSparse
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
Definition: MatrixMarket_Tpetra.hpp:6698
Tpetra::MatrixMarket::Reader
Matrix Market file reader for CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:165
Tpetra::CrsGraph::getRowMap
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
Definition: Tpetra_CrsGraph_def.hpp:1100
Tpetra::Map
A parallel distribution of indices over processes.
Definition: Tpetra_Map_decl.hpp:246
Tpetra::MatrixMarket::Writer::writeDenseFile
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Definition: MatrixMarket_Tpetra.hpp:6790
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
Definition: MatrixMarket_Tpetra.hpp:8324
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
Definition: MatrixMarket_Tpetra.hpp:6649
Tpetra::Import
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Definition: Tpetra_Import_decl.hpp:116
Tpetra::MatrixMarket::Writer
Matrix Market file writer for CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:5842
Tpetra::Operator
Abstract interface for operators (e.g., matrices and preconditioners).
Definition: Tpetra_Operator.hpp:86
Tpetra::MatrixMarket::Writer::writeDenseFile
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
Definition: MatrixMarket_Tpetra.hpp:6771
Tpetra::Details::gathervPrint
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator,...
Definition: Tpetra_Details_gathervPrint.cpp:52
Tpetra::MatrixMarket::Reader::readSparseGraphFile
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.
Definition: MatrixMarket_Tpetra.hpp:1648
Tpetra::MatrixMarket::Writer::writeOperator
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
Definition: MatrixMarket_Tpetra.hpp:8282
Tpetra::MatrixMarket::Reader::readSparseFile
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
Definition: MatrixMarket_Tpetra.hpp:2230
Tpetra::MatrixMarket::Reader::readSparse
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:2301
Tpetra::Map::getNodeNumElements
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Definition: Tpetra_Map_decl.hpp:618
Tpetra::MatrixMarket::Writer::writeMapFile
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
Definition: MatrixMarket_Tpetra.hpp:8176
Tpetra::MatrixMarket::Writer::writeSparseGraph
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream.
Definition: MatrixMarket_Tpetra.hpp:6315
Tpetra::MatrixMarket::Writer::writeSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:5973
Tpetra::MatrixMarket::Writer::writeSparseFile
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.
Definition: MatrixMarket_Tpetra.hpp:5906
Tpetra::MatrixMarket::Reader::readDenseFile
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:4058
Tpetra::MatrixMarket::Reader::local_ordinal_type
SparseMatrixType::local_ordinal_type local_ordinal_type
Definition: MatrixMarket_Tpetra.hpp:176
Tpetra::MatrixMarket::Reader::readVector
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:4237
Tpetra::MatrixMarket::Reader::readSparseFile
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:2092
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments.
Definition: MatrixMarket_Tpetra.hpp:6633
Tpetra::Map::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Definition: Tpetra_Map_def.hpp:2102
Tpetra::MatrixMarket::Reader::readMap
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream.
Definition: MatrixMarket_Tpetra.hpp:5362
Tpetra::MatrixMarket::Reader::readSparseGraphFile
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:1734
Tpetra::MatrixMarket::Writer::writeSparse
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.
Definition: MatrixMarket_Tpetra.hpp:6707
Tpetra::MatrixMarket::Reader::readSparse
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:2866
Tpetra::MatrixMarket::Reader::multivector_type
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:198
Tpetra::Vector
A distributed dense vector.
Definition: Tpetra_Vector_decl.hpp:82
Tpetra::Map::getGlobalNumElements
global_size_t getGlobalNumElements() const
The number of elements in this Map.
Definition: Tpetra_Map_decl.hpp:609
Tpetra::MatrixMarket::Reader::scalar_type
SparseMatrixType::scalar_type scalar_type
Definition: MatrixMarket_Tpetra.hpp:173
Tpetra::MatrixMarket::Writer::writeDenseFile
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Definition: MatrixMarket_Tpetra.hpp:6804
Tpetra::MatrixMarket::Writer::global_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:5857
Tpetra::MatrixMarket::Writer::writeSparseGraphFile
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments,...
Definition: MatrixMarket_Tpetra.hpp:6668
Tpetra::MatrixMarket::Writer::writeDense
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
Definition: MatrixMarket_Tpetra.hpp:7595
Tpetra::MatrixMarket::Reader::readSparseGraph
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:1908
Tpetra::MatrixMarket::Writer::writeSparseGraph
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments.
Definition: MatrixMarket_Tpetra.hpp:6558
Tpetra::CrsGraph::getComm
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
Definition: Tpetra_CrsGraph_def.hpp:1395
Tpetra::CrsGraph::getGlobalNumEntries
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Definition: Tpetra_CrsGraph_def.hpp:1186
Tpetra::MatrixMarket::Writer::writeMap
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
Definition: MatrixMarket_Tpetra.hpp:7659
Tpetra::MatrixMarket::Writer::writeDense
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Definition: MatrixMarket_Tpetra.hpp:7614
Tpetra::DistObject::getMap
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Definition: Tpetra_DistObject_decl.hpp:541
Tpetra::MatrixMarket::Writer::writeDenseFile
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
Definition: MatrixMarket_Tpetra.hpp:6743
Tpetra::DistObject::doImport
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 ("forward mode").
Definition: Tpetra_DistObject_def.hpp:274
Tpetra::CrsGraph
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Definition: Tpetra_CrsGraph_decl.hpp:278
Tpetra::MatrixMarket::Reader::readDense
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
Definition: MatrixMarket_Tpetra.hpp:4210
Tpetra::MatrixMarket::Writer::sparse_matrix_type
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:5845
Tpetra::Operator::getDomainMap
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X....
Tpetra::MatrixMarket::Writer::scalar_type
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
Definition: MatrixMarket_Tpetra.hpp:5849
Tpetra::MultiVector::getVector
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
Definition: Tpetra_MultiVector_def.hpp:3526
Tpetra::MatrixMarket::Writer::local_ordinal_type
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
Definition: MatrixMarket_Tpetra.hpp:5851
Tpetra::MatrixMarket::Writer::crs_graph_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:5869
Tpetra::Map::isContiguous
bool isContiguous() const
True if this Map is distributed contiguously, else false.
Definition: Tpetra_Map_def.hpp:1289
Tpetra::CrsGraph::getGlobalRowView
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's global column indices, as a Teuchos::Array...
Definition: Tpetra_CrsGraph_def.hpp:3118
Tpetra::MatrixMarket::Writer::writeMap
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
Definition: MatrixMarket_Tpetra.hpp:7675
Tpetra::CrsGraph::getRangeMap
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Definition: Tpetra_CrsGraph_def.hpp:1124
Tpetra::global_size_t
size_t global_size_t
Global size_t object.
Definition: Tpetra_ConfigDefs.hpp:109
Tpetra::MatrixMarket::Reader::node_type
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
Definition: MatrixMarket_Tpetra.hpp:187
Tpetra
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Tpetra_ComputeGatherMap.hpp
From a distributed map build a map with all GIDs on the root node.
Tpetra::MatrixMarket::Writer::writeSparse
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.
Definition: MatrixMarket_Tpetra.hpp:6011
Tpetra::MatrixMarket::Reader::vector_type
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
Definition: MatrixMarket_Tpetra.hpp:204
Tpetra::MatrixMarket::Writer::writeDense
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
Definition: MatrixMarket_Tpetra.hpp:6847
Tpetra::MatrixMarket::Reader::readMap
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream.
Definition: MatrixMarket_Tpetra.hpp:5412
Tpetra::CrsGraph::getColMap
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
Definition: Tpetra_CrsGraph_def.hpp:1108
Tpetra::MultiVector::getNumVectors
size_t getNumVectors() const
Number of columns in the multivector.
Definition: Tpetra_MultiVector_def.hpp:1807
Tpetra::MatrixMarket::Writer::node_type
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
Definition: MatrixMarket_Tpetra.hpp:5859
Tpetra::INSERT
@ INSERT
Insert new values that don't currently exist.
Definition: Tpetra_CombineMode.hpp:96
Tpetra::CrsGraph::fillComplete
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
Definition: Tpetra_CrsGraph_def.hpp:3890
Tpetra::MatrixMarket::Reader::readVectorFile
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
Definition: MatrixMarket_Tpetra.hpp:4115