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 
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 
210  private:
216  typedef Teuchos::ArrayRCP<int>::size_type size_type;
217 
228  static Teuchos::RCP<const map_type>
229  makeRangeMap (const Teuchos::RCP<const comm_type>& pComm,
230  const global_ordinal_type numRows)
231  {
232  // Return a conventional, uniformly partitioned, contiguous map.
233  return rcp (new map_type (static_cast<global_size_t> (numRows),
234  static_cast<global_ordinal_type> (0),
235  pComm, GloballyDistributed));
236  }
237 
265  static Teuchos::RCP<const map_type>
266  makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
267  const Teuchos::RCP<const comm_type>& pComm,
268  const global_ordinal_type numRows)
269  {
270  // If the caller didn't provide a map, return a conventional,
271  // uniformly partitioned, contiguous map.
272  if (pRowMap.is_null ()) {
273  return rcp (new map_type (static_cast<global_size_t> (numRows),
274  static_cast<global_ordinal_type> (0),
275  pComm, GloballyDistributed));
276  }
277  else {
278  TEUCHOS_TEST_FOR_EXCEPTION
279  (! pRowMap->isDistributed () && pComm->getSize () > 1,
280  std::invalid_argument, "The specified row map is not distributed, "
281  "but the given communicator includes more than one process (in "
282  "fact, there are " << pComm->getSize () << " processes).");
283  TEUCHOS_TEST_FOR_EXCEPTION
284  (pRowMap->getComm () != pComm, std::invalid_argument,
285  "The specified row Map's communicator (pRowMap->getComm()) "
286  "differs from the given separately supplied communicator pComm.");
287  return pRowMap;
288  }
289  }
290 
305  static Teuchos::RCP<const map_type>
306  makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
307  const global_ordinal_type numRows,
308  const global_ordinal_type numCols)
309  {
310  // Abbreviations so that the map creation call isn't too long.
311  typedef local_ordinal_type LO;
312  typedef global_ordinal_type GO;
313  typedef node_type NT;
314 
315  if (numRows == numCols) {
316  return pRangeMap;
317  } else {
318  return createUniformContigMapWithNode<LO,GO,NT> (numCols,
319  pRangeMap->getComm ());
320  }
321  }
322 
395  static void
396  distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
397  Teuchos::ArrayRCP<size_t>& myRowPtr,
398  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
399  Teuchos::ArrayRCP<scalar_type>& myValues,
400  const Teuchos::RCP<const map_type>& pRowMap,
401  Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
402  Teuchos::ArrayRCP<size_t>& rowPtr,
403  Teuchos::ArrayRCP<global_ordinal_type>& colInd,
404  Teuchos::ArrayRCP<scalar_type>& values,
405  const bool debug=false)
406  {
407  using Teuchos::arcp;
408  using Teuchos::ArrayRCP;
409  using Teuchos::ArrayView;
410  using Teuchos::as;
411  using Teuchos::Comm;
412  using Teuchos::CommRequest;
413  using Teuchos::null;
414  using Teuchos::RCP;
415  using Teuchos::receive;
416  using Teuchos::send;
417  using std::cerr;
418  using std::endl;
419 
420  const bool extraDebug = false;
421  RCP<const comm_type> pComm = pRowMap->getComm ();
422  const int numProcs = pComm->getSize ();
423  const int myRank = pComm->getRank ();
424  const int rootRank = 0;
425 
426  // Type abbreviations to make the code more concise.
427  typedef global_ordinal_type GO;
428 
429  // List of the global indices of my rows. They may or may
430  // not be contiguous, and the row map need not be one-to-one.
431  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
432  const size_type myNumRows = myRows.size();
433  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
434  pRowMap->getNodeNumElements(),
435  std::logic_error,
436  "pRowMap->getNodeElementList().size() = "
437  << myNumRows
438  << " != pRowMap->getNodeNumElements() = "
439  << pRowMap->getNodeNumElements() << ". "
440  "Please report this bug to the Tpetra developers.");
441  TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
442  std::logic_error,
443  "On Proc 0: numEntriesPerRow.size() = "
444  << numEntriesPerRow.size()
445  << " != pRowMap->getNodeElementList().size() = "
446  << myNumRows << ". Please report this bug to the "
447  "Tpetra developers.");
448 
449  // Space for my proc's number of entries per row. Will be
450  // filled in below.
451  myNumEntriesPerRow = arcp<size_t> (myNumRows);
452 
453  if (myRank != rootRank) {
454  // Tell the root how many rows we have. If we're sending
455  // none, then we don't have anything else to send, nor does
456  // the root have to receive anything else.
457  send (*pComm, myNumRows, rootRank);
458  if (myNumRows != 0) {
459  // Now send my rows' global indices. Hopefully the cast
460  // to int doesn't overflow. This is unlikely, since it
461  // should fit in a LO, even though it is a GO.
462  send (*pComm, static_cast<int> (myNumRows),
463  myRows.getRawPtr(), rootRank);
464 
465  // I (this proc) don't care if my global row indices are
466  // contiguous, though the root proc does (since otherwise
467  // it needs to pack noncontiguous data into contiguous
468  // storage before sending). That's why we don't check
469  // for contiguousness here.
470 
471  // Ask the root process for my part of the array of the
472  // number of entries per row.
473  receive (*pComm, rootRank,
474  static_cast<int> (myNumRows),
475  myNumEntriesPerRow.getRawPtr());
476 
477  // Use the resulting array to figure out how many column
478  // indices and values I should ask from the root process.
479  const local_ordinal_type myNumEntries =
480  std::accumulate (myNumEntriesPerRow.begin(),
481  myNumEntriesPerRow.end(), 0);
482 
483  // Make space for my entries of the sparse matrix. Note
484  // that they don't have to be sorted by row index.
485  // Iterating through all my rows requires computing a
486  // running sum over myNumEntriesPerRow.
487  myColInd = arcp<GO> (myNumEntries);
488  myValues = arcp<scalar_type> (myNumEntries);
489  if (myNumEntries > 0) {
490  // Ask for that many column indices and values, if
491  // there are any.
492  receive (*pComm, rootRank,
493  static_cast<int> (myNumEntries),
494  myColInd.getRawPtr());
495  receive (*pComm, rootRank,
496  static_cast<int> (myNumEntries),
497  myValues.getRawPtr());
498  }
499  } // If I own at least one row
500  } // If I am not the root processor
501  else { // I _am_ the root processor
502  if (debug) {
503  cerr << "-- Proc 0: Copying my data from global arrays" << endl;
504  }
505  // Proc 0 still needs to (allocate, if not done already)
506  // and fill its part of the matrix (my*).
507  for (size_type k = 0; k < myNumRows; ++k) {
508  const GO myCurRow = myRows[k];
509  const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
510  myNumEntriesPerRow[k] = numEntriesInThisRow;
511  }
512  if (extraDebug && debug) {
513  cerr << "Proc " << pRowMap->getComm ()->getRank ()
514  << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
515  for (size_type k = 0; k < myNumRows; ++k) {
516  cerr << myNumEntriesPerRow[k];
517  if (k < myNumRows-1) {
518  cerr << " ";
519  }
520  }
521  cerr << "]" << endl;
522  }
523  // The total number of matrix entries that my proc owns.
524  const local_ordinal_type myNumEntries =
525  std::accumulate (myNumEntriesPerRow.begin(),
526  myNumEntriesPerRow.end(), 0);
527  if (debug) {
528  cerr << "-- Proc 0: I own " << myNumRows << " rows and "
529  << myNumEntries << " entries" << endl;
530  }
531  myColInd = arcp<GO> (myNumEntries);
532  myValues = arcp<scalar_type> (myNumEntries);
533 
534  // Copy Proc 0's part of the matrix into the my* arrays.
535  // It's important that myCurPos be updated _before_ k,
536  // otherwise myCurPos will get the wrong number of entries
537  // per row (it should be for the row in the just-completed
538  // iteration, not for the next iteration's row).
539  local_ordinal_type myCurPos = 0;
540  for (size_type k = 0; k < myNumRows;
541  myCurPos += myNumEntriesPerRow[k], ++k) {
542  const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
543  const GO myRow = myRows[k];
544  const size_t curPos = rowPtr[myRow];
545  // Only copy if there are entries to copy, in order not
546  // to construct empty ranges for the ArrayRCP views.
547  if (curNumEntries > 0) {
548  ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
549  ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
550  std::copy (colIndView.begin(), colIndView.end(),
551  myColIndView.begin());
552 
553  ArrayView<scalar_type> valuesView =
554  values (curPos, curNumEntries);
555  ArrayView<scalar_type> myValuesView =
556  myValues (myCurPos, curNumEntries);
557  std::copy (valuesView.begin(), valuesView.end(),
558  myValuesView.begin());
559  }
560  }
561 
562  // Proc 0 processes each other proc p in turn.
563  for (int p = 1; p < numProcs; ++p) {
564  if (debug) {
565  cerr << "-- Proc 0: Processing proc " << p << endl;
566  }
567 
568  size_type theirNumRows = 0;
569  // Ask Proc p how many rows it has. If it doesn't
570  // have any, we can move on to the next proc. This
571  // has to be a standard receive so that we can avoid
572  // the degenerate case of sending zero data.
573  receive (*pComm, p, &theirNumRows);
574  if (debug) {
575  cerr << "-- Proc 0: Proc " << p << " owns "
576  << theirNumRows << " rows" << endl;
577  }
578  if (theirNumRows != 0) {
579  // Ask Proc p which rows it owns. The resulting global
580  // row indices are not guaranteed to be contiguous or
581  // sorted. Global row indices are themselves indices
582  // into the numEntriesPerRow array.
583  ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
584  receive (*pComm, p, as<int> (theirNumRows),
585  theirRows.getRawPtr ());
586  // Extra test to make sure that the rows we received
587  // are all sensible. This is a good idea since we are
588  // going to use the global row indices we've received
589  // to index into the numEntriesPerRow array. Better to
590  // catch any bugs here and print a sensible error
591  // message, rather than segfault and print a cryptic
592  // error message.
593  {
594  const global_size_t numRows = pRowMap->getGlobalNumElements ();
595  const GO indexBase = pRowMap->getIndexBase ();
596  bool theirRowsValid = true;
597  for (size_type k = 0; k < theirNumRows; ++k) {
598  if (theirRows[k] < indexBase ||
599  as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
600  theirRowsValid = false;
601  }
602  }
603  if (! theirRowsValid) {
604  TEUCHOS_TEST_FOR_EXCEPTION(
605  ! theirRowsValid, std::logic_error,
606  "Proc " << p << " has at least one invalid row index. "
607  "Here are all of them: " <<
608  Teuchos::toString (theirRows ()) << ". Valid row index "
609  "range (zero-based): [0, " << (numRows - 1) << "].");
610  }
611  }
612 
613  // Perhaps we could save a little work if we check
614  // whether Proc p's row indices are contiguous. That
615  // would make lookups in the global data arrays
616  // faster. For now, we just implement the general
617  // case and don't prematurely optimize. (Remember
618  // that you're making Proc 0 read the whole file, so
619  // you've already lost scalability.)
620 
621  // Compute the number of entries in each of Proc p's
622  // rows. (Proc p will compute its row pointer array
623  // on its own, after it gets the data from Proc 0.)
624  ArrayRCP<size_t> theirNumEntriesPerRow;
625  theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
626  for (size_type k = 0; k < theirNumRows; ++k) {
627  theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
628  }
629 
630  // Tell Proc p the number of entries in each of its
631  // rows. Hopefully the cast to int doesn't overflow.
632  // This is unlikely, since it should fit in a LO,
633  // even though it is a GO.
634  send (*pComm, static_cast<int> (theirNumRows),
635  theirNumEntriesPerRow.getRawPtr(), p);
636 
637  // Figure out how many entries Proc p owns.
638  const local_ordinal_type theirNumEntries =
639  std::accumulate (theirNumEntriesPerRow.begin(),
640  theirNumEntriesPerRow.end(), 0);
641 
642  if (debug) {
643  cerr << "-- Proc 0: Proc " << p << " owns "
644  << theirNumEntries << " entries" << endl;
645  }
646 
647  // If there are no entries to send, then we're done
648  // with Proc p.
649  if (theirNumEntries == 0) {
650  continue;
651  }
652 
653  // Construct (views of) proc p's column indices and
654  // values. Later, we might like to optimize for the
655  // (common) contiguous case, for which we don't need to
656  // copy data into separate "their*" arrays (we can just
657  // use contiguous views of the global arrays).
658  ArrayRCP<GO> theirColInd (theirNumEntries);
659  ArrayRCP<scalar_type> theirValues (theirNumEntries);
660  // Copy Proc p's part of the matrix into the their*
661  // arrays. It's important that theirCurPos be updated
662  // _before_ k, otherwise theirCurPos will get the wrong
663  // number of entries per row (it should be for the row
664  // in the just-completed iteration, not for the next
665  // iteration's row).
666  local_ordinal_type theirCurPos = 0;
667  for (size_type k = 0; k < theirNumRows;
668  theirCurPos += theirNumEntriesPerRow[k], k++) {
669  const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
670  const GO theirRow = theirRows[k];
671  const local_ordinal_type curPos = rowPtr[theirRow];
672 
673  // Only copy if there are entries to copy, in order
674  // not to construct empty ranges for the ArrayRCP
675  // views.
676  if (curNumEntries > 0) {
677  ArrayView<GO> colIndView =
678  colInd (curPos, curNumEntries);
679  ArrayView<GO> theirColIndView =
680  theirColInd (theirCurPos, curNumEntries);
681  std::copy (colIndView.begin(), colIndView.end(),
682  theirColIndView.begin());
683 
684  ArrayView<scalar_type> valuesView =
685  values (curPos, curNumEntries);
686  ArrayView<scalar_type> theirValuesView =
687  theirValues (theirCurPos, curNumEntries);
688  std::copy (valuesView.begin(), valuesView.end(),
689  theirValuesView.begin());
690  }
691  }
692  // Send Proc p its column indices and values.
693  // Hopefully the cast to int doesn't overflow. This
694  // is unlikely, since it should fit in a LO, even
695  // though it is a GO.
696  send (*pComm, static_cast<int> (theirNumEntries),
697  theirColInd.getRawPtr(), p);
698  send (*pComm, static_cast<int> (theirNumEntries),
699  theirValues.getRawPtr(), p);
700 
701  if (debug) {
702  cerr << "-- Proc 0: Finished with proc " << p << endl;
703  }
704  } // If proc p owns at least one row
705  } // For each proc p not the root proc 0
706  } // If I'm (not) the root proc 0
707 
708  // Invalidate the input data to save space, since we don't
709  // need it anymore.
710  numEntriesPerRow = null;
711  rowPtr = null;
712  colInd = null;
713  values = null;
714 
715  if (debug && myRank == 0) {
716  cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
717  }
718 
719  // Allocate and fill in myRowPtr (the row pointer array for
720  // my rank's rows). We delay this until the end because we
721  // don't need it to compute anything else in distribute().
722  // Each proc can do this work for itself, since it only needs
723  // myNumEntriesPerRow to do so.
724  myRowPtr = arcp<size_t> (myNumRows+1);
725  myRowPtr[0] = 0;
726  for (size_type k = 1; k < myNumRows+1; ++k) {
727  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
728  }
729  if (extraDebug && debug) {
730  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
731  << ": myRowPtr[0.." << myNumRows << "] = [";
732  for (size_type k = 0; k < myNumRows+1; ++k) {
733  cerr << myRowPtr[k];
734  if (k < myNumRows) {
735  cerr << " ";
736  }
737  }
738  cerr << "]" << endl << endl;
739  }
740 
741  if (debug && myRank == 0) {
742  cerr << "-- Proc 0: Done with distribute" << endl;
743  }
744  }
745 
759  static Teuchos::RCP<sparse_matrix_type>
760  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
761  Teuchos::ArrayRCP<size_t>& myRowPtr,
762  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
763  Teuchos::ArrayRCP<scalar_type>& myValues,
764  const Teuchos::RCP<const map_type>& pRowMap,
765  const Teuchos::RCP<const map_type>& pRangeMap,
766  const Teuchos::RCP<const map_type>& pDomainMap,
767  const bool callFillComplete = true)
768  {
769  using Teuchos::ArrayView;
770  using Teuchos::null;
771  using Teuchos::RCP;
772  using Teuchos::rcp;
773  using std::cerr;
774  using std::endl;
775  // Typedef to make certain type declarations shorter.
776  typedef global_ordinal_type GO;
777 
778  // The row pointer array always has at least one entry, even
779  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
780  // and myValues would all be empty arrays in that degenerate
781  // case, but the row and domain maps would still be nonnull
782  // (though they would be trivial maps).
783  TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
784  "makeMatrix: myRowPtr array is null. "
785  "Please report this bug to the Tpetra developers.");
786  TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
787  "makeMatrix: domain map is null. "
788  "Please report this bug to the Tpetra developers.");
789  TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
790  "makeMatrix: range map is null. "
791  "Please report this bug to the Tpetra developers.");
792  TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
793  "makeMatrix: row map is null. "
794  "Please report this bug to the Tpetra developers.");
795 
796  // Construct the CrsMatrix, using the row map, with the
797  // constructor specifying the number of nonzeros for each row.
798  RCP<sparse_matrix_type> A =
799  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow (),
800  StaticProfile));
801 
802  // List of the global indices of my rows.
803  // They may or may not be contiguous.
804  ArrayView<const GO> myRows = pRowMap->getNodeElementList ();
805  const size_type myNumRows = myRows.size ();
806 
807  // Add this processor's matrix entries to the CrsMatrix.
808  const GO indexBase = pRowMap->getIndexBase ();
809  for (size_type i = 0; i < myNumRows; ++i) {
810  const size_type myCurPos = myRowPtr[i];
811  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
812  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
813  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
814 
815  // Modify the column indices in place to have the right index base.
816  for (size_type k = 0; k < curNumEntries; ++k) {
817  curColInd[k] += indexBase;
818  }
819  // Avoid constructing empty views of ArrayRCP objects.
820  if (curNumEntries > 0) {
821  A->insertGlobalValues (myRows[i], curColInd, curValues);
822  }
823  }
824  // We've entered in all our matrix entries, so we can delete
825  // the original data. This will save memory when we call
826  // fillComplete(), so that we never keep more than two copies
827  // of the matrix's data in memory at once.
828  myNumEntriesPerRow = null;
829  myRowPtr = null;
830  myColInd = null;
831  myValues = null;
832 
833  if (callFillComplete) {
834  A->fillComplete (pDomainMap, pRangeMap);
835  }
836  return A;
837  }
838 
844  static Teuchos::RCP<sparse_matrix_type>
845  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
846  Teuchos::ArrayRCP<size_t>& myRowPtr,
847  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
848  Teuchos::ArrayRCP<scalar_type>& myValues,
849  const Teuchos::RCP<const map_type>& pRowMap,
850  const Teuchos::RCP<const map_type>& pRangeMap,
851  const Teuchos::RCP<const map_type>& pDomainMap,
852  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
853  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
854  {
855  using Teuchos::ArrayView;
856  using Teuchos::null;
857  using Teuchos::RCP;
858  using Teuchos::rcp;
859  using std::cerr;
860  using std::endl;
861  // Typedef to make certain type declarations shorter.
862  typedef global_ordinal_type GO;
863 
864  // The row pointer array always has at least one entry, even
865  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
866  // and myValues would all be empty arrays in that degenerate
867  // case, but the row and domain maps would still be nonnull
868  // (though they would be trivial maps).
869  TEUCHOS_TEST_FOR_EXCEPTION(
870  myRowPtr.is_null(), std::logic_error,
871  "makeMatrix: myRowPtr array is null. "
872  "Please report this bug to the Tpetra developers.");
873  TEUCHOS_TEST_FOR_EXCEPTION(
874  pDomainMap.is_null(), std::logic_error,
875  "makeMatrix: domain map is null. "
876  "Please report this bug to the Tpetra developers.");
877  TEUCHOS_TEST_FOR_EXCEPTION(
878  pRangeMap.is_null(), std::logic_error,
879  "makeMatrix: range map is null. "
880  "Please report this bug to the Tpetra developers.");
881  TEUCHOS_TEST_FOR_EXCEPTION(
882  pRowMap.is_null(), std::logic_error,
883  "makeMatrix: row map is null. "
884  "Please report this bug to the Tpetra developers.");
885 
886  // Construct the CrsMatrix, using the row map, with the
887  // constructor specifying the number of nonzeros for each row.
888  RCP<sparse_matrix_type> A =
889  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
890  StaticProfile, constructorParams));
891 
892  // List of the global indices of my rows.
893  // They may or may not be contiguous.
894  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
895  const size_type myNumRows = myRows.size();
896 
897  // Add this processor's matrix entries to the CrsMatrix.
898  const GO indexBase = pRowMap->getIndexBase ();
899  for (size_type i = 0; i < myNumRows; ++i) {
900  const size_type myCurPos = myRowPtr[i];
901  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
902  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
903  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
904 
905  // Modify the column indices in place to have the right index base.
906  for (size_type k = 0; k < curNumEntries; ++k) {
907  curColInd[k] += indexBase;
908  }
909  if (curNumEntries > 0) {
910  A->insertGlobalValues (myRows[i], curColInd, curValues);
911  }
912  }
913  // We've entered in all our matrix entries, so we can delete
914  // the original data. This will save memory when we call
915  // fillComplete(), so that we never keep more than two copies
916  // of the matrix's data in memory at once.
917  myNumEntriesPerRow = null;
918  myRowPtr = null;
919  myColInd = null;
920  myValues = null;
921 
922  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
923  return A;
924  }
925 
930  static Teuchos::RCP<sparse_matrix_type>
931  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
932  Teuchos::ArrayRCP<size_t>& myRowPtr,
933  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
934  Teuchos::ArrayRCP<scalar_type>& myValues,
935  const Teuchos::RCP<const map_type>& rowMap,
936  Teuchos::RCP<const map_type>& colMap,
937  const Teuchos::RCP<const map_type>& domainMap,
938  const Teuchos::RCP<const map_type>& rangeMap,
939  const bool callFillComplete = true)
940  {
941  using Teuchos::ArrayView;
942  using Teuchos::as;
943  using Teuchos::null;
944  using Teuchos::RCP;
945  using Teuchos::rcp;
946  typedef global_ordinal_type GO;
947 
948  // Construct the CrsMatrix.
949 
950  RCP<sparse_matrix_type> A; // the matrix to return.
951  if (colMap.is_null ()) { // the user didn't provide a column Map
952  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow, StaticProfile));
953  } else { // the user provided a column Map
954  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow, StaticProfile));
955  }
956 
957  // List of the global indices of my rows.
958  // They may or may not be contiguous.
959  ArrayView<const GO> myRows = rowMap->getNodeElementList ();
960  const size_type myNumRows = myRows.size ();
961 
962  // Add this process' matrix entries to the CrsMatrix.
963  const GO indexBase = rowMap->getIndexBase ();
964  for (size_type i = 0; i < myNumRows; ++i) {
965  const size_type myCurPos = myRowPtr[i];
966  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
967  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
968  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
969 
970  // Modify the column indices in place to have the right index base.
971  for (size_type k = 0; k < curNumEntries; ++k) {
972  curColInd[k] += indexBase;
973  }
974  if (curNumEntries > 0) {
975  A->insertGlobalValues (myRows[i], curColInd, curValues);
976  }
977  }
978  // We've entered in all our matrix entries, so we can delete
979  // the original data. This will save memory when we call
980  // fillComplete(), so that we never keep more than two copies
981  // of the matrix's data in memory at once.
982  myNumEntriesPerRow = null;
983  myRowPtr = null;
984  myColInd = null;
985  myValues = null;
986 
987  if (callFillComplete) {
988  A->fillComplete (domainMap, rangeMap);
989  if (colMap.is_null ()) {
990  colMap = A->getColMap ();
991  }
992  }
993  return A;
994  }
995 
996  private:
997 
1014  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1015  readBanner (std::istream& in,
1016  size_t& lineNumber,
1017  const bool tolerant=false,
1018  const bool /* debug */=false,
1019  const bool isGraph=false)
1020  {
1021  using Teuchos::MatrixMarket::Banner;
1022  using Teuchos::RCP;
1023  using Teuchos::rcp;
1024  using std::cerr;
1025  using std::endl;
1026  typedef Teuchos::ScalarTraits<scalar_type> STS;
1027 
1028  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1029  std::string line; // If read from stream successful: the Banner line
1030 
1031  // Try to read a line from the input stream.
1032  const bool readFailed = ! getline(in, line);
1033  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1034  "Failed to get Matrix Market banner line from input.");
1035 
1036  // We read a line from the input stream.
1037  lineNumber++;
1038 
1039  // Assume that the line we found is the Banner line.
1040  try {
1041  pBanner = rcp (new Banner (line, tolerant));
1042  } catch (std::exception& e) {
1043  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1044  "Matrix Market banner line contains syntax error(s): "
1045  << e.what());
1046  }
1047  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1048  std::invalid_argument, "The Matrix Market file does not contain "
1049  "matrix data. Its Banner (first) line says that its object type is \""
1050  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1051 
1052  // Validate the data type of the matrix, with respect to the
1053  // Scalar type of the CrsMatrix entries.
1054  TEUCHOS_TEST_FOR_EXCEPTION(
1055  ! STS::isComplex && pBanner->dataType() == "complex",
1056  std::invalid_argument,
1057  "The Matrix Market file contains complex-valued data, but you are "
1058  "trying to read it into a matrix containing entries of the real-"
1059  "valued Scalar type \""
1060  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1061  TEUCHOS_TEST_FOR_EXCEPTION(
1062  !isGraph &&
1063  pBanner->dataType() != "real" &&
1064  pBanner->dataType() != "complex" &&
1065  pBanner->dataType() != "integer",
1066  std::invalid_argument,
1067  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1068  "Matrix Market file may not contain a \"pattern\" matrix. A "
1069  "pattern matrix is really just a graph with no weights. It "
1070  "should be stored in a CrsGraph, not a CrsMatrix.");
1071 
1072  TEUCHOS_TEST_FOR_EXCEPTION(
1073  isGraph &&
1074  pBanner->dataType() != "pattern",
1075  std::invalid_argument,
1076  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1077  "Matrix Market file must contain a \"pattern\" matrix.");
1078 
1079  return pBanner;
1080  }
1081 
1104  static Teuchos::Tuple<global_ordinal_type, 3>
1105  readCoordDims (std::istream& in,
1106  size_t& lineNumber,
1107  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1108  const Teuchos::RCP<const comm_type>& pComm,
1109  const bool tolerant = false,
1110  const bool /* debug */ = false)
1111  {
1112  using Teuchos::MatrixMarket::readCoordinateDimensions;
1113  using Teuchos::Tuple;
1114 
1115  // Packed coordinate matrix dimensions (numRows, numCols,
1116  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1117  // ranks.
1118  Tuple<global_ordinal_type, 3> dims;
1119 
1120  // Read in the coordinate matrix dimensions from the input
1121  // stream. "success" tells us whether reading in the
1122  // coordinate matrix dimensions succeeded ("Guilty unless
1123  // proven innocent").
1124  bool success = false;
1125  if (pComm->getRank() == 0) {
1126  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1127  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1128  "only accepts \"coordinate\" (sparse) matrix data.");
1129  // Unpacked coordinate matrix dimensions
1130  global_ordinal_type numRows, numCols, numNonzeros;
1131  // Only MPI Rank 0 reads from the input stream
1132  success = readCoordinateDimensions (in, numRows, numCols,
1133  numNonzeros, lineNumber,
1134  tolerant);
1135  // Pack up the data into a Tuple so we can send them with
1136  // one broadcast instead of three.
1137  dims[0] = numRows;
1138  dims[1] = numCols;
1139  dims[2] = numNonzeros;
1140  }
1141  // Only Rank 0 did the reading, so it decides success.
1142  //
1143  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1144  // to send bools. For now, we convert to/from int instead,
1145  // using the usual "true is 1, false is 0" encoding.
1146  {
1147  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1148  Teuchos::broadcast (*pComm, 0, &the_success);
1149  success = (the_success == 1);
1150  }
1151  if (success) {
1152  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1153  // to all the other MPI ranks.
1154  Teuchos::broadcast (*pComm, 0, dims);
1155  }
1156  else {
1157  // Perhaps in tolerant mode, we could set all the
1158  // dimensions to zero for now, and deduce correct
1159  // dimensions by reading all of the file's entries and
1160  // computing the max(row index) and max(column index).
1161  // However, for now we just error out in that case.
1162  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1163  "Error reading Matrix Market sparse matrix: failed to read "
1164  "coordinate matrix dimensions.");
1165  }
1166  return dims;
1167  }
1168 
1179  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1180 
1181  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1182 
1208  static Teuchos::RCP<adder_type>
1209  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1210  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1211  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1212  const bool tolerant=false,
1213  const bool debug=false)
1214  {
1215  if (pComm->getRank () == 0) {
1216  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1218  raw_adder_type;
1219  Teuchos::RCP<raw_adder_type> pRaw =
1220  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1221  tolerant, debug));
1222  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1223  }
1224  else {
1225  return Teuchos::null;
1226  }
1227  }
1228 
1254  static Teuchos::RCP<graph_adder_type>
1255  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1256  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1257  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1258  const bool tolerant=false,
1259  const bool debug=false)
1260  {
1261  if (pComm->getRank () == 0) {
1262  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1263  Teuchos::RCP<raw_adder_type> pRaw =
1264  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1265  tolerant, debug));
1266  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1267  }
1268  else {
1269  return Teuchos::null;
1270  }
1271  }
1272 
1274  static Teuchos::RCP<sparse_graph_type>
1275  readSparseGraphHelper (std::istream& in,
1276  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1277  const Teuchos::RCP<const map_type>& rowMap,
1278  Teuchos::RCP<const map_type>& colMap,
1279  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1280  const bool tolerant,
1281  const bool debug)
1282  {
1283  using Teuchos::MatrixMarket::Banner;
1284  using Teuchos::RCP;
1285  using Teuchos::ptr;
1286  using Teuchos::Tuple;
1287  using std::cerr;
1288  using std::endl;
1289 
1290  const int myRank = pComm->getRank ();
1291  const int rootRank = 0;
1292 
1293  // Current line number in the input stream. Various calls
1294  // will modify this depending on the number of lines that are
1295  // read from the input stream. Only Rank 0 modifies this.
1296  size_t lineNumber = 1;
1297 
1298  if (debug && myRank == rootRank) {
1299  cerr << "Matrix Market reader: readGraph:" << endl
1300  << "-- Reading banner line" << endl;
1301  }
1302 
1303  // The "Banner" tells you whether the input stream represents
1304  // a sparse matrix, the symmetry type of the matrix, and the
1305  // type of the data it contains.
1306  //
1307  // pBanner will only be nonnull on MPI Rank 0. It will be
1308  // null on all other MPI processes.
1309  RCP<const Banner> pBanner;
1310  {
1311  // We read and validate the Banner on Proc 0, but broadcast
1312  // the validation result to all processes.
1313  // Teuchos::broadcast doesn't currently work with bool, so
1314  // we use int (true -> 1, false -> 0).
1315  int bannerIsCorrect = 1;
1316  std::ostringstream errMsg;
1317 
1318  if (myRank == rootRank) {
1319  // Read the Banner line from the input stream.
1320  try {
1321  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1322  }
1323  catch (std::exception& e) {
1324  errMsg << "Attempt to read the Matrix Market file's Banner line "
1325  "threw an exception: " << e.what();
1326  bannerIsCorrect = 0;
1327  }
1328 
1329  if (bannerIsCorrect) {
1330  // Validate the Banner for the case of a sparse graph.
1331  // We validate on Proc 0, since it reads the Banner.
1332 
1333  // In intolerant mode, the matrix type must be "coordinate".
1334  if (! tolerant && pBanner->matrixType() != "coordinate") {
1335  bannerIsCorrect = 0;
1336  errMsg << "The Matrix Market input file must contain a "
1337  "\"coordinate\"-format sparse graph in order to create a "
1338  "Tpetra::CrsGraph object from it, but the file's matrix "
1339  "type is \"" << pBanner->matrixType() << "\" instead.";
1340  }
1341  // In tolerant mode, we allow the matrix type to be
1342  // anything other than "array" (which would mean that
1343  // the file contains a dense matrix).
1344  if (tolerant && pBanner->matrixType() == "array") {
1345  bannerIsCorrect = 0;
1346  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1347  "format sparse graph in order to create a Tpetra::CrsGraph "
1348  "object from it, but the file's matrix type is \"array\" "
1349  "instead. That probably means the file contains dense matrix "
1350  "data.";
1351  }
1352  }
1353  } // Proc 0: Done reading the Banner, hopefully successfully.
1354 
1355  // Broadcast from Proc 0 whether the Banner was read correctly.
1356  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1357 
1358  // If the Banner is invalid, all processes throw an
1359  // exception. Only Proc 0 gets the exception message, but
1360  // that's OK, since the main point is to "stop the world"
1361  // (rather than throw an exception on one process and leave
1362  // the others hanging).
1363  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1364  std::invalid_argument, errMsg.str ());
1365  } // Done reading the Banner line and broadcasting success.
1366  if (debug && myRank == rootRank) {
1367  cerr << "-- Reading dimensions line" << endl;
1368  }
1369 
1370  // Read the graph dimensions from the Matrix Market metadata.
1371  // dims = (numRows, numCols, numEntries). Proc 0 does the
1372  // reading, but it broadcasts the results to all MPI
1373  // processes. Thus, readCoordDims() is a collective
1374  // operation. It does a collective check for correctness too.
1375  Tuple<global_ordinal_type, 3> dims =
1376  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1377 
1378  if (debug && myRank == rootRank) {
1379  cerr << "-- Making Adder for collecting graph data" << endl;
1380  }
1381 
1382  // "Adder" object for collecting all the sparse graph entries
1383  // from the input stream. This is only nonnull on Proc 0.
1384  // The Adder internally converts the one-based indices (native
1385  // Matrix Market format) into zero-based indices.
1386  RCP<graph_adder_type> pAdder =
1387  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1388 
1389  if (debug && myRank == rootRank) {
1390  cerr << "-- Reading graph data" << endl;
1391  }
1392  //
1393  // Read the graph entries from the input stream on Proc 0.
1394  //
1395  {
1396  // We use readSuccess to broadcast the results of the read
1397  // (succeeded or not) to all MPI processes. Since
1398  // Teuchos::broadcast doesn't currently know how to send
1399  // bools, we convert to int (true -> 1, false -> 0).
1400  int readSuccess = 1;
1401  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1402  if (myRank == rootRank) {
1403  try {
1404  // Reader for "coordinate" format sparse graph data.
1405  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1406  global_ordinal_type> reader_type;
1407  reader_type reader (pAdder);
1408 
1409  // Read the sparse graph entries.
1410  std::pair<bool, std::vector<size_t> > results =
1411  reader.read (in, lineNumber, tolerant, debug);
1412  readSuccess = results.first ? 1 : 0;
1413  }
1414  catch (std::exception& e) {
1415  readSuccess = 0;
1416  errMsg << e.what();
1417  }
1418  }
1419  broadcast (*pComm, rootRank, ptr (&readSuccess));
1420 
1421  // It would be nice to add a "verbose" flag, so that in
1422  // tolerant mode, we could log any bad line number(s) on
1423  // Proc 0. For now, we just throw if the read fails to
1424  // succeed.
1425  //
1426  // Question: If we're in tolerant mode, and if the read did
1427  // not succeed, should we attempt to call fillComplete()?
1428  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1429  "Failed to read the Matrix Market sparse graph file: "
1430  << errMsg.str());
1431  } // Done reading the graph entries (stored on Proc 0 for now)
1432 
1433  if (debug && myRank == rootRank) {
1434  cerr << "-- Successfully read the Matrix Market data" << endl;
1435  }
1436 
1437  // In tolerant mode, we need to rebroadcast the graph
1438  // dimensions, since they may be different after reading the
1439  // actual graph data. We only need to broadcast the number
1440  // of rows and columns. Only Rank 0 needs to know the actual
1441  // global number of entries, since (a) we need to merge
1442  // duplicates on Rank 0 first anyway, and (b) when we
1443  // distribute the entries, each rank other than Rank 0 will
1444  // only need to know how many entries it owns, not the total
1445  // number of entries.
1446  if (tolerant) {
1447  if (debug && myRank == rootRank) {
1448  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1449  << endl
1450  << "----- Dimensions before: "
1451  << dims[0] << " x " << dims[1]
1452  << endl;
1453  }
1454  // Packed coordinate graph dimensions (numRows, numCols).
1455  Tuple<global_ordinal_type, 2> updatedDims;
1456  if (myRank == rootRank) {
1457  // If one or more bottom rows of the graph contain no
1458  // entries, then the Adder will report that the number
1459  // of rows is less than that specified in the
1460  // metadata. We allow this case, and favor the
1461  // metadata so that the zero row(s) will be included.
1462  updatedDims[0] =
1463  std::max (dims[0], pAdder->getAdder()->numRows());
1464  updatedDims[1] = pAdder->getAdder()->numCols();
1465  }
1466  broadcast (*pComm, rootRank, updatedDims);
1467  dims[0] = updatedDims[0];
1468  dims[1] = updatedDims[1];
1469  if (debug && myRank == rootRank) {
1470  cerr << "----- Dimensions after: " << dims[0] << " x "
1471  << dims[1] << endl;
1472  }
1473  }
1474  else {
1475  // In strict mode, we require that the graph's metadata and
1476  // its actual data agree, at least somewhat. In particular,
1477  // the number of rows must agree, since otherwise we cannot
1478  // distribute the graph correctly.
1479 
1480  // Teuchos::broadcast() doesn't know how to broadcast bools,
1481  // so we use an int with the standard 1 == true, 0 == false
1482  // encoding.
1483  int dimsMatch = 1;
1484  if (myRank == rootRank) {
1485  // If one or more bottom rows of the graph contain no
1486  // entries, then the Adder will report that the number of
1487  // rows is less than that specified in the metadata. We
1488  // allow this case, and favor the metadata, but do not
1489  // allow the Adder to think there are more rows in the
1490  // graph than the metadata says.
1491  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1492  dimsMatch = 0;
1493  }
1494  }
1495  broadcast (*pComm, 0, ptr (&dimsMatch));
1496  if (dimsMatch == 0) {
1497  // We're in an error state anyway, so we might as well
1498  // work a little harder to print an informative error
1499  // message.
1500  //
1501  // Broadcast the Adder's idea of the graph dimensions
1502  // from Proc 0 to all processes.
1503  Tuple<global_ordinal_type, 2> addersDims;
1504  if (myRank == rootRank) {
1505  addersDims[0] = pAdder->getAdder()->numRows();
1506  addersDims[1] = pAdder->getAdder()->numCols();
1507  }
1508  broadcast (*pComm, 0, addersDims);
1509  TEUCHOS_TEST_FOR_EXCEPTION(
1510  dimsMatch == 0, std::runtime_error,
1511  "The graph metadata says that the graph is " << dims[0] << " x "
1512  << dims[1] << ", but the actual data says that the graph is "
1513  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1514  "data includes more rows than reported in the metadata. This "
1515  "is not allowed when parsing in strict mode. Parse the graph in "
1516  "tolerant mode to ignore the metadata when it disagrees with the "
1517  "data.");
1518  }
1519  } // Matrix dimensions (# rows, # cols, # entries) agree.
1520 
1521  // Create a map describing a distribution where the root owns EVERYTHING
1522  RCP<map_type> proc0Map;
1523  global_ordinal_type indexBase;
1524  if(Teuchos::is_null(rowMap)) {
1525  indexBase = 0;
1526  }
1527  else {
1528  indexBase = rowMap->getIndexBase();
1529  }
1530  if(myRank == rootRank) {
1531  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1532  }
1533  else {
1534  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1535  }
1536 
1537  // Create the graph where the root owns EVERYTHING
1538  std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1539  if (myRank == rootRank) {
1540  const auto& entries = pAdder()->getAdder()->getEntries();
1541  // This will count duplicates, but it's better than dense.
1542  // An even better approach would use a classic algorithm,
1543  // likely in Saad's old textbook, for converting COO (entries)
1544  // to CSR (the local part of the sparse matrix data structure).
1545  for (const auto& entry : entries) {
1546  const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1547  ++numEntriesPerRow_map[gblRow];
1548  }
1549  }
1550 
1551  Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getNodeNumElements ());
1552  for (const auto& ent : numEntriesPerRow_map) {
1553  const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1554  numEntriesPerRow[lclRow] = ent.second;
1555  }
1556  // Free anything we don't need before allocating the graph.
1557  // Swapping with an empty data structure is the standard idiom
1558  // for freeing memory used by Standard Library containers.
1559  // (Just resizing to 0 doesn't promise to free memory.)
1560  {
1561  std::map<global_ordinal_type, size_t> empty_map;
1562  std::swap (numEntriesPerRow_map, empty_map);
1563  }
1564 
1565  RCP<sparse_graph_type> proc0Graph =
1566  rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1567  StaticProfile,constructorParams));
1568  if(myRank == rootRank) {
1569  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1570 
1571  // Get the entries
1572  const std::vector<element_type>& entries =
1573  pAdder->getAdder()->getEntries();
1574 
1575  // Insert them one at a time
1576  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1577  const element_type& curEntry = entries[curPos];
1578  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1579  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1580  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1581  proc0Graph->insertGlobalIndices(curRow,colView);
1582  }
1583  }
1584  proc0Graph->fillComplete();
1585 
1586  RCP<sparse_graph_type> distGraph;
1587  if(Teuchos::is_null(rowMap))
1588  {
1589  // Create a map describing the distribution we actually want
1590  RCP<map_type> distMap =
1591  rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1592 
1593  // Create the graph with that distribution too
1594  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,StaticProfile,constructorParams));
1595 
1596  // Create an importer/exporter/vandelay to redistribute the graph
1597  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1598  import_type importer (proc0Map, distMap);
1599 
1600  // Import the data
1601  distGraph->doImport(*proc0Graph,importer,INSERT);
1602  }
1603  else {
1604  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,StaticProfile,constructorParams));
1605 
1606  // Create an importer/exporter/vandelay to redistribute the graph
1607  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1608  import_type importer (proc0Map, rowMap);
1609 
1610  // Import the data
1611  distGraph->doImport(*proc0Graph,importer,INSERT);
1612  }
1613 
1614  return distGraph;
1615  }
1616 
1617  public:
1641  static Teuchos::RCP<sparse_graph_type>
1642  readSparseGraphFile (const std::string& filename,
1643  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1644  const bool callFillComplete=true,
1645  const bool tolerant=false,
1646  const bool debug=false)
1647  {
1648  using Teuchos::broadcast;
1649  using Teuchos::outArg;
1650 
1651  // Only open the file on Process 0. Test carefully to make
1652  // sure that the file opened successfully (and broadcast that
1653  // result to all processes to prevent a hang on exception
1654  // throw), since it's a common mistake to misspell a filename.
1655  std::ifstream in;
1656  int opened = 0;
1657  if (comm->getRank () == 0) {
1658  try {
1659  in.open (filename.c_str ());
1660  opened = 1;
1661  }
1662  catch (...) {
1663  opened = 0;
1664  }
1665  }
1666  broadcast<int, int> (*comm, 0, outArg (opened));
1667  TEUCHOS_TEST_FOR_EXCEPTION
1668  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1669  "Failed to open file \"" << filename << "\" on Process 0.");
1670  return readSparseGraph (in, comm,
1671  callFillComplete,
1672  tolerant, debug);
1673  // We can rely on the destructor of the input stream to close
1674  // the file on scope exit, even if readSparseGraph() throws an
1675  // exception.
1676  }
1677 
1678 
1707  static Teuchos::RCP<sparse_graph_type>
1708  readSparseGraphFile (const std::string& filename,
1709  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1710  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1711  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1712  const bool tolerant=false,
1713  const bool debug=false)
1714  {
1715  using Teuchos::broadcast;
1716  using Teuchos::outArg;
1717 
1718  // Only open the file on Process 0. Test carefully to make
1719  // sure that the file opened successfully (and broadcast that
1720  // result to all processes to prevent a hang on exception
1721  // throw), since it's a common mistake to misspell a filename.
1722  std::ifstream in;
1723  int opened = 0;
1724  if (pComm->getRank () == 0) {
1725  try {
1726  in.open (filename.c_str ());
1727  opened = 1;
1728  }
1729  catch (...) {
1730  opened = 0;
1731  }
1732  }
1733  broadcast<int, int> (*pComm, 0, outArg (opened));
1734  TEUCHOS_TEST_FOR_EXCEPTION
1735  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1736  "Failed to open file \"" << filename << "\" on Process 0.");
1737  if (pComm->getRank () == 0) { // only open the input file on Process 0
1738  in.open (filename.c_str ());
1739  }
1740  return readSparseGraph (in, pComm,
1741  constructorParams,
1742  fillCompleteParams, tolerant, debug);
1743  // We can rely on the destructor of the input stream to close
1744  // the file on scope exit, even if readSparseGraph() throws an
1745  // exception.
1746  }
1747 
1748 
1786  static Teuchos::RCP<sparse_graph_type>
1787  readSparseGraphFile (const std::string& filename,
1788  const Teuchos::RCP<const map_type>& rowMap,
1789  Teuchos::RCP<const map_type>& colMap,
1790  const Teuchos::RCP<const map_type>& domainMap,
1791  const Teuchos::RCP<const map_type>& rangeMap,
1792  const bool callFillComplete=true,
1793  const bool tolerant=false,
1794  const bool debug=false)
1795  {
1796  using Teuchos::broadcast;
1797  using Teuchos::Comm;
1798  using Teuchos::outArg;
1799  using Teuchos::RCP;
1800 
1801  TEUCHOS_TEST_FOR_EXCEPTION
1802  (rowMap.is_null (), std::invalid_argument,
1803  "Input rowMap must be nonnull.");
1804  RCP<const Comm<int> > comm = rowMap->getComm ();
1805  if (comm.is_null ()) {
1806  // If the input communicator is null on some process, then
1807  // that process does not participate in the collective.
1808  return Teuchos::null;
1809  }
1810 
1811  // Only open the file on Process 0. Test carefully to make
1812  // sure that the file opened successfully (and broadcast that
1813  // result to all processes to prevent a hang on exception
1814  // throw), since it's a common mistake to misspell a filename.
1815  std::ifstream in;
1816  int opened = 0;
1817  if (comm->getRank () == 0) {
1818  try {
1819  in.open (filename.c_str ());
1820  opened = 1;
1821  }
1822  catch (...) {
1823  opened = 0;
1824  }
1825  }
1826  broadcast<int, int> (*comm, 0, outArg (opened));
1827  TEUCHOS_TEST_FOR_EXCEPTION
1828  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1829  "Failed to open file \"" << filename << "\" on Process 0.");
1830  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1831  callFillComplete, tolerant, debug);
1832  }
1833 
1859  static Teuchos::RCP<sparse_graph_type>
1860  readSparseGraph (std::istream& in,
1861  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1862  const bool callFillComplete=true,
1863  const bool tolerant=false,
1864  const bool debug=false)
1865  {
1866  Teuchos::RCP<const map_type> fakeRowMap;
1867  Teuchos::RCP<const map_type> fakeColMap;
1868  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1869 
1870  Teuchos::RCP<sparse_graph_type> graph =
1871  readSparseGraphHelper (in, pComm,
1872  fakeRowMap, fakeColMap,
1873  fakeCtorParams, tolerant, debug);
1874  if (callFillComplete) {
1875  graph->fillComplete ();
1876  }
1877  return graph;
1878  }
1879 
1880 
1910  static Teuchos::RCP<sparse_graph_type>
1911  readSparseGraph (std::istream& in,
1912  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1913  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1914  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1915  const bool tolerant=false,
1916  const bool debug=false)
1917  {
1918  Teuchos::RCP<const map_type> fakeRowMap;
1919  Teuchos::RCP<const map_type> fakeColMap;
1920  Teuchos::RCP<sparse_graph_type> graph =
1921  readSparseGraphHelper (in, pComm,
1922  fakeRowMap, fakeColMap,
1923  constructorParams, tolerant, debug);
1924  graph->fillComplete (fillCompleteParams);
1925  return graph;
1926  }
1927 
1928 
1969  static Teuchos::RCP<sparse_graph_type>
1970  readSparseGraph (std::istream& in,
1971  const Teuchos::RCP<const map_type>& rowMap,
1972  Teuchos::RCP<const map_type>& colMap,
1973  const Teuchos::RCP<const map_type>& domainMap,
1974  const Teuchos::RCP<const map_type>& rangeMap,
1975  const bool callFillComplete=true,
1976  const bool tolerant=false,
1977  const bool debug=false)
1978  {
1979  Teuchos::RCP<sparse_graph_type> graph =
1980  readSparseGraphHelper (in, rowMap->getComm (),
1981  rowMap, colMap, Teuchos::null, tolerant,
1982  debug);
1983  if (callFillComplete) {
1984  graph->fillComplete (domainMap, rangeMap);
1985  }
1986  return graph;
1987  }
1988 
2012  static Teuchos::RCP<sparse_matrix_type>
2013  readSparseFile (const std::string& filename,
2014  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2015  const bool callFillComplete=true,
2016  const bool tolerant=false,
2017  const bool debug=false)
2018  {
2019  const int myRank = pComm->getRank ();
2020  std::ifstream in;
2021 
2022  // Only open the file on Rank 0.
2023  if (myRank == 0) {
2024  in.open (filename.c_str ());
2025  }
2026  // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2027  // opening the file succeeded, before continuing. That will
2028  // avoid hangs if the read doesn't work. On the other hand,
2029  // readSparse could do that too, by checking the status of the
2030  // std::ostream.
2031 
2032  return readSparse (in, pComm, callFillComplete, tolerant, debug);
2033  // We can rely on the destructor of the input stream to close
2034  // the file on scope exit, even if readSparse() throws an
2035  // exception.
2036  }
2037 
2038 
2067  static Teuchos::RCP<sparse_matrix_type>
2068  readSparseFile (const std::string& filename,
2069  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2070  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2071  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2072  const bool tolerant=false,
2073  const bool debug=false)
2074  {
2075  std::ifstream in;
2076  if (pComm->getRank () == 0) { // only open on Process 0
2077  in.open (filename.c_str ());
2078  }
2079  return readSparse (in, pComm, constructorParams,
2080  fillCompleteParams, tolerant, debug);
2081  }
2082 
2083 
2121  static Teuchos::RCP<sparse_matrix_type>
2122  readSparseFile (const std::string& filename,
2123  const Teuchos::RCP<const map_type>& rowMap,
2124  Teuchos::RCP<const map_type>& colMap,
2125  const Teuchos::RCP<const map_type>& domainMap,
2126  const Teuchos::RCP<const map_type>& rangeMap,
2127  const bool callFillComplete=true,
2128  const bool tolerant=false,
2129  const bool debug=false)
2130  {
2131  using Teuchos::broadcast;
2132  using Teuchos::Comm;
2133  using Teuchos::outArg;
2134  using Teuchos::RCP;
2135 
2136  TEUCHOS_TEST_FOR_EXCEPTION(
2137  rowMap.is_null (), std::invalid_argument,
2138  "Row Map must be nonnull.");
2139 
2140  RCP<const Comm<int> > comm = rowMap->getComm ();
2141  const int myRank = comm->getRank ();
2142 
2143  // Only open the file on Process 0. Test carefully to make
2144  // sure that the file opened successfully (and broadcast that
2145  // result to all processes to prevent a hang on exception
2146  // throw), since it's a common mistake to misspell a filename.
2147  std::ifstream in;
2148  int opened = 0;
2149  if (myRank == 0) {
2150  try {
2151  in.open (filename.c_str ());
2152  opened = 1;
2153  }
2154  catch (...) {
2155  opened = 0;
2156  }
2157  }
2158  broadcast<int, int> (*comm, 0, outArg (opened));
2159  TEUCHOS_TEST_FOR_EXCEPTION(
2160  opened == 0, std::runtime_error,
2161  "readSparseFile: Failed to open file \"" << filename << "\" on "
2162  "Process 0.");
2163  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2164  callFillComplete, tolerant, debug);
2165  }
2166 
2192  static Teuchos::RCP<sparse_matrix_type>
2193  readSparse (std::istream& in,
2194  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2195  const bool callFillComplete=true,
2196  const bool tolerant=false,
2197  const bool debug=false)
2198  {
2199  using Teuchos::MatrixMarket::Banner;
2200  using Teuchos::arcp;
2201  using Teuchos::ArrayRCP;
2202  using Teuchos::broadcast;
2203  using Teuchos::null;
2204  using Teuchos::ptr;
2205  using Teuchos::RCP;
2206  using Teuchos::REDUCE_MAX;
2207  using Teuchos::reduceAll;
2208  using Teuchos::Tuple;
2209  using std::cerr;
2210  using std::endl;
2211  typedef Teuchos::ScalarTraits<scalar_type> STS;
2212 
2213  const bool extraDebug = false;
2214  const int myRank = pComm->getRank ();
2215  const int rootRank = 0;
2216 
2217  // Current line number in the input stream. Various calls
2218  // will modify this depending on the number of lines that are
2219  // read from the input stream. Only Rank 0 modifies this.
2220  size_t lineNumber = 1;
2221 
2222  if (debug && myRank == rootRank) {
2223  cerr << "Matrix Market reader: readSparse:" << endl
2224  << "-- Reading banner line" << endl;
2225  }
2226 
2227  // The "Banner" tells you whether the input stream represents
2228  // a sparse matrix, the symmetry type of the matrix, and the
2229  // type of the data it contains.
2230  //
2231  // pBanner will only be nonnull on MPI Rank 0. It will be
2232  // null on all other MPI processes.
2233  RCP<const Banner> pBanner;
2234  {
2235  // We read and validate the Banner on Proc 0, but broadcast
2236  // the validation result to all processes.
2237  // Teuchos::broadcast doesn't currently work with bool, so
2238  // we use int (true -> 1, false -> 0).
2239  int bannerIsCorrect = 1;
2240  std::ostringstream errMsg;
2241 
2242  if (myRank == rootRank) {
2243  // Read the Banner line from the input stream.
2244  try {
2245  pBanner = readBanner (in, lineNumber, tolerant, debug);
2246  }
2247  catch (std::exception& e) {
2248  errMsg << "Attempt to read the Matrix Market file's Banner line "
2249  "threw an exception: " << e.what();
2250  bannerIsCorrect = 0;
2251  }
2252 
2253  if (bannerIsCorrect) {
2254  // Validate the Banner for the case of a sparse matrix.
2255  // We validate on Proc 0, since it reads the Banner.
2256 
2257  // In intolerant mode, the matrix type must be "coordinate".
2258  if (! tolerant && pBanner->matrixType() != "coordinate") {
2259  bannerIsCorrect = 0;
2260  errMsg << "The Matrix Market input file must contain a "
2261  "\"coordinate\"-format sparse matrix in order to create a "
2262  "Tpetra::CrsMatrix object from it, but the file's matrix "
2263  "type is \"" << pBanner->matrixType() << "\" instead.";
2264  }
2265  // In tolerant mode, we allow the matrix type to be
2266  // anything other than "array" (which would mean that
2267  // the file contains a dense matrix).
2268  if (tolerant && pBanner->matrixType() == "array") {
2269  bannerIsCorrect = 0;
2270  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2271  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2272  "object from it, but the file's matrix type is \"array\" "
2273  "instead. That probably means the file contains dense matrix "
2274  "data.";
2275  }
2276  }
2277  } // Proc 0: Done reading the Banner, hopefully successfully.
2278 
2279  // Broadcast from Proc 0 whether the Banner was read correctly.
2280  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2281 
2282  // If the Banner is invalid, all processes throw an
2283  // exception. Only Proc 0 gets the exception message, but
2284  // that's OK, since the main point is to "stop the world"
2285  // (rather than throw an exception on one process and leave
2286  // the others hanging).
2287  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2288  std::invalid_argument, errMsg.str ());
2289  } // Done reading the Banner line and broadcasting success.
2290  if (debug && myRank == rootRank) {
2291  cerr << "-- Reading dimensions line" << endl;
2292  }
2293 
2294  // Read the matrix dimensions from the Matrix Market metadata.
2295  // dims = (numRows, numCols, numEntries). Proc 0 does the
2296  // reading, but it broadcasts the results to all MPI
2297  // processes. Thus, readCoordDims() is a collective
2298  // operation. It does a collective check for correctness too.
2299  Tuple<global_ordinal_type, 3> dims =
2300  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2301 
2302  if (debug && myRank == rootRank) {
2303  cerr << "-- Making Adder for collecting matrix data" << endl;
2304  }
2305 
2306  // "Adder" object for collecting all the sparse matrix entries
2307  // from the input stream. This is only nonnull on Proc 0.
2308  RCP<adder_type> pAdder =
2309  makeAdder (pComm, pBanner, dims, tolerant, debug);
2310 
2311  if (debug && myRank == rootRank) {
2312  cerr << "-- Reading matrix data" << endl;
2313  }
2314  //
2315  // Read the matrix entries from the input stream on Proc 0.
2316  //
2317  {
2318  // We use readSuccess to broadcast the results of the read
2319  // (succeeded or not) to all MPI processes. Since
2320  // Teuchos::broadcast doesn't currently know how to send
2321  // bools, we convert to int (true -> 1, false -> 0).
2322  int readSuccess = 1;
2323  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2324  if (myRank == rootRank) {
2325  try {
2326  // Reader for "coordinate" format sparse matrix data.
2327  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2328  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2329  reader_type reader (pAdder);
2330 
2331  // Read the sparse matrix entries.
2332  std::pair<bool, std::vector<size_t> > results =
2333  reader.read (in, lineNumber, tolerant, debug);
2334  readSuccess = results.first ? 1 : 0;
2335  }
2336  catch (std::exception& e) {
2337  readSuccess = 0;
2338  errMsg << e.what();
2339  }
2340  }
2341  broadcast (*pComm, rootRank, ptr (&readSuccess));
2342 
2343  // It would be nice to add a "verbose" flag, so that in
2344  // tolerant mode, we could log any bad line number(s) on
2345  // Proc 0. For now, we just throw if the read fails to
2346  // succeed.
2347  //
2348  // Question: If we're in tolerant mode, and if the read did
2349  // not succeed, should we attempt to call fillComplete()?
2350  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2351  "Failed to read the Matrix Market sparse matrix file: "
2352  << errMsg.str());
2353  } // Done reading the matrix entries (stored on Proc 0 for now)
2354 
2355  if (debug && myRank == rootRank) {
2356  cerr << "-- Successfully read the Matrix Market data" << endl;
2357  }
2358 
2359  // In tolerant mode, we need to rebroadcast the matrix
2360  // dimensions, since they may be different after reading the
2361  // actual matrix data. We only need to broadcast the number
2362  // of rows and columns. Only Rank 0 needs to know the actual
2363  // global number of entries, since (a) we need to merge
2364  // duplicates on Rank 0 first anyway, and (b) when we
2365  // distribute the entries, each rank other than Rank 0 will
2366  // only need to know how many entries it owns, not the total
2367  // number of entries.
2368  if (tolerant) {
2369  if (debug && myRank == rootRank) {
2370  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2371  << endl
2372  << "----- Dimensions before: "
2373  << dims[0] << " x " << dims[1]
2374  << endl;
2375  }
2376  // Packed coordinate matrix dimensions (numRows, numCols).
2377  Tuple<global_ordinal_type, 2> updatedDims;
2378  if (myRank == rootRank) {
2379  // If one or more bottom rows of the matrix contain no
2380  // entries, then the Adder will report that the number
2381  // of rows is less than that specified in the
2382  // metadata. We allow this case, and favor the
2383  // metadata so that the zero row(s) will be included.
2384  updatedDims[0] =
2385  std::max (dims[0], pAdder->getAdder()->numRows());
2386  updatedDims[1] = pAdder->getAdder()->numCols();
2387  }
2388  broadcast (*pComm, rootRank, updatedDims);
2389  dims[0] = updatedDims[0];
2390  dims[1] = updatedDims[1];
2391  if (debug && myRank == rootRank) {
2392  cerr << "----- Dimensions after: " << dims[0] << " x "
2393  << dims[1] << endl;
2394  }
2395  }
2396  else {
2397  // In strict mode, we require that the matrix's metadata and
2398  // its actual data agree, at least somewhat. In particular,
2399  // the number of rows must agree, since otherwise we cannot
2400  // distribute the matrix correctly.
2401 
2402  // Teuchos::broadcast() doesn't know how to broadcast bools,
2403  // so we use an int with the standard 1 == true, 0 == false
2404  // encoding.
2405  int dimsMatch = 1;
2406  if (myRank == rootRank) {
2407  // If one or more bottom rows of the matrix contain no
2408  // entries, then the Adder will report that the number of
2409  // rows is less than that specified in the metadata. We
2410  // allow this case, and favor the metadata, but do not
2411  // allow the Adder to think there are more rows in the
2412  // matrix than the metadata says.
2413  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2414  dimsMatch = 0;
2415  }
2416  }
2417  broadcast (*pComm, 0, ptr (&dimsMatch));
2418  if (dimsMatch == 0) {
2419  // We're in an error state anyway, so we might as well
2420  // work a little harder to print an informative error
2421  // message.
2422  //
2423  // Broadcast the Adder's idea of the matrix dimensions
2424  // from Proc 0 to all processes.
2425  Tuple<global_ordinal_type, 2> addersDims;
2426  if (myRank == rootRank) {
2427  addersDims[0] = pAdder->getAdder()->numRows();
2428  addersDims[1] = pAdder->getAdder()->numCols();
2429  }
2430  broadcast (*pComm, 0, addersDims);
2431  TEUCHOS_TEST_FOR_EXCEPTION(
2432  dimsMatch == 0, std::runtime_error,
2433  "The matrix metadata says that the matrix is " << dims[0] << " x "
2434  << dims[1] << ", but the actual data says that the matrix is "
2435  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2436  "data includes more rows than reported in the metadata. This "
2437  "is not allowed when parsing in strict mode. Parse the matrix in "
2438  "tolerant mode to ignore the metadata when it disagrees with the "
2439  "data.");
2440  }
2441  } // Matrix dimensions (# rows, # cols, # entries) agree.
2442 
2443  if (debug && myRank == rootRank) {
2444  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2445  }
2446 
2447  // Now that we've read in all the matrix entries from the
2448  // input stream into the adder on Proc 0, post-process them
2449  // into CSR format (still on Proc 0). This will facilitate
2450  // distributing them to all the processors.
2451  //
2452  // These arrays represent the global matrix data as a CSR
2453  // matrix (with numEntriesPerRow as redundant but convenient
2454  // metadata, since it's computable from rowPtr and vice
2455  // versa). They are valid only on Proc 0.
2456  ArrayRCP<size_t> numEntriesPerRow;
2457  ArrayRCP<size_t> rowPtr;
2458  ArrayRCP<global_ordinal_type> colInd;
2459  ArrayRCP<scalar_type> values;
2460 
2461  // Proc 0 first merges duplicate entries, and then converts
2462  // the coordinate-format matrix data to CSR.
2463  {
2464  int mergeAndConvertSucceeded = 1;
2465  std::ostringstream errMsg;
2466 
2467  if (myRank == rootRank) {
2468  try {
2469  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2470  global_ordinal_type> element_type;
2471 
2472  // Number of rows in the matrix. If we are in tolerant
2473  // mode, we've already synchronized dims with the actual
2474  // matrix data. If in strict mode, we should use dims
2475  // (as read from the file's metadata) rather than the
2476  // matrix data to determine the dimensions. (The matrix
2477  // data will claim fewer rows than the metadata, if one
2478  // or more rows have no entries stored in the file.)
2479  const size_type numRows = dims[0];
2480 
2481  // Additively merge duplicate matrix entries.
2482  pAdder->getAdder()->merge ();
2483 
2484  // Get a temporary const view of the merged matrix entries.
2485  const std::vector<element_type>& entries =
2486  pAdder->getAdder()->getEntries();
2487 
2488  // Number of matrix entries (after merging).
2489  const size_t numEntries = (size_t)entries.size();
2490 
2491  if (debug) {
2492  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2493  << " rows and numEntries=" << numEntries
2494  << " entries." << endl;
2495  }
2496 
2497  // Make space for the CSR matrix data. Converting to
2498  // CSR is easier if we fill numEntriesPerRow with zeros
2499  // at first.
2500  numEntriesPerRow = arcp<size_t> (numRows);
2501  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2502  rowPtr = arcp<size_t> (numRows+1);
2503  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2504  colInd = arcp<global_ordinal_type> (numEntries);
2505  values = arcp<scalar_type> (numEntries);
2506 
2507  // Convert from array-of-structs coordinate format to CSR
2508  // (compressed sparse row) format.
2509  global_ordinal_type prvRow = 0;
2510  size_t curPos = 0;
2511  rowPtr[0] = 0;
2512  for (curPos = 0; curPos < numEntries; ++curPos) {
2513  const element_type& curEntry = entries[curPos];
2514  const global_ordinal_type curRow = curEntry.rowIndex();
2515  TEUCHOS_TEST_FOR_EXCEPTION(
2516  curRow < prvRow, std::logic_error,
2517  "Row indices are out of order, even though they are supposed "
2518  "to be sorted. curRow = " << curRow << ", prvRow = "
2519  << prvRow << ", at curPos = " << curPos << ". Please report "
2520  "this bug to the Tpetra developers.");
2521  if (curRow > prvRow) {
2522  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2523  rowPtr[r] = curPos;
2524  }
2525  prvRow = curRow;
2526  }
2527  numEntriesPerRow[curRow]++;
2528  colInd[curPos] = curEntry.colIndex();
2529  values[curPos] = curEntry.value();
2530  }
2531  // rowPtr has one more entry than numEntriesPerRow. The
2532  // last entry of rowPtr is the number of entries in
2533  // colInd and values.
2534  rowPtr[numRows] = numEntries;
2535  } // Finished conversion to CSR format
2536  catch (std::exception& e) {
2537  mergeAndConvertSucceeded = 0;
2538  errMsg << "Failed to merge sparse matrix entries and convert to "
2539  "CSR format: " << e.what();
2540  }
2541 
2542  if (debug && mergeAndConvertSucceeded) {
2543  // Number of rows in the matrix.
2544  const size_type numRows = dims[0];
2545  const size_type maxToDisplay = 100;
2546 
2547  cerr << "----- Proc 0: numEntriesPerRow[0.."
2548  << (numEntriesPerRow.size()-1) << "] ";
2549  if (numRows > maxToDisplay) {
2550  cerr << "(only showing first and last few entries) ";
2551  }
2552  cerr << "= [";
2553  if (numRows > 0) {
2554  if (numRows > maxToDisplay) {
2555  for (size_type k = 0; k < 2; ++k) {
2556  cerr << numEntriesPerRow[k] << " ";
2557  }
2558  cerr << "... ";
2559  for (size_type k = numRows-2; k < numRows-1; ++k) {
2560  cerr << numEntriesPerRow[k] << " ";
2561  }
2562  }
2563  else {
2564  for (size_type k = 0; k < numRows-1; ++k) {
2565  cerr << numEntriesPerRow[k] << " ";
2566  }
2567  }
2568  cerr << numEntriesPerRow[numRows-1];
2569  } // numRows > 0
2570  cerr << "]" << endl;
2571 
2572  cerr << "----- Proc 0: rowPtr ";
2573  if (numRows > maxToDisplay) {
2574  cerr << "(only showing first and last few entries) ";
2575  }
2576  cerr << "= [";
2577  if (numRows > maxToDisplay) {
2578  for (size_type k = 0; k < 2; ++k) {
2579  cerr << rowPtr[k] << " ";
2580  }
2581  cerr << "... ";
2582  for (size_type k = numRows-2; k < numRows; ++k) {
2583  cerr << rowPtr[k] << " ";
2584  }
2585  }
2586  else {
2587  for (size_type k = 0; k < numRows; ++k) {
2588  cerr << rowPtr[k] << " ";
2589  }
2590  }
2591  cerr << rowPtr[numRows] << "]" << endl;
2592  }
2593  } // if myRank == rootRank
2594  } // Done converting sparse matrix data to CSR format
2595 
2596  // Now we're done with the Adder, so we can release the
2597  // reference ("free" it) to save space. This only actually
2598  // does anything on Rank 0, since pAdder is null on all the
2599  // other MPI processes.
2600  pAdder = null;
2601 
2602  if (debug && myRank == rootRank) {
2603  cerr << "-- Making range, domain, and row maps" << endl;
2604  }
2605 
2606  // Make the maps that describe the matrix's range and domain,
2607  // and the distribution of its rows. Creating a Map is a
2608  // collective operation, so we don't have to do a broadcast of
2609  // a success Boolean.
2610  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2611  RCP<const map_type> pDomainMap =
2612  makeDomainMap (pRangeMap, dims[0], dims[1]);
2613  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2614 
2615  if (debug && myRank == rootRank) {
2616  cerr << "-- Distributing the matrix data" << endl;
2617  }
2618 
2619  // Distribute the matrix data. Each processor has to add the
2620  // rows that it owns. If you try to make Proc 0 call
2621  // insertGlobalValues() for _all_ the rows, not just those it
2622  // owns, then fillComplete() will compute the number of
2623  // columns incorrectly. That's why Proc 0 has to distribute
2624  // the matrix data and why we make all the processors (not
2625  // just Proc 0) call insertGlobalValues() on their own data.
2626  //
2627  // These arrays represent each processor's part of the matrix
2628  // data, in "CSR" format (sort of, since the row indices might
2629  // not be contiguous).
2630  ArrayRCP<size_t> myNumEntriesPerRow;
2631  ArrayRCP<size_t> myRowPtr;
2632  ArrayRCP<global_ordinal_type> myColInd;
2633  ArrayRCP<scalar_type> myValues;
2634  // Distribute the matrix data. This is a collective operation.
2635  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2636  numEntriesPerRow, rowPtr, colInd, values, debug);
2637 
2638  if (debug && myRank == rootRank) {
2639  cerr << "-- Inserting matrix entries on each processor";
2640  if (callFillComplete) {
2641  cerr << " and calling fillComplete()";
2642  }
2643  cerr << endl;
2644  }
2645  // Each processor inserts its part of the matrix data, and
2646  // then they all call fillComplete(). This method invalidates
2647  // the my* distributed matrix data before calling
2648  // fillComplete(), in order to save space. In general, we
2649  // never store more than two copies of the matrix's entries in
2650  // memory at once, which is no worse than what Tpetra
2651  // promises.
2652  RCP<sparse_matrix_type> pMatrix =
2653  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2654  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2655  // Only use a reduce-all in debug mode to check if pMatrix is
2656  // null. Otherwise, just throw an exception. We never expect
2657  // a null pointer here, so we can save a communication.
2658  if (debug) {
2659  int localIsNull = pMatrix.is_null () ? 1 : 0;
2660  int globalIsNull = 0;
2661  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2662  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2663  "Reader::makeMatrix() returned a null pointer on at least one "
2664  "process. Please report this bug to the Tpetra developers.");
2665  }
2666  else {
2667  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2668  "Reader::makeMatrix() returned a null pointer. "
2669  "Please report this bug to the Tpetra developers.");
2670  }
2671 
2672  // We can't get the dimensions of the matrix until after
2673  // fillComplete() is called. Thus, we can't do the sanity
2674  // check (dimensions read from the Matrix Market data,
2675  // vs. dimensions reported by the CrsMatrix) unless the user
2676  // asked makeMatrix() to call fillComplete().
2677  //
2678  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2679  // what one might think it does, so you have to ask the range
2680  // resp. domain map for the number of rows resp. columns.
2681  if (callFillComplete) {
2682  const int numProcs = pComm->getSize ();
2683 
2684  if (extraDebug && debug) {
2685  const global_size_t globalNumRows =
2686  pRangeMap->getGlobalNumElements ();
2687  const global_size_t globalNumCols =
2688  pDomainMap->getGlobalNumElements ();
2689  if (myRank == rootRank) {
2690  cerr << "-- Matrix is "
2691  << globalNumRows << " x " << globalNumCols
2692  << " with " << pMatrix->getGlobalNumEntries()
2693  << " entries, and index base "
2694  << pMatrix->getIndexBase() << "." << endl;
2695  }
2696  pComm->barrier ();
2697  for (int p = 0; p < numProcs; ++p) {
2698  if (myRank == p) {
2699  cerr << "-- Proc " << p << " owns "
2700  << pMatrix->getNodeNumCols() << " columns, and "
2701  << pMatrix->getNodeNumEntries() << " entries." << endl;
2702  }
2703  pComm->barrier ();
2704  }
2705  } // if (extraDebug && debug)
2706  } // if (callFillComplete)
2707 
2708  if (debug && myRank == rootRank) {
2709  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2710  << endl;
2711  }
2712  return pMatrix;
2713  }
2714 
2715 
2744  static Teuchos::RCP<sparse_matrix_type>
2745  readSparse (std::istream& in,
2746  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2747  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2748  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2749  const bool tolerant=false,
2750  const bool debug=false)
2751  {
2752  using Teuchos::MatrixMarket::Banner;
2753  using Teuchos::arcp;
2754  using Teuchos::ArrayRCP;
2755  using Teuchos::broadcast;
2756  using Teuchos::null;
2757  using Teuchos::ptr;
2758  using Teuchos::RCP;
2759  using Teuchos::reduceAll;
2760  using Teuchos::Tuple;
2761  using std::cerr;
2762  using std::endl;
2763  typedef Teuchos::ScalarTraits<scalar_type> STS;
2764 
2765  const bool extraDebug = false;
2766  const int myRank = pComm->getRank ();
2767  const int rootRank = 0;
2768 
2769  // Current line number in the input stream. Various calls
2770  // will modify this depending on the number of lines that are
2771  // read from the input stream. Only Rank 0 modifies this.
2772  size_t lineNumber = 1;
2773 
2774  if (debug && myRank == rootRank) {
2775  cerr << "Matrix Market reader: readSparse:" << endl
2776  << "-- Reading banner line" << endl;
2777  }
2778 
2779  // The "Banner" tells you whether the input stream represents
2780  // a sparse matrix, the symmetry type of the matrix, and the
2781  // type of the data it contains.
2782  //
2783  // pBanner will only be nonnull on MPI Rank 0. It will be
2784  // null on all other MPI processes.
2785  RCP<const Banner> pBanner;
2786  {
2787  // We read and validate the Banner on Proc 0, but broadcast
2788  // the validation result to all processes.
2789  // Teuchos::broadcast doesn't currently work with bool, so
2790  // we use int (true -> 1, false -> 0).
2791  int bannerIsCorrect = 1;
2792  std::ostringstream errMsg;
2793 
2794  if (myRank == rootRank) {
2795  // Read the Banner line from the input stream.
2796  try {
2797  pBanner = readBanner (in, lineNumber, tolerant, debug);
2798  }
2799  catch (std::exception& e) {
2800  errMsg << "Attempt to read the Matrix Market file's Banner line "
2801  "threw an exception: " << e.what();
2802  bannerIsCorrect = 0;
2803  }
2804 
2805  if (bannerIsCorrect) {
2806  // Validate the Banner for the case of a sparse matrix.
2807  // We validate on Proc 0, since it reads the Banner.
2808 
2809  // In intolerant mode, the matrix type must be "coordinate".
2810  if (! tolerant && pBanner->matrixType() != "coordinate") {
2811  bannerIsCorrect = 0;
2812  errMsg << "The Matrix Market input file must contain a "
2813  "\"coordinate\"-format sparse matrix in order to create a "
2814  "Tpetra::CrsMatrix object from it, but the file's matrix "
2815  "type is \"" << pBanner->matrixType() << "\" instead.";
2816  }
2817  // In tolerant mode, we allow the matrix type to be
2818  // anything other than "array" (which would mean that
2819  // the file contains a dense matrix).
2820  if (tolerant && pBanner->matrixType() == "array") {
2821  bannerIsCorrect = 0;
2822  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2823  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2824  "object from it, but the file's matrix type is \"array\" "
2825  "instead. That probably means the file contains dense matrix "
2826  "data.";
2827  }
2828  }
2829  } // Proc 0: Done reading the Banner, hopefully successfully.
2830 
2831  // Broadcast from Proc 0 whether the Banner was read correctly.
2832  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2833 
2834  // If the Banner is invalid, all processes throw an
2835  // exception. Only Proc 0 gets the exception message, but
2836  // that's OK, since the main point is to "stop the world"
2837  // (rather than throw an exception on one process and leave
2838  // the others hanging).
2839  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2840  std::invalid_argument, errMsg.str ());
2841  } // Done reading the Banner line and broadcasting success.
2842  if (debug && myRank == rootRank) {
2843  cerr << "-- Reading dimensions line" << endl;
2844  }
2845 
2846  // Read the matrix dimensions from the Matrix Market metadata.
2847  // dims = (numRows, numCols, numEntries). Proc 0 does the
2848  // reading, but it broadcasts the results to all MPI
2849  // processes. Thus, readCoordDims() is a collective
2850  // operation. It does a collective check for correctness too.
2851  Tuple<global_ordinal_type, 3> dims =
2852  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2853 
2854  if (debug && myRank == rootRank) {
2855  cerr << "-- Making Adder for collecting matrix data" << endl;
2856  }
2857 
2858  // "Adder" object for collecting all the sparse matrix entries
2859  // from the input stream. This is only nonnull on Proc 0.
2860  RCP<adder_type> pAdder =
2861  makeAdder (pComm, pBanner, dims, tolerant, debug);
2862 
2863  if (debug && myRank == rootRank) {
2864  cerr << "-- Reading matrix data" << endl;
2865  }
2866  //
2867  // Read the matrix entries from the input stream on Proc 0.
2868  //
2869  {
2870  // We use readSuccess to broadcast the results of the read
2871  // (succeeded or not) to all MPI processes. Since
2872  // Teuchos::broadcast doesn't currently know how to send
2873  // bools, we convert to int (true -> 1, false -> 0).
2874  int readSuccess = 1;
2875  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2876  if (myRank == rootRank) {
2877  try {
2878  // Reader for "coordinate" format sparse matrix data.
2879  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2880  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2881  reader_type reader (pAdder);
2882 
2883  // Read the sparse matrix entries.
2884  std::pair<bool, std::vector<size_t> > results =
2885  reader.read (in, lineNumber, tolerant, debug);
2886  readSuccess = results.first ? 1 : 0;
2887  }
2888  catch (std::exception& e) {
2889  readSuccess = 0;
2890  errMsg << e.what();
2891  }
2892  }
2893  broadcast (*pComm, rootRank, ptr (&readSuccess));
2894 
2895  // It would be nice to add a "verbose" flag, so that in
2896  // tolerant mode, we could log any bad line number(s) on
2897  // Proc 0. For now, we just throw if the read fails to
2898  // succeed.
2899  //
2900  // Question: If we're in tolerant mode, and if the read did
2901  // not succeed, should we attempt to call fillComplete()?
2902  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2903  "Failed to read the Matrix Market sparse matrix file: "
2904  << errMsg.str());
2905  } // Done reading the matrix entries (stored on Proc 0 for now)
2906 
2907  if (debug && myRank == rootRank) {
2908  cerr << "-- Successfully read the Matrix Market data" << endl;
2909  }
2910 
2911  // In tolerant mode, we need to rebroadcast the matrix
2912  // dimensions, since they may be different after reading the
2913  // actual matrix data. We only need to broadcast the number
2914  // of rows and columns. Only Rank 0 needs to know the actual
2915  // global number of entries, since (a) we need to merge
2916  // duplicates on Rank 0 first anyway, and (b) when we
2917  // distribute the entries, each rank other than Rank 0 will
2918  // only need to know how many entries it owns, not the total
2919  // number of entries.
2920  if (tolerant) {
2921  if (debug && myRank == rootRank) {
2922  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2923  << endl
2924  << "----- Dimensions before: "
2925  << dims[0] << " x " << dims[1]
2926  << endl;
2927  }
2928  // Packed coordinate matrix dimensions (numRows, numCols).
2929  Tuple<global_ordinal_type, 2> updatedDims;
2930  if (myRank == rootRank) {
2931  // If one or more bottom rows of the matrix contain no
2932  // entries, then the Adder will report that the number
2933  // of rows is less than that specified in the
2934  // metadata. We allow this case, and favor the
2935  // metadata so that the zero row(s) will be included.
2936  updatedDims[0] =
2937  std::max (dims[0], pAdder->getAdder()->numRows());
2938  updatedDims[1] = pAdder->getAdder()->numCols();
2939  }
2940  broadcast (*pComm, rootRank, updatedDims);
2941  dims[0] = updatedDims[0];
2942  dims[1] = updatedDims[1];
2943  if (debug && myRank == rootRank) {
2944  cerr << "----- Dimensions after: " << dims[0] << " x "
2945  << dims[1] << endl;
2946  }
2947  }
2948  else {
2949  // In strict mode, we require that the matrix's metadata and
2950  // its actual data agree, at least somewhat. In particular,
2951  // the number of rows must agree, since otherwise we cannot
2952  // distribute the matrix correctly.
2953 
2954  // Teuchos::broadcast() doesn't know how to broadcast bools,
2955  // so we use an int with the standard 1 == true, 0 == false
2956  // encoding.
2957  int dimsMatch = 1;
2958  if (myRank == rootRank) {
2959  // If one or more bottom rows of the matrix contain no
2960  // entries, then the Adder will report that the number of
2961  // rows is less than that specified in the metadata. We
2962  // allow this case, and favor the metadata, but do not
2963  // allow the Adder to think there are more rows in the
2964  // matrix than the metadata says.
2965  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2966  dimsMatch = 0;
2967  }
2968  }
2969  broadcast (*pComm, 0, ptr (&dimsMatch));
2970  if (dimsMatch == 0) {
2971  // We're in an error state anyway, so we might as well
2972  // work a little harder to print an informative error
2973  // message.
2974  //
2975  // Broadcast the Adder's idea of the matrix dimensions
2976  // from Proc 0 to all processes.
2977  Tuple<global_ordinal_type, 2> addersDims;
2978  if (myRank == rootRank) {
2979  addersDims[0] = pAdder->getAdder()->numRows();
2980  addersDims[1] = pAdder->getAdder()->numCols();
2981  }
2982  broadcast (*pComm, 0, addersDims);
2983  TEUCHOS_TEST_FOR_EXCEPTION(
2984  dimsMatch == 0, std::runtime_error,
2985  "The matrix metadata says that the matrix is " << dims[0] << " x "
2986  << dims[1] << ", but the actual data says that the matrix is "
2987  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2988  "data includes more rows than reported in the metadata. This "
2989  "is not allowed when parsing in strict mode. Parse the matrix in "
2990  "tolerant mode to ignore the metadata when it disagrees with the "
2991  "data.");
2992  }
2993  } // Matrix dimensions (# rows, # cols, # entries) agree.
2994 
2995  if (debug && myRank == rootRank) {
2996  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2997  }
2998 
2999  // Now that we've read in all the matrix entries from the
3000  // input stream into the adder on Proc 0, post-process them
3001  // into CSR format (still on Proc 0). This will facilitate
3002  // distributing them to all the processors.
3003  //
3004  // These arrays represent the global matrix data as a CSR
3005  // matrix (with numEntriesPerRow as redundant but convenient
3006  // metadata, since it's computable from rowPtr and vice
3007  // versa). They are valid only on Proc 0.
3008  ArrayRCP<size_t> numEntriesPerRow;
3009  ArrayRCP<size_t> rowPtr;
3010  ArrayRCP<global_ordinal_type> colInd;
3011  ArrayRCP<scalar_type> values;
3012 
3013  // Proc 0 first merges duplicate entries, and then converts
3014  // the coordinate-format matrix data to CSR.
3015  {
3016  int mergeAndConvertSucceeded = 1;
3017  std::ostringstream errMsg;
3018 
3019  if (myRank == rootRank) {
3020  try {
3021  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3022  global_ordinal_type> element_type;
3023 
3024  // Number of rows in the matrix. If we are in tolerant
3025  // mode, we've already synchronized dims with the actual
3026  // matrix data. If in strict mode, we should use dims
3027  // (as read from the file's metadata) rather than the
3028  // matrix data to determine the dimensions. (The matrix
3029  // data will claim fewer rows than the metadata, if one
3030  // or more rows have no entries stored in the file.)
3031  const size_type numRows = dims[0];
3032 
3033  // Additively merge duplicate matrix entries.
3034  pAdder->getAdder()->merge ();
3035 
3036  // Get a temporary const view of the merged matrix entries.
3037  const std::vector<element_type>& entries =
3038  pAdder->getAdder()->getEntries();
3039 
3040  // Number of matrix entries (after merging).
3041  const size_t numEntries = (size_t)entries.size();
3042 
3043  if (debug) {
3044  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3045  << " rows and numEntries=" << numEntries
3046  << " entries." << endl;
3047  }
3048 
3049  // Make space for the CSR matrix data. Converting to
3050  // CSR is easier if we fill numEntriesPerRow with zeros
3051  // at first.
3052  numEntriesPerRow = arcp<size_t> (numRows);
3053  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3054  rowPtr = arcp<size_t> (numRows+1);
3055  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3056  colInd = arcp<global_ordinal_type> (numEntries);
3057  values = arcp<scalar_type> (numEntries);
3058 
3059  // Convert from array-of-structs coordinate format to CSR
3060  // (compressed sparse row) format.
3061  global_ordinal_type prvRow = 0;
3062  size_t curPos = 0;
3063  rowPtr[0] = 0;
3064  for (curPos = 0; curPos < numEntries; ++curPos) {
3065  const element_type& curEntry = entries[curPos];
3066  const global_ordinal_type curRow = curEntry.rowIndex();
3067  TEUCHOS_TEST_FOR_EXCEPTION(
3068  curRow < prvRow, std::logic_error,
3069  "Row indices are out of order, even though they are supposed "
3070  "to be sorted. curRow = " << curRow << ", prvRow = "
3071  << prvRow << ", at curPos = " << curPos << ". Please report "
3072  "this bug to the Tpetra developers.");
3073  if (curRow > prvRow) {
3074  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3075  rowPtr[r] = curPos;
3076  }
3077  prvRow = curRow;
3078  }
3079  numEntriesPerRow[curRow]++;
3080  colInd[curPos] = curEntry.colIndex();
3081  values[curPos] = curEntry.value();
3082  }
3083  // rowPtr has one more entry than numEntriesPerRow. The
3084  // last entry of rowPtr is the number of entries in
3085  // colInd and values.
3086  rowPtr[numRows] = numEntries;
3087  } // Finished conversion to CSR format
3088  catch (std::exception& e) {
3089  mergeAndConvertSucceeded = 0;
3090  errMsg << "Failed to merge sparse matrix entries and convert to "
3091  "CSR format: " << e.what();
3092  }
3093 
3094  if (debug && mergeAndConvertSucceeded) {
3095  // Number of rows in the matrix.
3096  const size_type numRows = dims[0];
3097  const size_type maxToDisplay = 100;
3098 
3099  cerr << "----- Proc 0: numEntriesPerRow[0.."
3100  << (numEntriesPerRow.size()-1) << "] ";
3101  if (numRows > maxToDisplay) {
3102  cerr << "(only showing first and last few entries) ";
3103  }
3104  cerr << "= [";
3105  if (numRows > 0) {
3106  if (numRows > maxToDisplay) {
3107  for (size_type k = 0; k < 2; ++k) {
3108  cerr << numEntriesPerRow[k] << " ";
3109  }
3110  cerr << "... ";
3111  for (size_type k = numRows-2; k < numRows-1; ++k) {
3112  cerr << numEntriesPerRow[k] << " ";
3113  }
3114  }
3115  else {
3116  for (size_type k = 0; k < numRows-1; ++k) {
3117  cerr << numEntriesPerRow[k] << " ";
3118  }
3119  }
3120  cerr << numEntriesPerRow[numRows-1];
3121  } // numRows > 0
3122  cerr << "]" << endl;
3123 
3124  cerr << "----- Proc 0: rowPtr ";
3125  if (numRows > maxToDisplay) {
3126  cerr << "(only showing first and last few entries) ";
3127  }
3128  cerr << "= [";
3129  if (numRows > maxToDisplay) {
3130  for (size_type k = 0; k < 2; ++k) {
3131  cerr << rowPtr[k] << " ";
3132  }
3133  cerr << "... ";
3134  for (size_type k = numRows-2; k < numRows; ++k) {
3135  cerr << rowPtr[k] << " ";
3136  }
3137  }
3138  else {
3139  for (size_type k = 0; k < numRows; ++k) {
3140  cerr << rowPtr[k] << " ";
3141  }
3142  }
3143  cerr << rowPtr[numRows] << "]" << endl;
3144  }
3145  } // if myRank == rootRank
3146  } // Done converting sparse matrix data to CSR format
3147 
3148  // Now we're done with the Adder, so we can release the
3149  // reference ("free" it) to save space. This only actually
3150  // does anything on Rank 0, since pAdder is null on all the
3151  // other MPI processes.
3152  pAdder = null;
3153 
3154  if (debug && myRank == rootRank) {
3155  cerr << "-- Making range, domain, and row maps" << endl;
3156  }
3157 
3158  // Make the maps that describe the matrix's range and domain,
3159  // and the distribution of its rows. Creating a Map is a
3160  // collective operation, so we don't have to do a broadcast of
3161  // a success Boolean.
3162  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3163  RCP<const map_type> pDomainMap =
3164  makeDomainMap (pRangeMap, dims[0], dims[1]);
3165  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3166 
3167  if (debug && myRank == rootRank) {
3168  cerr << "-- Distributing the matrix data" << endl;
3169  }
3170 
3171  // Distribute the matrix data. Each processor has to add the
3172  // rows that it owns. If you try to make Proc 0 call
3173  // insertGlobalValues() for _all_ the rows, not just those it
3174  // owns, then fillComplete() will compute the number of
3175  // columns incorrectly. That's why Proc 0 has to distribute
3176  // the matrix data and why we make all the processors (not
3177  // just Proc 0) call insertGlobalValues() on their own data.
3178  //
3179  // These arrays represent each processor's part of the matrix
3180  // data, in "CSR" format (sort of, since the row indices might
3181  // not be contiguous).
3182  ArrayRCP<size_t> myNumEntriesPerRow;
3183  ArrayRCP<size_t> myRowPtr;
3184  ArrayRCP<global_ordinal_type> myColInd;
3185  ArrayRCP<scalar_type> myValues;
3186  // Distribute the matrix data. This is a collective operation.
3187  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3188  numEntriesPerRow, rowPtr, colInd, values, debug);
3189 
3190  if (debug && myRank == rootRank) {
3191  cerr << "-- Inserting matrix entries on each process "
3192  "and calling fillComplete()" << endl;
3193  }
3194  // Each processor inserts its part of the matrix data, and
3195  // then they all call fillComplete(). This method invalidates
3196  // the my* distributed matrix data before calling
3197  // fillComplete(), in order to save space. In general, we
3198  // never store more than two copies of the matrix's entries in
3199  // memory at once, which is no worse than what Tpetra
3200  // promises.
3201  Teuchos::RCP<sparse_matrix_type> pMatrix =
3202  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3203  pRowMap, pRangeMap, pDomainMap, constructorParams,
3204  fillCompleteParams);
3205  // Only use a reduce-all in debug mode to check if pMatrix is
3206  // null. Otherwise, just throw an exception. We never expect
3207  // a null pointer here, so we can save a communication.
3208  if (debug) {
3209  int localIsNull = pMatrix.is_null () ? 1 : 0;
3210  int globalIsNull = 0;
3211  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3212  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3213  "Reader::makeMatrix() returned a null pointer on at least one "
3214  "process. Please report this bug to the Tpetra developers.");
3215  }
3216  else {
3217  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3218  "Reader::makeMatrix() returned a null pointer. "
3219  "Please report this bug to the Tpetra developers.");
3220  }
3221 
3222  // Sanity check for dimensions (read from the Matrix Market
3223  // data, vs. dimensions reported by the CrsMatrix).
3224  //
3225  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3226  // what one might think it does, so you have to ask the range
3227  // resp. domain map for the number of rows resp. columns.
3228  if (extraDebug && debug) {
3229  const int numProcs = pComm->getSize ();
3230  const global_size_t globalNumRows =
3231  pRangeMap->getGlobalNumElements();
3232  const global_size_t globalNumCols =
3233  pDomainMap->getGlobalNumElements();
3234  if (myRank == rootRank) {
3235  cerr << "-- Matrix is "
3236  << globalNumRows << " x " << globalNumCols
3237  << " with " << pMatrix->getGlobalNumEntries()
3238  << " entries, and index base "
3239  << pMatrix->getIndexBase() << "." << endl;
3240  }
3241  pComm->barrier ();
3242  for (int p = 0; p < numProcs; ++p) {
3243  if (myRank == p) {
3244  cerr << "-- Proc " << p << " owns "
3245  << pMatrix->getNodeNumCols() << " columns, and "
3246  << pMatrix->getNodeNumEntries() << " entries." << endl;
3247  }
3248  pComm->barrier ();
3249  }
3250  } // if (extraDebug && debug)
3251 
3252  if (debug && myRank == rootRank) {
3253  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3254  << endl;
3255  }
3256  return pMatrix;
3257  }
3258 
3259 
3300  static Teuchos::RCP<sparse_matrix_type>
3301  readSparse (std::istream& in,
3302  const Teuchos::RCP<const map_type>& rowMap,
3303  Teuchos::RCP<const map_type>& colMap,
3304  const Teuchos::RCP<const map_type>& domainMap,
3305  const Teuchos::RCP<const map_type>& rangeMap,
3306  const bool callFillComplete=true,
3307  const bool tolerant=false,
3308  const bool debug=false)
3309  {
3310  using Teuchos::MatrixMarket::Banner;
3311  using Teuchos::arcp;
3312  using Teuchos::ArrayRCP;
3313  using Teuchos::ArrayView;
3314  using Teuchos::as;
3315  using Teuchos::broadcast;
3316  using Teuchos::Comm;
3317  using Teuchos::null;
3318  using Teuchos::ptr;
3319  using Teuchos::RCP;
3320  using Teuchos::reduceAll;
3321  using Teuchos::Tuple;
3322  using std::cerr;
3323  using std::endl;
3324  typedef Teuchos::ScalarTraits<scalar_type> STS;
3325 
3326  RCP<const Comm<int> > pComm = rowMap->getComm ();
3327  const int myRank = pComm->getRank ();
3328  const int rootRank = 0;
3329  const bool extraDebug = false;
3330 
3331  // Fast checks for invalid input. We can't check other
3332  // attributes of the Maps until we've read in the matrix
3333  // dimensions.
3334  TEUCHOS_TEST_FOR_EXCEPTION(
3335  rowMap.is_null (), std::invalid_argument,
3336  "Row Map must be nonnull.");
3337  TEUCHOS_TEST_FOR_EXCEPTION(
3338  rangeMap.is_null (), std::invalid_argument,
3339  "Range Map must be nonnull.");
3340  TEUCHOS_TEST_FOR_EXCEPTION(
3341  domainMap.is_null (), std::invalid_argument,
3342  "Domain Map must be nonnull.");
3343  TEUCHOS_TEST_FOR_EXCEPTION(
3344  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3345  std::invalid_argument,
3346  "The specified row Map's communicator (rowMap->getComm())"
3347  "differs from the given separately supplied communicator pComm.");
3348  TEUCHOS_TEST_FOR_EXCEPTION(
3349  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3350  std::invalid_argument,
3351  "The specified domain Map's communicator (domainMap->getComm())"
3352  "differs from the given separately supplied communicator pComm.");
3353  TEUCHOS_TEST_FOR_EXCEPTION(
3354  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3355  std::invalid_argument,
3356  "The specified range Map's communicator (rangeMap->getComm())"
3357  "differs from the given separately supplied communicator pComm.");
3358 
3359  // Current line number in the input stream. Various calls
3360  // will modify this depending on the number of lines that are
3361  // read from the input stream. Only Rank 0 modifies this.
3362  size_t lineNumber = 1;
3363 
3364  if (debug && myRank == rootRank) {
3365  cerr << "Matrix Market reader: readSparse:" << endl
3366  << "-- Reading banner line" << endl;
3367  }
3368 
3369  // The "Banner" tells you whether the input stream represents
3370  // a sparse matrix, the symmetry type of the matrix, and the
3371  // type of the data it contains.
3372  //
3373  // pBanner will only be nonnull on MPI Rank 0. It will be
3374  // null on all other MPI processes.
3375  RCP<const Banner> pBanner;
3376  {
3377  // We read and validate the Banner on Proc 0, but broadcast
3378  // the validation result to all processes.
3379  // Teuchos::broadcast doesn't currently work with bool, so
3380  // we use int (true -> 1, false -> 0).
3381  int bannerIsCorrect = 1;
3382  std::ostringstream errMsg;
3383 
3384  if (myRank == rootRank) {
3385  // Read the Banner line from the input stream.
3386  try {
3387  pBanner = readBanner (in, lineNumber, tolerant, debug);
3388  }
3389  catch (std::exception& e) {
3390  errMsg << "Attempt to read the Matrix Market file's Banner line "
3391  "threw an exception: " << e.what();
3392  bannerIsCorrect = 0;
3393  }
3394 
3395  if (bannerIsCorrect) {
3396  // Validate the Banner for the case of a sparse matrix.
3397  // We validate on Proc 0, since it reads the Banner.
3398 
3399  // In intolerant mode, the matrix type must be "coordinate".
3400  if (! tolerant && pBanner->matrixType() != "coordinate") {
3401  bannerIsCorrect = 0;
3402  errMsg << "The Matrix Market input file must contain a "
3403  "\"coordinate\"-format sparse matrix in order to create a "
3404  "Tpetra::CrsMatrix object from it, but the file's matrix "
3405  "type is \"" << pBanner->matrixType() << "\" instead.";
3406  }
3407  // In tolerant mode, we allow the matrix type to be
3408  // anything other than "array" (which would mean that
3409  // the file contains a dense matrix).
3410  if (tolerant && pBanner->matrixType() == "array") {
3411  bannerIsCorrect = 0;
3412  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3413  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3414  "object from it, but the file's matrix type is \"array\" "
3415  "instead. That probably means the file contains dense matrix "
3416  "data.";
3417  }
3418  }
3419  } // Proc 0: Done reading the Banner, hopefully successfully.
3420 
3421  // Broadcast from Proc 0 whether the Banner was read correctly.
3422  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3423 
3424  // If the Banner is invalid, all processes throw an
3425  // exception. Only Proc 0 gets the exception message, but
3426  // that's OK, since the main point is to "stop the world"
3427  // (rather than throw an exception on one process and leave
3428  // the others hanging).
3429  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3430  std::invalid_argument, errMsg.str ());
3431  } // Done reading the Banner line and broadcasting success.
3432  if (debug && myRank == rootRank) {
3433  cerr << "-- Reading dimensions line" << endl;
3434  }
3435 
3436  // Read the matrix dimensions from the Matrix Market metadata.
3437  // dims = (numRows, numCols, numEntries). Proc 0 does the
3438  // reading, but it broadcasts the results to all MPI
3439  // processes. Thus, readCoordDims() is a collective
3440  // operation. It does a collective check for correctness too.
3441  Tuple<global_ordinal_type, 3> dims =
3442  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3443 
3444  if (debug && myRank == rootRank) {
3445  cerr << "-- Making Adder for collecting matrix data" << endl;
3446  }
3447 
3448  // "Adder" object for collecting all the sparse matrix entries
3449  // from the input stream. This is only nonnull on Proc 0.
3450  // The Adder internally converts the one-based indices (native
3451  // Matrix Market format) into zero-based indices.
3452  RCP<adder_type> pAdder =
3453  makeAdder (pComm, pBanner, dims, tolerant, debug);
3454 
3455  if (debug && myRank == rootRank) {
3456  cerr << "-- Reading matrix data" << endl;
3457  }
3458  //
3459  // Read the matrix entries from the input stream on Proc 0.
3460  //
3461  {
3462  // We use readSuccess to broadcast the results of the read
3463  // (succeeded or not) to all MPI processes. Since
3464  // Teuchos::broadcast doesn't currently know how to send
3465  // bools, we convert to int (true -> 1, false -> 0).
3466  int readSuccess = 1;
3467  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3468  if (myRank == rootRank) {
3469  try {
3470  // Reader for "coordinate" format sparse matrix data.
3471  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3472  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3473  reader_type reader (pAdder);
3474 
3475  // Read the sparse matrix entries.
3476  std::pair<bool, std::vector<size_t> > results =
3477  reader.read (in, lineNumber, tolerant, debug);
3478  readSuccess = results.first ? 1 : 0;
3479  }
3480  catch (std::exception& e) {
3481  readSuccess = 0;
3482  errMsg << e.what();
3483  }
3484  }
3485  broadcast (*pComm, rootRank, ptr (&readSuccess));
3486 
3487  // It would be nice to add a "verbose" flag, so that in
3488  // tolerant mode, we could log any bad line number(s) on
3489  // Proc 0. For now, we just throw if the read fails to
3490  // succeed.
3491  //
3492  // Question: If we're in tolerant mode, and if the read did
3493  // not succeed, should we attempt to call fillComplete()?
3494  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3495  "Failed to read the Matrix Market sparse matrix file: "
3496  << errMsg.str());
3497  } // Done reading the matrix entries (stored on Proc 0 for now)
3498 
3499  if (debug && myRank == rootRank) {
3500  cerr << "-- Successfully read the Matrix Market data" << endl;
3501  }
3502 
3503  // In tolerant mode, we need to rebroadcast the matrix
3504  // dimensions, since they may be different after reading the
3505  // actual matrix data. We only need to broadcast the number
3506  // of rows and columns. Only Rank 0 needs to know the actual
3507  // global number of entries, since (a) we need to merge
3508  // duplicates on Rank 0 first anyway, and (b) when we
3509  // distribute the entries, each rank other than Rank 0 will
3510  // only need to know how many entries it owns, not the total
3511  // number of entries.
3512  if (tolerant) {
3513  if (debug && myRank == rootRank) {
3514  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3515  << endl
3516  << "----- Dimensions before: "
3517  << dims[0] << " x " << dims[1]
3518  << endl;
3519  }
3520  // Packed coordinate matrix dimensions (numRows, numCols).
3521  Tuple<global_ordinal_type, 2> updatedDims;
3522  if (myRank == rootRank) {
3523  // If one or more bottom rows of the matrix contain no
3524  // entries, then the Adder will report that the number
3525  // of rows is less than that specified in the
3526  // metadata. We allow this case, and favor the
3527  // metadata so that the zero row(s) will be included.
3528  updatedDims[0] =
3529  std::max (dims[0], pAdder->getAdder()->numRows());
3530  updatedDims[1] = pAdder->getAdder()->numCols();
3531  }
3532  broadcast (*pComm, rootRank, updatedDims);
3533  dims[0] = updatedDims[0];
3534  dims[1] = updatedDims[1];
3535  if (debug && myRank == rootRank) {
3536  cerr << "----- Dimensions after: " << dims[0] << " x "
3537  << dims[1] << endl;
3538  }
3539  }
3540  else {
3541  // In strict mode, we require that the matrix's metadata and
3542  // its actual data agree, at least somewhat. In particular,
3543  // the number of rows must agree, since otherwise we cannot
3544  // distribute the matrix correctly.
3545 
3546  // Teuchos::broadcast() doesn't know how to broadcast bools,
3547  // so we use an int with the standard 1 == true, 0 == false
3548  // encoding.
3549  int dimsMatch = 1;
3550  if (myRank == rootRank) {
3551  // If one or more bottom rows of the matrix contain no
3552  // entries, then the Adder will report that the number of
3553  // rows is less than that specified in the metadata. We
3554  // allow this case, and favor the metadata, but do not
3555  // allow the Adder to think there are more rows in the
3556  // matrix than the metadata says.
3557  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3558  dimsMatch = 0;
3559  }
3560  }
3561  broadcast (*pComm, 0, ptr (&dimsMatch));
3562  if (dimsMatch == 0) {
3563  // We're in an error state anyway, so we might as well
3564  // work a little harder to print an informative error
3565  // message.
3566  //
3567  // Broadcast the Adder's idea of the matrix dimensions
3568  // from Proc 0 to all processes.
3569  Tuple<global_ordinal_type, 2> addersDims;
3570  if (myRank == rootRank) {
3571  addersDims[0] = pAdder->getAdder()->numRows();
3572  addersDims[1] = pAdder->getAdder()->numCols();
3573  }
3574  broadcast (*pComm, 0, addersDims);
3575  TEUCHOS_TEST_FOR_EXCEPTION(
3576  dimsMatch == 0, std::runtime_error,
3577  "The matrix metadata says that the matrix is " << dims[0] << " x "
3578  << dims[1] << ", but the actual data says that the matrix is "
3579  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3580  "data includes more rows than reported in the metadata. This "
3581  "is not allowed when parsing in strict mode. Parse the matrix in "
3582  "tolerant mode to ignore the metadata when it disagrees with the "
3583  "data.");
3584  }
3585  } // Matrix dimensions (# rows, # cols, # entries) agree.
3586 
3587  if (debug && myRank == rootRank) {
3588  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3589  }
3590 
3591  // Now that we've read in all the matrix entries from the
3592  // input stream into the adder on Proc 0, post-process them
3593  // into CSR format (still on Proc 0). This will facilitate
3594  // distributing them to all the processors.
3595  //
3596  // These arrays represent the global matrix data as a CSR
3597  // matrix (with numEntriesPerRow as redundant but convenient
3598  // metadata, since it's computable from rowPtr and vice
3599  // versa). They are valid only on Proc 0.
3600  ArrayRCP<size_t> numEntriesPerRow;
3601  ArrayRCP<size_t> rowPtr;
3602  ArrayRCP<global_ordinal_type> colInd;
3603  ArrayRCP<scalar_type> values;
3604  size_t maxNumEntriesPerRow = 0;
3605 
3606  // Proc 0 first merges duplicate entries, and then converts
3607  // the coordinate-format matrix data to CSR.
3608  {
3609  int mergeAndConvertSucceeded = 1;
3610  std::ostringstream errMsg;
3611 
3612  if (myRank == rootRank) {
3613  try {
3614  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3615  global_ordinal_type> element_type;
3616 
3617  // Number of rows in the matrix. If we are in tolerant
3618  // mode, we've already synchronized dims with the actual
3619  // matrix data. If in strict mode, we should use dims
3620  // (as read from the file's metadata) rather than the
3621  // matrix data to determine the dimensions. (The matrix
3622  // data will claim fewer rows than the metadata, if one
3623  // or more rows have no entries stored in the file.)
3624  const size_type numRows = dims[0];
3625 
3626  // Additively merge duplicate matrix entries.
3627  pAdder->getAdder()->merge ();
3628 
3629  // Get a temporary const view of the merged matrix entries.
3630  const std::vector<element_type>& entries =
3631  pAdder->getAdder()->getEntries();
3632 
3633  // Number of matrix entries (after merging).
3634  const size_t numEntries = (size_t)entries.size();
3635 
3636  if (debug) {
3637  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3638  << " rows and numEntries=" << numEntries
3639  << " entries." << endl;
3640  }
3641 
3642  // Make space for the CSR matrix data. Converting to
3643  // CSR is easier if we fill numEntriesPerRow with zeros
3644  // at first.
3645  numEntriesPerRow = arcp<size_t> (numRows);
3646  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3647  rowPtr = arcp<size_t> (numRows+1);
3648  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3649  colInd = arcp<global_ordinal_type> (numEntries);
3650  values = arcp<scalar_type> (numEntries);
3651 
3652  // Convert from array-of-structs coordinate format to CSR
3653  // (compressed sparse row) format.
3654  global_ordinal_type prvRow = 0;
3655  size_t curPos = 0;
3656  rowPtr[0] = 0;
3657  for (curPos = 0; curPos < numEntries; ++curPos) {
3658  const element_type& curEntry = entries[curPos];
3659  const global_ordinal_type curRow = curEntry.rowIndex();
3660  TEUCHOS_TEST_FOR_EXCEPTION(
3661  curRow < prvRow, std::logic_error,
3662  "Row indices are out of order, even though they are supposed "
3663  "to be sorted. curRow = " << curRow << ", prvRow = "
3664  << prvRow << ", at curPos = " << curPos << ". Please report "
3665  "this bug to the Tpetra developers.");
3666  if (curRow > prvRow) {
3667  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3668  rowPtr[r] = curPos;
3669  }
3670  prvRow = curRow;
3671  }
3672  numEntriesPerRow[curRow]++;
3673  colInd[curPos] = curEntry.colIndex();
3674  values[curPos] = curEntry.value();
3675  }
3676  // rowPtr has one more entry than numEntriesPerRow. The
3677  // last entry of rowPtr is the number of entries in
3678  // colInd and values.
3679  rowPtr[numRows] = numEntries;
3680  } // Finished conversion to CSR format
3681  catch (std::exception& e) {
3682  mergeAndConvertSucceeded = 0;
3683  errMsg << "Failed to merge sparse matrix entries and convert to "
3684  "CSR format: " << e.what();
3685  }
3686 
3687  if (debug && mergeAndConvertSucceeded) {
3688  // Number of rows in the matrix.
3689  const size_type numRows = dims[0];
3690  const size_type maxToDisplay = 100;
3691 
3692  cerr << "----- Proc 0: numEntriesPerRow[0.."
3693  << (numEntriesPerRow.size()-1) << "] ";
3694  if (numRows > maxToDisplay) {
3695  cerr << "(only showing first and last few entries) ";
3696  }
3697  cerr << "= [";
3698  if (numRows > 0) {
3699  if (numRows > maxToDisplay) {
3700  for (size_type k = 0; k < 2; ++k) {
3701  cerr << numEntriesPerRow[k] << " ";
3702  }
3703  cerr << "... ";
3704  for (size_type k = numRows-2; k < numRows-1; ++k) {
3705  cerr << numEntriesPerRow[k] << " ";
3706  }
3707  }
3708  else {
3709  for (size_type k = 0; k < numRows-1; ++k) {
3710  cerr << numEntriesPerRow[k] << " ";
3711  }
3712  }
3713  cerr << numEntriesPerRow[numRows-1];
3714  } // numRows > 0
3715  cerr << "]" << endl;
3716 
3717  cerr << "----- Proc 0: rowPtr ";
3718  if (numRows > maxToDisplay) {
3719  cerr << "(only showing first and last few entries) ";
3720  }
3721  cerr << "= [";
3722  if (numRows > maxToDisplay) {
3723  for (size_type k = 0; k < 2; ++k) {
3724  cerr << rowPtr[k] << " ";
3725  }
3726  cerr << "... ";
3727  for (size_type k = numRows-2; k < numRows; ++k) {
3728  cerr << rowPtr[k] << " ";
3729  }
3730  }
3731  else {
3732  for (size_type k = 0; k < numRows; ++k) {
3733  cerr << rowPtr[k] << " ";
3734  }
3735  }
3736  cerr << rowPtr[numRows] << "]" << endl;
3737 
3738  cerr << "----- Proc 0: colInd = [";
3739  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3740  cerr << colInd[k] << " ";
3741  }
3742  cerr << "]" << endl;
3743  }
3744  } // if myRank == rootRank
3745  } // Done converting sparse matrix data to CSR format
3746 
3747  // Now we're done with the Adder, so we can release the
3748  // reference ("free" it) to save space. This only actually
3749  // does anything on Rank 0, since pAdder is null on all the
3750  // other MPI processes.
3751  pAdder = null;
3752 
3753  // Verify details of the Maps. Don't count the global number
3754  // of entries in the row Map, since that number doesn't
3755  // correctly count overlap.
3756  if (debug && myRank == rootRank) {
3757  cerr << "-- Verifying Maps" << endl;
3758  }
3759  TEUCHOS_TEST_FOR_EXCEPTION(
3760  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3761  std::invalid_argument,
3762  "The range Map has " << rangeMap->getGlobalNumElements ()
3763  << " entries, but the matrix has a global number of rows " << dims[0]
3764  << ".");
3765  TEUCHOS_TEST_FOR_EXCEPTION(
3766  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3767  std::invalid_argument,
3768  "The domain Map has " << domainMap->getGlobalNumElements ()
3769  << " entries, but the matrix has a global number of columns "
3770  << dims[1] << ".");
3771 
3772  // Create a row Map which is entirely owned on Proc 0.
3773  RCP<Teuchos::FancyOStream> err = debug ?
3774  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3775 
3776  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3777  ArrayView<const global_ordinal_type> myRows =
3778  gatherRowMap->getNodeElementList ();
3779  const size_type myNumRows = myRows.size ();
3780  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3781 
3782  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3783  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3784  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3785  if (gatherNumEntriesPerRow[i_] > maxNumEntriesPerRow)
3786  maxNumEntriesPerRow = gatherNumEntriesPerRow[i_];
3787  }
3788 
3789  // Create a matrix using this Map, and fill in on Proc 0. We
3790  // know how many entries there are in each row, so we can use
3791  // static profile.
3792  RCP<sparse_matrix_type> A_proc0 =
3793  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow (),
3794  Tpetra::StaticProfile));
3795  if (myRank == rootRank) {
3796  if (debug) {
3797  cerr << "-- Proc 0: Filling gather matrix" << endl;
3798  }
3799  if (debug) {
3800  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3801  }
3802 
3803  // Add Proc 0's matrix entries to the CrsMatrix.
3804  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3805  size_type i = myRows[i_] - indexBase;
3806 
3807  const size_type curPos = as<size_type> (rowPtr[i]);
3808  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3809  ArrayView<global_ordinal_type> curColInd =
3810  colInd.view (curPos, curNumEntries);
3811  ArrayView<scalar_type> curValues =
3812  values.view (curPos, curNumEntries);
3813 
3814  // Modify the column indices in place to have the right index base.
3815  for (size_type k = 0; k < curNumEntries; ++k) {
3816  curColInd[k] += indexBase;
3817  }
3818  if (debug) {
3819  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3820  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3821  }
3822  // Avoid constructing empty views of ArrayRCP objects.
3823  if (curNumEntries > 0) {
3824  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3825  }
3826  }
3827  // Now we can save space by deallocating numEntriesPerRow,
3828  // rowPtr, colInd, and values, since we've already put those
3829  // data in the matrix.
3830  numEntriesPerRow = null;
3831  rowPtr = null;
3832  colInd = null;
3833  values = null;
3834  } // if myRank == rootRank
3835 
3836  broadcast<int,size_t> (*pComm, 0, &maxNumEntriesPerRow);
3837 
3838  RCP<sparse_matrix_type> A;
3839  if (colMap.is_null ()) {
3840  A = rcp (new sparse_matrix_type (rowMap, maxNumEntriesPerRow));
3841  } else {
3842  A = rcp (new sparse_matrix_type (rowMap, colMap, maxNumEntriesPerRow));
3843  }
3845  export_type exp (gatherRowMap, rowMap);
3846  A->doExport (*A_proc0, exp, INSERT);
3847 
3848  if (callFillComplete) {
3849  A->fillComplete (domainMap, rangeMap);
3850  }
3851 
3852  // We can't get the dimensions of the matrix until after
3853  // fillComplete() is called. Thus, we can't do the sanity
3854  // check (dimensions read from the Matrix Market data,
3855  // vs. dimensions reported by the CrsMatrix) unless the user
3856  // asked us to call fillComplete().
3857  //
3858  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3859  // what one might think it does, so you have to ask the range
3860  // resp. domain map for the number of rows resp. columns.
3861  if (callFillComplete) {
3862  const int numProcs = pComm->getSize ();
3863 
3864  if (extraDebug && debug) {
3865  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3866  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3867  if (myRank == rootRank) {
3868  cerr << "-- Matrix is "
3869  << globalNumRows << " x " << globalNumCols
3870  << " with " << A->getGlobalNumEntries()
3871  << " entries, and index base "
3872  << A->getIndexBase() << "." << endl;
3873  }
3874  pComm->barrier ();
3875  for (int p = 0; p < numProcs; ++p) {
3876  if (myRank == p) {
3877  cerr << "-- Proc " << p << " owns "
3878  << A->getNodeNumCols() << " columns, and "
3879  << A->getNodeNumEntries() << " entries." << endl;
3880  }
3881  pComm->barrier ();
3882  }
3883  } // if (extraDebug && debug)
3884  } // if (callFillComplete)
3885 
3886  if (debug && myRank == rootRank) {
3887  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3888  << endl;
3889  }
3890  return A;
3891  }
3892 
3921  static Teuchos::RCP<multivector_type>
3922  readDenseFile (const std::string& filename,
3923  const Teuchos::RCP<const comm_type>& comm,
3924  Teuchos::RCP<const map_type>& map,
3925  const bool tolerant=false,
3926  const bool debug=false)
3927  {
3928  std::ifstream in;
3929  if (comm->getRank () == 0) { // Only open the file on Proc 0.
3930  in.open (filename.c_str ()); // Destructor closes safely
3931  }
3932  return readDense (in, comm, map, tolerant, debug);
3933  }
3934 
3935 
3965  static Teuchos::RCP<vector_type>
3966  readVectorFile (const std::string& filename,
3967  const Teuchos::RCP<const comm_type>& comm,
3968  Teuchos::RCP<const map_type>& map,
3969  const bool tolerant=false,
3970  const bool debug=false)
3971  {
3972  std::ifstream in;
3973  if (comm->getRank () == 0) { // Only open the file on Proc 0.
3974  in.open (filename.c_str ()); // Destructor closes safely
3975  }
3976  return readVector (in, comm, map, tolerant, debug);
3977  }
3978 
3979 
4046  static Teuchos::RCP<multivector_type>
4047  readDense (std::istream& in,
4048  const Teuchos::RCP<const comm_type>& comm,
4049  Teuchos::RCP<const map_type>& map,
4050  const bool tolerant=false,
4051  const bool debug=false)
4052  {
4053  Teuchos::RCP<Teuchos::FancyOStream> err =
4054  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4055  return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4056  }
4057 
4058 
4060  static Teuchos::RCP<vector_type>
4061  readVector (std::istream& in,
4062  const Teuchos::RCP<const comm_type>& comm,
4063  Teuchos::RCP<const map_type>& map,
4064  const bool tolerant=false,
4065  const bool debug=false)
4066  {
4067  Teuchos::RCP<Teuchos::FancyOStream> err =
4068  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4069  return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4070  }
4071 
4072 
4093  static Teuchos::RCP<const map_type>
4094  readMapFile (const std::string& filename,
4095  const Teuchos::RCP<const comm_type>& comm,
4096  const bool tolerant=false,
4097  const bool debug=false)
4098  {
4099  using Teuchos::inOutArg;
4100  using Teuchos::broadcast;
4101  std::ifstream in;
4102 
4103  int success = 1;
4104  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4105  in.open (filename.c_str ()); // Destructor closes safely
4106  if (! in) {
4107  success = 0;
4108  }
4109  }
4110  broadcast<int, int> (*comm, 0, inOutArg (success));
4111  TEUCHOS_TEST_FOR_EXCEPTION(
4112  success == 0, std::runtime_error,
4113  "Tpetra::MatrixMarket::Reader::readMapFile: "
4114  "Failed to read file \"" << filename << "\" on Process 0.");
4115  return readMap (in, comm, tolerant, debug);
4116  }
4117 
4118 
4119  private:
4120  template<class MultiVectorScalarType>
4121  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4124  node_type> >
4125  readDenseImpl (std::istream& in,
4126  const Teuchos::RCP<const comm_type>& comm,
4127  Teuchos::RCP<const map_type>& map,
4128  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4129  const bool tolerant=false,
4130  const bool debug=false)
4131  {
4132  using Teuchos::MatrixMarket::Banner;
4133  using Teuchos::MatrixMarket::checkCommentLine;
4134  using Teuchos::ArrayRCP;
4135  using Teuchos::as;
4136  using Teuchos::broadcast;
4137  using Teuchos::outArg;
4138  using Teuchos::RCP;
4139  using Teuchos::Tuple;
4140  using std::endl;
4141  typedef MultiVectorScalarType ST;
4142  typedef local_ordinal_type LO;
4143  typedef global_ordinal_type GO;
4144  typedef node_type NT;
4145  typedef Teuchos::ScalarTraits<ST> STS;
4146  typedef typename STS::magnitudeType MT;
4147  typedef Teuchos::ScalarTraits<MT> STM;
4149 
4150  // Rank 0 is the only (MPI) process allowed to read from the
4151  // input stream.
4152  const int myRank = comm->getRank ();
4153 
4154  if (! err.is_null ()) {
4155  err->pushTab ();
4156  }
4157  if (debug) {
4158  *err << myRank << ": readDenseImpl" << endl;
4159  }
4160  if (! err.is_null ()) {
4161  err->pushTab ();
4162  }
4163 
4164  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4165  // instances be identical and that the Node instances be
4166  // identical. The essential condition is more complicated to
4167  // test and isn't the same for all Node types. Thus, we just
4168  // leave it up to the user.
4169 
4170  // // If map is nonnull, check the precondition that its
4171  // // communicator resp. node equal comm resp. node. Checking
4172  // // now avoids doing a lot of file reading before we detect the
4173  // // violated precondition.
4174  // TEUCHOS_TEST_FOR_EXCEPTION(
4175  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4176  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4177  // "communicator and node must equal the supplied communicator resp. "
4178  // "node.");
4179 
4180  // Process 0 will read in the matrix dimensions from the file,
4181  // and broadcast them to all ranks in the given communicator.
4182  // There are only 2 dimensions in the matrix, but we use the
4183  // third element of the Tuple to encode the banner's reported
4184  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4185  // (same as "real"). We don't allow pattern matrices (i.e.,
4186  // graphs) since they only make sense for sparse data.
4187  Tuple<GO, 3> dims;
4188  dims[0] = 0;
4189  dims[1] = 0;
4190 
4191  // Current line number in the input stream. Only valid on
4192  // Proc 0. Various calls will modify this depending on the
4193  // number of lines that are read from the input stream.
4194  size_t lineNumber = 1;
4195 
4196  // Capture errors and their messages on Proc 0.
4197  std::ostringstream exMsg;
4198  int localBannerReadSuccess = 1;
4199  int localDimsReadSuccess = 1;
4200 
4201  // Only Proc 0 gets to read matrix data from the input stream.
4202  if (myRank == 0) {
4203  if (debug) {
4204  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4205  }
4206 
4207  // The "Banner" tells you whether the input stream
4208  // represents a dense matrix, the symmetry type of the
4209  // matrix, and the type of the data it contains.
4210  RCP<const Banner> pBanner;
4211  try {
4212  pBanner = readBanner (in, lineNumber, tolerant, debug);
4213  } catch (std::exception& e) {
4214  exMsg << e.what ();
4215  localBannerReadSuccess = 0;
4216  }
4217  // Make sure the input stream is the right kind of data.
4218  if (localBannerReadSuccess) {
4219  if (pBanner->matrixType () != "array") {
4220  exMsg << "The Matrix Market file does not contain dense matrix "
4221  "data. Its banner (first) line says that its matrix type is \""
4222  << pBanner->matrixType () << "\", rather that the required "
4223  "\"array\".";
4224  localBannerReadSuccess = 0;
4225  } else if (pBanner->dataType() == "pattern") {
4226  exMsg << "The Matrix Market file's banner (first) "
4227  "line claims that the matrix's data type is \"pattern\". This does "
4228  "not make sense for a dense matrix, yet the file reports the matrix "
4229  "as dense. The only valid data types for a dense matrix are "
4230  "\"real\", \"complex\", and \"integer\".";
4231  localBannerReadSuccess = 0;
4232  } else {
4233  // Encode the data type reported by the Banner as the
4234  // third element of the dimensions Tuple.
4235  dims[2] = encodeDataType (pBanner->dataType ());
4236  }
4237  } // if we successfully read the banner line
4238 
4239  // At this point, we've successfully read the banner line.
4240  // Now read the dimensions line.
4241  if (localBannerReadSuccess) {
4242  if (debug) {
4243  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4244  }
4245  // Keep reading lines from the input stream until we find
4246  // a non-comment line, or until we run out of lines. The
4247  // latter is an error, since every "array" format Matrix
4248  // Market file must have a dimensions line after the
4249  // banner (even if the matrix has zero rows or columns, or
4250  // zero entries).
4251  std::string line;
4252  bool commentLine = true;
4253 
4254  while (commentLine) {
4255  // Test whether it is even valid to read from the input
4256  // stream wrapping the line.
4257  if (in.eof () || in.fail ()) {
4258  exMsg << "Unable to get array dimensions line (at all) from line "
4259  << lineNumber << " of input stream. The input stream "
4260  << "claims that it is "
4261  << (in.eof() ? "at end-of-file." : "in a failed state.");
4262  localDimsReadSuccess = 0;
4263  } else {
4264  // Try to get the next line from the input stream.
4265  if (getline (in, line)) {
4266  ++lineNumber; // We did actually read a line.
4267  }
4268  // Is the current line a comment line? Ignore start
4269  // and size; they are only useful for reading the
4270  // actual matrix entries. (We could use them here as
4271  // an optimization, but we've chosen not to.)
4272  size_t start = 0, size = 0;
4273  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4274  } // whether we failed to read the line at all
4275  } // while the line we just read is a comment line
4276 
4277  //
4278  // Get <numRows> <numCols> from the line we just read.
4279  //
4280  std::istringstream istr (line);
4281 
4282  // Test whether it is even valid to read from the input
4283  // stream wrapping the line.
4284  if (istr.eof () || istr.fail ()) {
4285  exMsg << "Unable to read any data from line " << lineNumber
4286  << " of input; the line should contain the matrix dimensions "
4287  << "\"<numRows> <numCols>\".";
4288  localDimsReadSuccess = 0;
4289  } else { // It's valid to read from the line.
4290  GO theNumRows = 0;
4291  istr >> theNumRows; // Read in the number of rows.
4292  if (istr.fail ()) {
4293  exMsg << "Failed to get number of rows from line "
4294  << lineNumber << " of input; the line should contains the "
4295  << "matrix dimensions \"<numRows> <numCols>\".";
4296  localDimsReadSuccess = 0;
4297  } else { // We successfully read the number of rows
4298  dims[0] = theNumRows; // Save the number of rows
4299  if (istr.eof ()) { // Do we still have data to read?
4300  exMsg << "No more data after number of rows on line "
4301  << lineNumber << " of input; the line should contain the "
4302  << "matrix dimensions \"<numRows> <numCols>\".";
4303  localDimsReadSuccess = 0;
4304  } else { // Still data left to read; read in number of columns.
4305  GO theNumCols = 0;
4306  istr >> theNumCols; // Read in the number of columns
4307  if (istr.fail ()) {
4308  exMsg << "Failed to get number of columns from line "
4309  << lineNumber << " of input; the line should contain "
4310  << "the matrix dimensions \"<numRows> <numCols>\".";
4311  localDimsReadSuccess = 0;
4312  } else { // We successfully read the number of columns
4313  dims[1] = theNumCols; // Save the number of columns
4314  } // if istr.fail ()
4315  } // if istr.eof ()
4316  } // if we read the number of rows
4317  } // if the input stream wrapping the dims line was (in)valid
4318  } // if we successfully read the banner line
4319  } // if (myRank == 0)
4320 
4321  // Broadcast the matrix dimensions, the encoded data type, and
4322  // whether or not Proc 0 succeeded in reading the banner and
4323  // dimensions.
4324  Tuple<GO, 5> bannerDimsReadResult;
4325  if (myRank == 0) {
4326  bannerDimsReadResult[0] = dims[0]; // numRows
4327  bannerDimsReadResult[1] = dims[1]; // numCols
4328  bannerDimsReadResult[2] = dims[2]; // encoded data type
4329  bannerDimsReadResult[3] = localBannerReadSuccess;
4330  bannerDimsReadResult[4] = localDimsReadSuccess;
4331  }
4332  // Broadcast matrix dimensions and the encoded data type from
4333  // Proc 0 to all the MPI processes.
4334  broadcast (*comm, 0, bannerDimsReadResult);
4335 
4336  TEUCHOS_TEST_FOR_EXCEPTION(
4337  bannerDimsReadResult[3] == 0, std::runtime_error,
4338  "Failed to read banner line: " << exMsg.str ());
4339  TEUCHOS_TEST_FOR_EXCEPTION(
4340  bannerDimsReadResult[4] == 0, std::runtime_error,
4341  "Failed to read matrix dimensions line: " << exMsg.str ());
4342  if (myRank != 0) {
4343  dims[0] = bannerDimsReadResult[0];
4344  dims[1] = bannerDimsReadResult[1];
4345  dims[2] = bannerDimsReadResult[2];
4346  }
4347 
4348  // Tpetra objects want the matrix dimensions in these types.
4349  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4350  const size_t numCols = static_cast<size_t> (dims[1]);
4351 
4352  // Make a "Proc 0 owns everything" Map that we will use to
4353  // read in the multivector entries in the correct order on
4354  // Proc 0. This must be a collective
4355  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4356  if (map.is_null ()) {
4357  // The user didn't supply a Map. Make a contiguous
4358  // distributed Map for them, using the read-in multivector
4359  // dimensions.
4360  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4361  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4362  // At this point, map exists and has a nonnull node.
4363  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4364  comm);
4365  }
4366  else { // The user supplied a Map.
4367  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4368  }
4369 
4370  // Make a multivector X owned entirely by Proc 0.
4371  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4372 
4373  //
4374  // On Proc 0, read the Matrix Market data from the input
4375  // stream into the multivector X.
4376  //
4377  int localReadDataSuccess = 1;
4378  if (myRank == 0) {
4379  try {
4380  if (debug) {
4381  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4382  << endl;
4383  }
4384 
4385  // Make sure that we can get a 1-D view of X.
4386  TEUCHOS_TEST_FOR_EXCEPTION(
4387  ! X->isConstantStride (), std::logic_error,
4388  "Can't get a 1-D view of the entries of the MultiVector X on "
4389  "Process 0, because the stride between the columns of X is not "
4390  "constant. This shouldn't happen because we just created X and "
4391  "haven't filled it in yet. Please report this bug to the Tpetra "
4392  "developers.");
4393 
4394  // Get a writeable 1-D view of the entries of X. Rank 0
4395  // owns all of them. The view will expire at the end of
4396  // scope, so (if necessary) it will be written back to X
4397  // at this time.
4398  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4399  TEUCHOS_TEST_FOR_EXCEPTION(
4400  as<global_size_t> (X_view.size ()) < numRows * numCols,
4401  std::logic_error,
4402  "The view of X has size " << X_view << " which is not enough to "
4403  "accommodate the expected number of entries numRows*numCols = "
4404  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4405  "Please report this bug to the Tpetra developers.");
4406  const size_t stride = X->getStride ();
4407 
4408  // The third element of the dimensions Tuple encodes the data
4409  // type reported by the Banner: "real" == 0, "complex" == 1,
4410  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4411  // allow dense matrices to be pattern matrices, so dims[2] ==
4412  // 0 or 1. We've already checked for this above.
4413  const bool isComplex = (dims[2] == 1);
4414  size_type count = 0, curRow = 0, curCol = 0;
4415 
4416  std::string line;
4417  while (getline (in, line)) {
4418  ++lineNumber;
4419  // Is the current line a comment line? If it's not,
4420  // line.substr(start,size) contains the data.
4421  size_t start = 0, size = 0;
4422  const bool commentLine =
4423  checkCommentLine (line, start, size, lineNumber, tolerant);
4424  if (! commentLine) {
4425  // Make sure we have room in which to put the new matrix
4426  // entry. We check this only after checking for a
4427  // comment line, because there may be one or more
4428  // comment lines at the end of the file. In tolerant
4429  // mode, we simply ignore any extra data.
4430  if (count >= X_view.size()) {
4431  if (tolerant) {
4432  break;
4433  }
4434  else {
4435  TEUCHOS_TEST_FOR_EXCEPTION(
4436  count >= X_view.size(),
4437  std::runtime_error,
4438  "The Matrix Market input stream has more data in it than "
4439  "its metadata reported. Current line number is "
4440  << lineNumber << ".");
4441  }
4442  }
4443 
4444  // mfh 19 Dec 2012: Ignore everything up to the initial
4445  // colon. writeDense() has the option to print out the
4446  // global row index in front of each entry, followed by
4447  // a colon and space.
4448  {
4449  const size_t pos = line.substr (start, size).find (':');
4450  if (pos != std::string::npos) {
4451  start = pos+1;
4452  }
4453  }
4454  std::istringstream istr (line.substr (start, size));
4455  // Does the line contain anything at all? Can we
4456  // safely read from the input stream wrapping the
4457  // line?
4458  if (istr.eof() || istr.fail()) {
4459  // In tolerant mode, simply ignore the line.
4460  if (tolerant) {
4461  break;
4462  }
4463  // We repeat the full test here so the exception
4464  // message is more informative.
4465  TEUCHOS_TEST_FOR_EXCEPTION(
4466  ! tolerant && (istr.eof() || istr.fail()),
4467  std::runtime_error,
4468  "Line " << lineNumber << " of the Matrix Market file is "
4469  "empty, or we cannot read from it for some other reason.");
4470  }
4471  // Current matrix entry to read in.
4472  ST val = STS::zero();
4473  // Real and imaginary parts of the current matrix entry.
4474  // The imaginary part is zero if the matrix is real-valued.
4475  MT real = STM::zero(), imag = STM::zero();
4476 
4477  // isComplex refers to the input stream's data, not to
4478  // the scalar type S. It's OK to read real-valued
4479  // data into a matrix storing complex-valued data; in
4480  // that case, all entries' imaginary parts are zero.
4481  if (isComplex) {
4482  // STS::real() and STS::imag() return a copy of
4483  // their respective components, not a writeable
4484  // reference. Otherwise we could just assign to
4485  // them using the istream extraction operator (>>).
4486  // That's why we have separate magnitude type "real"
4487  // and "imag" variables.
4488 
4489  // Attempt to read the real part of the current entry.
4490  istr >> real;
4491  if (istr.fail()) {
4492  TEUCHOS_TEST_FOR_EXCEPTION(
4493  ! tolerant && istr.eof(), std::runtime_error,
4494  "Failed to get the real part of a complex-valued matrix "
4495  "entry from line " << lineNumber << " of the Matrix Market "
4496  "file.");
4497  // In tolerant mode, just skip bad lines.
4498  if (tolerant) {
4499  break;
4500  }
4501  } else if (istr.eof()) {
4502  TEUCHOS_TEST_FOR_EXCEPTION(
4503  ! tolerant && istr.eof(), std::runtime_error,
4504  "Missing imaginary part of a complex-valued matrix entry "
4505  "on line " << lineNumber << " of the Matrix Market file.");
4506  // In tolerant mode, let any missing imaginary part be 0.
4507  } else {
4508  // Attempt to read the imaginary part of the current
4509  // matrix entry.
4510  istr >> imag;
4511  TEUCHOS_TEST_FOR_EXCEPTION(
4512  ! tolerant && istr.fail(), std::runtime_error,
4513  "Failed to get the imaginary part of a complex-valued "
4514  "matrix entry from line " << lineNumber << " of the "
4515  "Matrix Market file.");
4516  // In tolerant mode, let any missing or corrupted
4517  // imaginary part be 0.
4518  }
4519  } else { // Matrix Market file contains real-valued data.
4520  // Attempt to read the current matrix entry.
4521  istr >> real;
4522  TEUCHOS_TEST_FOR_EXCEPTION(
4523  ! tolerant && istr.fail(), std::runtime_error,
4524  "Failed to get a real-valued matrix entry from line "
4525  << lineNumber << " of the Matrix Market file.");
4526  // In tolerant mode, simply ignore the line if
4527  // we failed to read a matrix entry.
4528  if (istr.fail() && tolerant) {
4529  break;
4530  }
4531  }
4532  // In tolerant mode, we simply let pass through whatever
4533  // data we got.
4534  TEUCHOS_TEST_FOR_EXCEPTION(
4535  ! tolerant && istr.fail(), std::runtime_error,
4536  "Failed to read matrix data from line " << lineNumber
4537  << " of the Matrix Market file.");
4538 
4539  // Assign val = ST(real, imag).
4540  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4541 
4542  curRow = count % numRows;
4543  curCol = count / numRows;
4544  X_view[curRow + curCol*stride] = val;
4545  ++count;
4546  } // if not a comment line
4547  } // while there are still lines in the file, get the next one
4548 
4549  TEUCHOS_TEST_FOR_EXCEPTION(
4550  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4551  std::runtime_error,
4552  "The Matrix Market metadata reports that the dense matrix is "
4553  << numRows << " x " << numCols << ", and thus has "
4554  << numRows*numCols << " total entries, but we only found " << count
4555  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4556  } catch (std::exception& e) {
4557  exMsg << e.what ();
4558  localReadDataSuccess = 0;
4559  }
4560  } // if (myRank == 0)
4561 
4562  if (debug) {
4563  *err << myRank << ": readDenseImpl: done reading data" << endl;
4564  }
4565 
4566  // Synchronize on whether Proc 0 successfully read the data.
4567  int globalReadDataSuccess = localReadDataSuccess;
4568  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4569  TEUCHOS_TEST_FOR_EXCEPTION(
4570  globalReadDataSuccess == 0, std::runtime_error,
4571  "Failed to read the multivector's data: " << exMsg.str ());
4572 
4573  // If there's only one MPI process and the user didn't supply
4574  // a Map (i.e., pMap is null), we're done. Set pMap to the
4575  // Map used to distribute X, and return X.
4576  if (comm->getSize () == 1 && map.is_null ()) {
4577  map = proc0Map;
4578  if (! err.is_null ()) {
4579  err->popTab ();
4580  }
4581  if (debug) {
4582  *err << myRank << ": readDenseImpl: done" << endl;
4583  }
4584  if (! err.is_null ()) {
4585  err->popTab ();
4586  }
4587  return X;
4588  }
4589 
4590  if (debug) {
4591  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4592  }
4593 
4594  // Make a multivector Y with the distributed map pMap.
4595  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4596 
4597  if (debug) {
4598  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4599  }
4600 
4601  // Make an Export object that will export X to Y. First
4602  // argument is the source map, second argument is the target
4603  // map.
4604  Export<LO, GO, NT> exporter (proc0Map, map, err);
4605 
4606  if (debug) {
4607  *err << myRank << ": readDenseImpl: Exporting" << endl;
4608  }
4609  // Export X into Y.
4610  Y->doExport (*X, exporter, INSERT);
4611 
4612  if (! err.is_null ()) {
4613  err->popTab ();
4614  }
4615  if (debug) {
4616  *err << myRank << ": readDenseImpl: done" << endl;
4617  }
4618  if (! err.is_null ()) {
4619  err->popTab ();
4620  }
4621 
4622  // Y is distributed over all process(es) in the communicator.
4623  return Y;
4624  }
4625 
4626 
4627  template<class VectorScalarType>
4628  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4631  node_type> >
4632  readVectorImpl (std::istream& in,
4633  const Teuchos::RCP<const comm_type>& comm,
4634  Teuchos::RCP<const map_type>& map,
4635  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4636  const bool tolerant=false,
4637  const bool debug=false)
4638  {
4639  using Teuchos::MatrixMarket::Banner;
4640  using Teuchos::MatrixMarket::checkCommentLine;
4641  using Teuchos::as;
4642  using Teuchos::broadcast;
4643  using Teuchos::outArg;
4644  using Teuchos::RCP;
4645  using Teuchos::Tuple;
4646  using std::endl;
4647  typedef VectorScalarType ST;
4648  typedef local_ordinal_type LO;
4649  typedef global_ordinal_type GO;
4650  typedef node_type NT;
4651  typedef Teuchos::ScalarTraits<ST> STS;
4652  typedef typename STS::magnitudeType MT;
4653  typedef Teuchos::ScalarTraits<MT> STM;
4654  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4655 
4656  // Rank 0 is the only (MPI) process allowed to read from the
4657  // input stream.
4658  const int myRank = comm->getRank ();
4659 
4660  if (! err.is_null ()) {
4661  err->pushTab ();
4662  }
4663  if (debug) {
4664  *err << myRank << ": readVectorImpl" << endl;
4665  }
4666  if (! err.is_null ()) {
4667  err->pushTab ();
4668  }
4669 
4670  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4671  // instances be identical and that the Node instances be
4672  // identical. The essential condition is more complicated to
4673  // test and isn't the same for all Node types. Thus, we just
4674  // leave it up to the user.
4675 
4676  // // If map is nonnull, check the precondition that its
4677  // // communicator resp. node equal comm resp. node. Checking
4678  // // now avoids doing a lot of file reading before we detect the
4679  // // violated precondition.
4680  // TEUCHOS_TEST_FOR_EXCEPTION(
4681  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4682  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4683  // "communicator and node must equal the supplied communicator resp. "
4684  // "node.");
4685 
4686  // Process 0 will read in the matrix dimensions from the file,
4687  // and broadcast them to all ranks in the given communicator.
4688  // There are only 2 dimensions in the matrix, but we use the
4689  // third element of the Tuple to encode the banner's reported
4690  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4691  // (same as "real"). We don't allow pattern matrices (i.e.,
4692  // graphs) since they only make sense for sparse data.
4693  Tuple<GO, 3> dims;
4694  dims[0] = 0;
4695  dims[1] = 0;
4696 
4697  // Current line number in the input stream. Only valid on
4698  // Proc 0. Various calls will modify this depending on the
4699  // number of lines that are read from the input stream.
4700  size_t lineNumber = 1;
4701 
4702  // Capture errors and their messages on Proc 0.
4703  std::ostringstream exMsg;
4704  int localBannerReadSuccess = 1;
4705  int localDimsReadSuccess = 1;
4706 
4707  // Only Proc 0 gets to read matrix data from the input stream.
4708  if (myRank == 0) {
4709  if (debug) {
4710  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4711  }
4712 
4713  // The "Banner" tells you whether the input stream
4714  // represents a dense matrix, the symmetry type of the
4715  // matrix, and the type of the data it contains.
4716  RCP<const Banner> pBanner;
4717  try {
4718  pBanner = readBanner (in, lineNumber, tolerant, debug);
4719  } catch (std::exception& e) {
4720  exMsg << e.what ();
4721  localBannerReadSuccess = 0;
4722  }
4723  // Make sure the input stream is the right kind of data.
4724  if (localBannerReadSuccess) {
4725  if (pBanner->matrixType () != "array") {
4726  exMsg << "The Matrix Market file does not contain dense matrix "
4727  "data. Its banner (first) line says that its matrix type is \""
4728  << pBanner->matrixType () << "\", rather that the required "
4729  "\"array\".";
4730  localBannerReadSuccess = 0;
4731  } else if (pBanner->dataType() == "pattern") {
4732  exMsg << "The Matrix Market file's banner (first) "
4733  "line claims that the matrix's data type is \"pattern\". This does "
4734  "not make sense for a dense matrix, yet the file reports the matrix "
4735  "as dense. The only valid data types for a dense matrix are "
4736  "\"real\", \"complex\", and \"integer\".";
4737  localBannerReadSuccess = 0;
4738  } else {
4739  // Encode the data type reported by the Banner as the
4740  // third element of the dimensions Tuple.
4741  dims[2] = encodeDataType (pBanner->dataType ());
4742  }
4743  } // if we successfully read the banner line
4744 
4745  // At this point, we've successfully read the banner line.
4746  // Now read the dimensions line.
4747  if (localBannerReadSuccess) {
4748  if (debug) {
4749  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4750  }
4751  // Keep reading lines from the input stream until we find
4752  // a non-comment line, or until we run out of lines. The
4753  // latter is an error, since every "array" format Matrix
4754  // Market file must have a dimensions line after the
4755  // banner (even if the matrix has zero rows or columns, or
4756  // zero entries).
4757  std::string line;
4758  bool commentLine = true;
4759 
4760  while (commentLine) {
4761  // Test whether it is even valid to read from the input
4762  // stream wrapping the line.
4763  if (in.eof () || in.fail ()) {
4764  exMsg << "Unable to get array dimensions line (at all) from line "
4765  << lineNumber << " of input stream. The input stream "
4766  << "claims that it is "
4767  << (in.eof() ? "at end-of-file." : "in a failed state.");
4768  localDimsReadSuccess = 0;
4769  } else {
4770  // Try to get the next line from the input stream.
4771  if (getline (in, line)) {
4772  ++lineNumber; // We did actually read a line.
4773  }
4774  // Is the current line a comment line? Ignore start
4775  // and size; they are only useful for reading the
4776  // actual matrix entries. (We could use them here as
4777  // an optimization, but we've chosen not to.)
4778  size_t start = 0, size = 0;
4779  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4780  } // whether we failed to read the line at all
4781  } // while the line we just read is a comment line
4782 
4783  //
4784  // Get <numRows> <numCols> from the line we just read.
4785  //
4786  std::istringstream istr (line);
4787 
4788  // Test whether it is even valid to read from the input
4789  // stream wrapping the line.
4790  if (istr.eof () || istr.fail ()) {
4791  exMsg << "Unable to read any data from line " << lineNumber
4792  << " of input; the line should contain the matrix dimensions "
4793  << "\"<numRows> <numCols>\".";
4794  localDimsReadSuccess = 0;
4795  } else { // It's valid to read from the line.
4796  GO theNumRows = 0;
4797  istr >> theNumRows; // Read in the number of rows.
4798  if (istr.fail ()) {
4799  exMsg << "Failed to get number of rows from line "
4800  << lineNumber << " of input; the line should contains the "
4801  << "matrix dimensions \"<numRows> <numCols>\".";
4802  localDimsReadSuccess = 0;
4803  } else { // We successfully read the number of rows
4804  dims[0] = theNumRows; // Save the number of rows
4805  if (istr.eof ()) { // Do we still have data to read?
4806  exMsg << "No more data after number of rows on line "
4807  << lineNumber << " of input; the line should contain the "
4808  << "matrix dimensions \"<numRows> <numCols>\".";
4809  localDimsReadSuccess = 0;
4810  } else { // Still data left to read; read in number of columns.
4811  GO theNumCols = 0;
4812  istr >> theNumCols; // Read in the number of columns
4813  if (istr.fail ()) {
4814  exMsg << "Failed to get number of columns from line "
4815  << lineNumber << " of input; the line should contain "
4816  << "the matrix dimensions \"<numRows> <numCols>\".";
4817  localDimsReadSuccess = 0;
4818  } else { // We successfully read the number of columns
4819  dims[1] = theNumCols; // Save the number of columns
4820  } // if istr.fail ()
4821  } // if istr.eof ()
4822  } // if we read the number of rows
4823  } // if the input stream wrapping the dims line was (in)valid
4824  } // if we successfully read the banner line
4825  } // if (myRank == 0)
4826 
4827  // Check if file has a Vector
4828  if (dims[1]!=1) {
4829  exMsg << "File does not contain a 1D Vector";
4830  localDimsReadSuccess = 0;
4831  }
4832 
4833  // Broadcast the matrix dimensions, the encoded data type, and
4834  // whether or not Proc 0 succeeded in reading the banner and
4835  // dimensions.
4836  Tuple<GO, 5> bannerDimsReadResult;
4837  if (myRank == 0) {
4838  bannerDimsReadResult[0] = dims[0]; // numRows
4839  bannerDimsReadResult[1] = dims[1]; // numCols
4840  bannerDimsReadResult[2] = dims[2]; // encoded data type
4841  bannerDimsReadResult[3] = localBannerReadSuccess;
4842  bannerDimsReadResult[4] = localDimsReadSuccess;
4843  }
4844 
4845  // Broadcast matrix dimensions and the encoded data type from
4846  // Proc 0 to all the MPI processes.
4847  broadcast (*comm, 0, bannerDimsReadResult);
4848 
4849  TEUCHOS_TEST_FOR_EXCEPTION(
4850  bannerDimsReadResult[3] == 0, std::runtime_error,
4851  "Failed to read banner line: " << exMsg.str ());
4852  TEUCHOS_TEST_FOR_EXCEPTION(
4853  bannerDimsReadResult[4] == 0, std::runtime_error,
4854  "Failed to read matrix dimensions line: " << exMsg.str ());
4855  if (myRank != 0) {
4856  dims[0] = bannerDimsReadResult[0];
4857  dims[1] = bannerDimsReadResult[1];
4858  dims[2] = bannerDimsReadResult[2];
4859  }
4860 
4861  // Tpetra objects want the matrix dimensions in these types.
4862  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4863  const size_t numCols = static_cast<size_t> (dims[1]);
4864 
4865  // Make a "Proc 0 owns everything" Map that we will use to
4866  // read in the multivector entries in the correct order on
4867  // Proc 0. This must be a collective
4868  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4869  if (map.is_null ()) {
4870  // The user didn't supply a Map. Make a contiguous
4871  // distributed Map for them, using the read-in multivector
4872  // dimensions.
4873  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4874  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4875  // At this point, map exists and has a nonnull node.
4876  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4877  comm);
4878  }
4879  else { // The user supplied a Map.
4880  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4881  }
4882 
4883  // Make a multivector X owned entirely by Proc 0.
4884  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
4885 
4886  //
4887  // On Proc 0, read the Matrix Market data from the input
4888  // stream into the multivector X.
4889  //
4890  int localReadDataSuccess = 1;
4891  if (myRank == 0) {
4892  try {
4893  if (debug) {
4894  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
4895  << endl;
4896  }
4897 
4898  // Make sure that we can get a 1-D view of X.
4899  TEUCHOS_TEST_FOR_EXCEPTION(
4900  ! X->isConstantStride (), std::logic_error,
4901  "Can't get a 1-D view of the entries of the MultiVector X on "
4902  "Process 0, because the stride between the columns of X is not "
4903  "constant. This shouldn't happen because we just created X and "
4904  "haven't filled it in yet. Please report this bug to the Tpetra "
4905  "developers.");
4906 
4907  // Get a writeable 1-D view of the entries of X. Rank 0
4908  // owns all of them. The view will expire at the end of
4909  // scope, so (if necessary) it will be written back to X
4910  // at this time.
4911  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4912  TEUCHOS_TEST_FOR_EXCEPTION(
4913  as<global_size_t> (X_view.size ()) < numRows * numCols,
4914  std::logic_error,
4915  "The view of X has size " << X_view << " which is not enough to "
4916  "accommodate the expected number of entries numRows*numCols = "
4917  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4918  "Please report this bug to the Tpetra developers.");
4919  const size_t stride = X->getStride ();
4920 
4921  // The third element of the dimensions Tuple encodes the data
4922  // type reported by the Banner: "real" == 0, "complex" == 1,
4923  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4924  // allow dense matrices to be pattern matrices, so dims[2] ==
4925  // 0 or 1. We've already checked for this above.
4926  const bool isComplex = (dims[2] == 1);
4927  size_type count = 0, curRow = 0, curCol = 0;
4928 
4929  std::string line;
4930  while (getline (in, line)) {
4931  ++lineNumber;
4932  // Is the current line a comment line? If it's not,
4933  // line.substr(start,size) contains the data.
4934  size_t start = 0, size = 0;
4935  const bool commentLine =
4936  checkCommentLine (line, start, size, lineNumber, tolerant);
4937  if (! commentLine) {
4938  // Make sure we have room in which to put the new matrix
4939  // entry. We check this only after checking for a
4940  // comment line, because there may be one or more
4941  // comment lines at the end of the file. In tolerant
4942  // mode, we simply ignore any extra data.
4943  if (count >= X_view.size()) {
4944  if (tolerant) {
4945  break;
4946  }
4947  else {
4948  TEUCHOS_TEST_FOR_EXCEPTION(
4949  count >= X_view.size(),
4950  std::runtime_error,
4951  "The Matrix Market input stream has more data in it than "
4952  "its metadata reported. Current line number is "
4953  << lineNumber << ".");
4954  }
4955  }
4956 
4957  // mfh 19 Dec 2012: Ignore everything up to the initial
4958  // colon. writeDense() has the option to print out the
4959  // global row index in front of each entry, followed by
4960  // a colon and space.
4961  {
4962  const size_t pos = line.substr (start, size).find (':');
4963  if (pos != std::string::npos) {
4964  start = pos+1;
4965  }
4966  }
4967  std::istringstream istr (line.substr (start, size));
4968  // Does the line contain anything at all? Can we
4969  // safely read from the input stream wrapping the
4970  // line?
4971  if (istr.eof() || istr.fail()) {
4972  // In tolerant mode, simply ignore the line.
4973  if (tolerant) {
4974  break;
4975  }
4976  // We repeat the full test here so the exception
4977  // message is more informative.
4978  TEUCHOS_TEST_FOR_EXCEPTION(
4979  ! tolerant && (istr.eof() || istr.fail()),
4980  std::runtime_error,
4981  "Line " << lineNumber << " of the Matrix Market file is "
4982  "empty, or we cannot read from it for some other reason.");
4983  }
4984  // Current matrix entry to read in.
4985  ST val = STS::zero();
4986  // Real and imaginary parts of the current matrix entry.
4987  // The imaginary part is zero if the matrix is real-valued.
4988  MT real = STM::zero(), imag = STM::zero();
4989 
4990  // isComplex refers to the input stream's data, not to
4991  // the scalar type S. It's OK to read real-valued
4992  // data into a matrix storing complex-valued data; in
4993  // that case, all entries' imaginary parts are zero.
4994  if (isComplex) {
4995  // STS::real() and STS::imag() return a copy of
4996  // their respective components, not a writeable
4997  // reference. Otherwise we could just assign to
4998  // them using the istream extraction operator (>>).
4999  // That's why we have separate magnitude type "real"
5000  // and "imag" variables.
5001 
5002  // Attempt to read the real part of the current entry.
5003  istr >> real;
5004  if (istr.fail()) {
5005  TEUCHOS_TEST_FOR_EXCEPTION(
5006  ! tolerant && istr.eof(), std::runtime_error,
5007  "Failed to get the real part of a complex-valued matrix "
5008  "entry from line " << lineNumber << " of the Matrix Market "
5009  "file.");
5010  // In tolerant mode, just skip bad lines.
5011  if (tolerant) {
5012  break;
5013  }
5014  } else if (istr.eof()) {
5015  TEUCHOS_TEST_FOR_EXCEPTION(
5016  ! tolerant && istr.eof(), std::runtime_error,
5017  "Missing imaginary part of a complex-valued matrix entry "
5018  "on line " << lineNumber << " of the Matrix Market file.");
5019  // In tolerant mode, let any missing imaginary part be 0.
5020  } else {
5021  // Attempt to read the imaginary part of the current
5022  // matrix entry.
5023  istr >> imag;
5024  TEUCHOS_TEST_FOR_EXCEPTION(
5025  ! tolerant && istr.fail(), std::runtime_error,
5026  "Failed to get the imaginary part of a complex-valued "
5027  "matrix entry from line " << lineNumber << " of the "
5028  "Matrix Market file.");
5029  // In tolerant mode, let any missing or corrupted
5030  // imaginary part be 0.
5031  }
5032  } else { // Matrix Market file contains real-valued data.
5033  // Attempt to read the current matrix entry.
5034  istr >> real;
5035  TEUCHOS_TEST_FOR_EXCEPTION(
5036  ! tolerant && istr.fail(), std::runtime_error,
5037  "Failed to get a real-valued matrix entry from line "
5038  << lineNumber << " of the Matrix Market file.");
5039  // In tolerant mode, simply ignore the line if
5040  // we failed to read a matrix entry.
5041  if (istr.fail() && tolerant) {
5042  break;
5043  }
5044  }
5045  // In tolerant mode, we simply let pass through whatever
5046  // data we got.
5047  TEUCHOS_TEST_FOR_EXCEPTION(
5048  ! tolerant && istr.fail(), std::runtime_error,
5049  "Failed to read matrix data from line " << lineNumber
5050  << " of the Matrix Market file.");
5051 
5052  // Assign val = ST(real, imag).
5053  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5054 
5055  curRow = count % numRows;
5056  curCol = count / numRows;
5057  X_view[curRow + curCol*stride] = val;
5058  ++count;
5059  } // if not a comment line
5060  } // while there are still lines in the file, get the next one
5061 
5062  TEUCHOS_TEST_FOR_EXCEPTION(
5063  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5064  std::runtime_error,
5065  "The Matrix Market metadata reports that the dense matrix is "
5066  << numRows << " x " << numCols << ", and thus has "
5067  << numRows*numCols << " total entries, but we only found " << count
5068  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5069  } catch (std::exception& e) {
5070  exMsg << e.what ();
5071  localReadDataSuccess = 0;
5072  }
5073  } // if (myRank == 0)
5074 
5075  if (debug) {
5076  *err << myRank << ": readVectorImpl: done reading data" << endl;
5077  }
5078 
5079  // Synchronize on whether Proc 0 successfully read the data.
5080  int globalReadDataSuccess = localReadDataSuccess;
5081  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5082  TEUCHOS_TEST_FOR_EXCEPTION(
5083  globalReadDataSuccess == 0, std::runtime_error,
5084  "Failed to read the multivector's data: " << exMsg.str ());
5085 
5086  // If there's only one MPI process and the user didn't supply
5087  // a Map (i.e., pMap is null), we're done. Set pMap to the
5088  // Map used to distribute X, and return X.
5089  if (comm->getSize () == 1 && map.is_null ()) {
5090  map = proc0Map;
5091  if (! err.is_null ()) {
5092  err->popTab ();
5093  }
5094  if (debug) {
5095  *err << myRank << ": readVectorImpl: done" << endl;
5096  }
5097  if (! err.is_null ()) {
5098  err->popTab ();
5099  }
5100  return X;
5101  }
5102 
5103  if (debug) {
5104  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5105  }
5106 
5107  // Make a multivector Y with the distributed map pMap.
5108  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5109 
5110  if (debug) {
5111  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5112  }
5113 
5114  // Make an Export object that will export X to Y. First
5115  // argument is the source map, second argument is the target
5116  // map.
5117  Export<LO, GO, NT> exporter (proc0Map, map, err);
5118 
5119  if (debug) {
5120  *err << myRank << ": readVectorImpl: Exporting" << endl;
5121  }
5122  // Export X into Y.
5123  Y->doExport (*X, exporter, INSERT);
5124 
5125  if (! err.is_null ()) {
5126  err->popTab ();
5127  }
5128  if (debug) {
5129  *err << myRank << ": readVectorImpl: done" << endl;
5130  }
5131  if (! err.is_null ()) {
5132  err->popTab ();
5133  }
5134 
5135  // Y is distributed over all process(es) in the communicator.
5136  return Y;
5137  }
5138 
5139  public:
5159  static Teuchos::RCP<const map_type>
5160  readMap (std::istream& in,
5161  const Teuchos::RCP<const comm_type>& comm,
5162  const bool tolerant=false,
5163  const bool debug=false)
5164  {
5165  Teuchos::RCP<Teuchos::FancyOStream> err =
5166  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5167  return readMap (in, comm, err, tolerant, debug);
5168  }
5169 
5170 
5196  static Teuchos::RCP<const map_type>
5197  readMap (std::istream& in,
5198  const Teuchos::RCP<const comm_type>& comm,
5199  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5200  const bool tolerant=false,
5201  const bool debug=false)
5202  {
5203  using Teuchos::arcp;
5204  using Teuchos::Array;
5205  using Teuchos::ArrayRCP;
5206  using Teuchos::as;
5207  using Teuchos::broadcast;
5208  using Teuchos::Comm;
5209  using Teuchos::CommRequest;
5210  using Teuchos::inOutArg;
5211  using Teuchos::ireceive;
5212  using Teuchos::outArg;
5213  using Teuchos::RCP;
5214  using Teuchos::receive;
5215  using Teuchos::reduceAll;
5216  using Teuchos::REDUCE_MIN;
5217  using Teuchos::isend;
5218  using Teuchos::SerialComm;
5219  using Teuchos::toString;
5220  using Teuchos::wait;
5221  using std::endl;
5222  typedef Tpetra::global_size_t GST;
5223  typedef ptrdiff_t int_type; // Can hold int and GO
5224  typedef local_ordinal_type LO;
5225  typedef global_ordinal_type GO;
5226  typedef node_type NT;
5228 
5229  const int numProcs = comm->getSize ();
5230  const int myRank = comm->getRank ();
5231 
5232  if (err.is_null ()) {
5233  err->pushTab ();
5234  }
5235  if (debug) {
5236  std::ostringstream os;
5237  os << myRank << ": readMap: " << endl;
5238  *err << os.str ();
5239  }
5240  if (err.is_null ()) {
5241  err->pushTab ();
5242  }
5243 
5244  // Tag for receive-size / send-size messages. writeMap used
5245  // tags 1337 and 1338; we count up from there.
5246  const int sizeTag = 1339;
5247  // Tag for receive-data / send-data messages.
5248  const int dataTag = 1340;
5249 
5250  // These are for sends on Process 0, and for receives on all
5251  // other processes. sizeReq is for the {receive,send}-size
5252  // message, and dataReq is for the message containing the
5253  // actual GIDs to belong to the receiving process.
5254  RCP<CommRequest<int> > sizeReq;
5255  RCP<CommRequest<int> > dataReq;
5256 
5257  // Each process will have to receive the number of GIDs to
5258  // expect. Thus, we can post the receives now, and cancel
5259  // them if something should go wrong in the meantime.
5260  ArrayRCP<int_type> numGidsToRecv (1);
5261  numGidsToRecv[0] = 0;
5262  if (myRank != 0) {
5263  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5264  }
5265 
5266  int readSuccess = 1;
5267  std::ostringstream exMsg;
5268  RCP<MV> data; // Will only be valid on Proc 0
5269  if (myRank == 0) {
5270  // If we want to reuse readDenseImpl, we have to make a
5271  // communicator that only contains Proc 0. Otherwise,
5272  // readDenseImpl will redistribute the data to all
5273  // processes. While we eventually want that, neither we nor
5274  // readDenseImpl know the correct Map to use at the moment.
5275  // That depends on the second column of the multivector.
5276  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5277  try {
5278  RCP<const map_type> dataMap;
5279  // This is currently the only place where we use the
5280  // 'tolerant' argument. Later, if we want to be clever,
5281  // we could have tolerant mode allow PIDs out of order.
5282  data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug);
5283  (void) dataMap; // Silence "unused" warnings
5284  if (data.is_null ()) {
5285  readSuccess = 0;
5286  exMsg << "readDenseImpl() returned null." << endl;
5287  }
5288  } catch (std::exception& e) {
5289  readSuccess = 0;
5290  exMsg << e.what () << endl;
5291  }
5292  }
5293 
5294  // Map from PID to all the GIDs for that PID.
5295  // Only populated on Process 0.
5296  std::map<int, Array<GO> > pid2gids;
5297 
5298  // The index base must be the global minimum GID.
5299  // We will compute this on Process 0 and broadcast,
5300  // so that all processes can set up the Map.
5301  int_type globalNumGIDs = 0;
5302 
5303  // The index base must be the global minimum GID.
5304  // We will compute this on Process 0 and broadcast,
5305  // so that all processes can set up the Map.
5306  GO indexBase = 0;
5307 
5308  // Process 0: If the above read of the MultiVector succeeded,
5309  // extract the GIDs and PIDs into pid2gids, and find the
5310  // global min GID.
5311  if (myRank == 0 && readSuccess == 1) {
5312  if (data->getNumVectors () == 2) { // Map format 1.0
5313  ArrayRCP<const GO> GIDs = data->getData (0);
5314  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5315  globalNumGIDs = GIDs.size ();
5316 
5317  // Start computing the global min GID, while collecting
5318  // the GIDs for each PID.
5319  if (globalNumGIDs > 0) {
5320  const int pid = static_cast<int> (PIDs[0]);
5321 
5322  if (pid < 0 || pid >= numProcs) {
5323  readSuccess = 0;
5324  exMsg << "Tpetra::MatrixMarket::readMap: "
5325  << "Encountered invalid PID " << pid << "." << endl;
5326  }
5327  else {
5328  const GO gid = GIDs[0];
5329  pid2gids[pid].push_back (gid);
5330  indexBase = gid; // the current min GID
5331  }
5332  }
5333  if (readSuccess == 1) {
5334  // Collect the rest of the GIDs for each PID, and compute
5335  // the global min GID.
5336  for (size_type k = 1; k < globalNumGIDs; ++k) {
5337  const int pid = static_cast<int> (PIDs[k]);
5338  if (pid < 0 || pid >= numProcs) {
5339  readSuccess = 0;
5340  exMsg << "Tpetra::MatrixMarket::readMap: "
5341  << "Encountered invalid PID " << pid << "." << endl;
5342  }
5343  else {
5344  const int_type gid = GIDs[k];
5345  pid2gids[pid].push_back (gid);
5346  if (gid < indexBase) {
5347  indexBase = gid; // the current min GID
5348  }
5349  }
5350  }
5351  }
5352  }
5353  else if (data->getNumVectors () == 1) { // Map format 2.0
5354  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5355  readSuccess = 0;
5356  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5357  "wrong format (for Map format 2.0). The global number of rows "
5358  "in the MultiVector must be even (divisible by 2)." << endl;
5359  }
5360  else {
5361  ArrayRCP<const GO> theData = data->getData (0);
5362  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5363  static_cast<GO> (2);
5364 
5365  // Start computing the global min GID, while
5366  // collecting the GIDs for each PID.
5367  if (globalNumGIDs > 0) {
5368  const int pid = static_cast<int> (theData[1]);
5369  if (pid < 0 || pid >= numProcs) {
5370  readSuccess = 0;
5371  exMsg << "Tpetra::MatrixMarket::readMap: "
5372  << "Encountered invalid PID " << pid << "." << endl;
5373  }
5374  else {
5375  const GO gid = theData[0];
5376  pid2gids[pid].push_back (gid);
5377  indexBase = gid; // the current min GID
5378  }
5379  }
5380  // Collect the rest of the GIDs for each PID, and
5381  // compute the global min GID.
5382  for (int_type k = 1; k < globalNumGIDs; ++k) {
5383  const int pid = static_cast<int> (theData[2*k + 1]);
5384  if (pid < 0 || pid >= numProcs) {
5385  readSuccess = 0;
5386  exMsg << "Tpetra::MatrixMarket::readMap: "
5387  << "Encountered invalid PID " << pid << "." << endl;
5388  }
5389  else {
5390  const GO gid = theData[2*k];
5391  pid2gids[pid].push_back (gid);
5392  if (gid < indexBase) {
5393  indexBase = gid; // the current min GID
5394  }
5395  }
5396  } // for each GID
5397  } // if the amount of data is correct
5398  }
5399  else {
5400  readSuccess = 0;
5401  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5402  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5403  "the old Map format 1.0).";
5404  }
5405  } // myRank is zero
5406 
5407  // Broadcast the indexBase, the global number of GIDs, and the
5408  // current success status. Use int_type for all of these.
5409  {
5410  int_type readResults[3];
5411  readResults[0] = static_cast<int_type> (indexBase);
5412  readResults[1] = static_cast<int_type> (globalNumGIDs);
5413  readResults[2] = static_cast<int_type> (readSuccess);
5414  broadcast<int, int_type> (*comm, 0, 3, readResults);
5415 
5416  indexBase = static_cast<GO> (readResults[0]);
5417  globalNumGIDs = static_cast<int_type> (readResults[1]);
5418  readSuccess = static_cast<int> (readResults[2]);
5419  }
5420 
5421  // Unwinding the stack will invoke sizeReq's destructor, which
5422  // will cancel the receive-size request on all processes that
5423  // posted it.
5424  TEUCHOS_TEST_FOR_EXCEPTION(
5425  readSuccess != 1, std::runtime_error,
5426  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5427  "following exception message: " << exMsg.str ());
5428 
5429  if (myRank == 0) {
5430  // Proc 0: Send each process' number of GIDs to that process.
5431  for (int p = 1; p < numProcs; ++p) {
5432  ArrayRCP<int_type> numGidsToSend (1);
5433 
5434  auto it = pid2gids.find (p);
5435  if (it == pid2gids.end ()) {
5436  numGidsToSend[0] = 0;
5437  } else {
5438  numGidsToSend[0] = it->second.size ();
5439  }
5440  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5441  wait<int> (*comm, outArg (sizeReq));
5442  }
5443  }
5444  else {
5445  // Wait on the receive-size message to finish.
5446  wait<int> (*comm, outArg (sizeReq));
5447  }
5448 
5449  // Allocate / get the array for my GIDs.
5450  // Only Process 0 will have its actual GIDs at this point.
5451  ArrayRCP<GO> myGids;
5452  int_type myNumGids = 0;
5453  if (myRank == 0) {
5454  GO* myGidsRaw = NULL;
5455 
5456  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5457  if (it != pid2gids.end ()) {
5458  myGidsRaw = it->second.getRawPtr ();
5459  myNumGids = it->second.size ();
5460  // Nonowning ArrayRCP just views the Array.
5461  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5462  }
5463  }
5464  else { // myRank != 0
5465  myNumGids = numGidsToRecv[0];
5466  myGids = arcp<GO> (myNumGids);
5467  }
5468 
5469  if (myRank != 0) {
5470  // Post receive for data, now that we know how much data we
5471  // will receive. Only post receive if my process actually
5472  // has nonzero GIDs.
5473  if (myNumGids > 0) {
5474  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5475  }
5476  }
5477 
5478  for (int p = 1; p < numProcs; ++p) {
5479  if (myRank == 0) {
5480  ArrayRCP<GO> sendGids; // to send to Process p
5481  GO* sendGidsRaw = NULL;
5482  int_type numSendGids = 0;
5483 
5484  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5485  if (it != pid2gids.end ()) {
5486  numSendGids = it->second.size ();
5487  sendGidsRaw = it->second.getRawPtr ();
5488  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5489  }
5490  // Only send if that process actually has nonzero GIDs.
5491  if (numSendGids > 0) {
5492  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5493  }
5494  wait<int> (*comm, outArg (dataReq));
5495  }
5496  else if (myRank == p) {
5497  // Wait on my receive of GIDs to finish.
5498  wait<int> (*comm, outArg (dataReq));
5499  }
5500  } // for each process rank p in 1, 2, ..., numProcs-1
5501 
5502  if (debug) {
5503  std::ostringstream os;
5504  os << myRank << ": readMap: creating Map" << endl;
5505  *err << os.str ();
5506  }
5507  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5508  RCP<const map_type> newMap;
5509 
5510  // Create the Map; test whether the constructor threw. This
5511  // avoids deadlock and makes error reporting more readable.
5512 
5513  int lclSuccess = 1;
5514  int gblSuccess = 0; // output argument
5515  std::ostringstream errStrm;
5516  try {
5517  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5518  }
5519  catch (std::exception& e) {
5520  lclSuccess = 0;
5521  errStrm << "Process " << comm->getRank () << " threw an exception: "
5522  << e.what () << std::endl;
5523  }
5524  catch (...) {
5525  lclSuccess = 0;
5526  errStrm << "Process " << comm->getRank () << " threw an exception "
5527  "not a subclass of std::exception" << std::endl;
5528  }
5529  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5530  lclSuccess, Teuchos::outArg (gblSuccess));
5531  if (gblSuccess != 1) {
5532  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5533  }
5534  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5535 
5536  if (err.is_null ()) {
5537  err->popTab ();
5538  }
5539  if (debug) {
5540  std::ostringstream os;
5541  os << myRank << ": readMap: done" << endl;
5542  *err << os.str ();
5543  }
5544  if (err.is_null ()) {
5545  err->popTab ();
5546  }
5547  return newMap;
5548  }
5549 
5550 
5551  private:
5552 
5563  static int
5564  encodeDataType (const std::string& dataType)
5565  {
5566  if (dataType == "real" || dataType == "integer") {
5567  return 0;
5568  } else if (dataType == "complex") {
5569  return 1;
5570  } else if (dataType == "pattern") {
5571  return 2;
5572  } else {
5573  // We should never get here, since Banner validates the
5574  // reported data type and ensures it is one of the accepted
5575  // values.
5576  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5577  "Unrecognized Matrix Market data type \"" << dataType
5578  << "\". We should never get here. "
5579  "Please report this bug to the Tpetra developers.");
5580  }
5581  }
5582  };
5583 
5612  template<class SparseMatrixType>
5613  class Writer {
5614  public:
5616  typedef SparseMatrixType sparse_matrix_type;
5617  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5618 
5620  typedef typename SparseMatrixType::scalar_type scalar_type;
5622  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5628  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5630  typedef typename SparseMatrixType::node_type node_type;
5631 
5633  typedef MultiVector<scalar_type,
5641 
5644 
5676  static void
5677  writeSparseFile (const std::string& filename,
5678  const sparse_matrix_type& matrix,
5679  const std::string& matrixName,
5680  const std::string& matrixDescription,
5681  const bool debug=false)
5682  {
5683  Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
5684  TEUCHOS_TEST_FOR_EXCEPTION
5685  (comm.is_null (), std::invalid_argument,
5686  "The input matrix's communicator (Teuchos::Comm object) is null.");
5687  const int myRank = comm->getRank ();
5688  std::ofstream out;
5689 
5690  // Only open the file on Rank 0.
5691  if (myRank == 0) {
5692  out.open (filename.c_str ());
5693  }
5694  writeSparse (out, matrix, matrixName, matrixDescription, debug);
5695  // We can rely on the destructor of the output stream to close
5696  // the file on scope exit, even if writeSparse() throws an
5697  // exception.
5698  }
5699 
5701  static void
5702  writeSparseFile (const std::string& filename,
5703  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5704  const std::string& matrixName,
5705  const std::string& matrixDescription,
5706  const bool debug=false)
5707  {
5708  TEUCHOS_TEST_FOR_EXCEPTION
5709  (pMatrix.is_null (), std::invalid_argument,
5710  "The input matrix is null.");
5711  writeSparseFile (filename, *pMatrix, matrixName,
5712  matrixDescription, debug);
5713  }
5714 
5734  static void
5735  writeSparseFile (const std::string& filename,
5736  const sparse_matrix_type& matrix,
5737  const bool debug=false)
5738  {
5739  writeSparseFile (filename, matrix, "", "", debug);
5740  }
5741 
5743  static void
5744  writeSparseFile (const std::string& filename,
5745  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5746  const bool debug=false)
5747  {
5748  writeSparseFile (filename, *pMatrix, "", "", debug);
5749  }
5750 
5781  static void
5782  writeSparse (std::ostream& out,
5783  const sparse_matrix_type& matrix,
5784  const std::string& matrixName,
5785  const std::string& matrixDescription,
5786  const bool debug=false)
5787  {
5788  using Teuchos::ArrayView;
5789  using Teuchos::Comm;
5790  using Teuchos::FancyOStream;
5791  using Teuchos::getFancyOStream;
5792  using Teuchos::null;
5793  using Teuchos::RCP;
5794  using Teuchos::rcpFromRef;
5795  using std::cerr;
5796  using std::endl;
5797  using ST = scalar_type;
5798  using LO = local_ordinal_type;
5799  using GO = global_ordinal_type;
5800  using STS = typename Teuchos::ScalarTraits<ST>;
5801 
5802  // Make the output stream write floating-point numbers in
5803  // scientific notation. It will politely put the output
5804  // stream back to its state on input, when this scope
5805  // terminates.
5806  Teuchos::SetScientific<ST> sci (out);
5807 
5808  // Get the matrix's communicator.
5809  RCP<const Comm<int> > comm = matrix.getComm ();
5810  TEUCHOS_TEST_FOR_EXCEPTION(
5811  comm.is_null (), std::invalid_argument,
5812  "The input matrix's communicator (Teuchos::Comm object) is null.");
5813  const int myRank = comm->getRank ();
5814 
5815  // Optionally, make a stream for debugging output.
5816  RCP<FancyOStream> err =
5817  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
5818  if (debug) {
5819  std::ostringstream os;
5820  os << myRank << ": writeSparse" << endl;
5821  *err << os.str ();
5822  comm->barrier ();
5823  os << "-- " << myRank << ": past barrier" << endl;
5824  *err << os.str ();
5825  }
5826 
5827  // Whether to print debugging output to stderr.
5828  const bool debugPrint = debug && myRank == 0;
5829 
5830  RCP<const map_type> rowMap = matrix.getRowMap ();
5831  RCP<const map_type> colMap = matrix.getColMap ();
5832  RCP<const map_type> domainMap = matrix.getDomainMap ();
5833  RCP<const map_type> rangeMap = matrix.getRangeMap ();
5834 
5835  const global_size_t numRows = rangeMap->getGlobalNumElements ();
5836  const global_size_t numCols = domainMap->getGlobalNumElements ();
5837 
5838  if (debug && myRank == 0) {
5839  std::ostringstream os;
5840  os << "-- Input sparse matrix is:"
5841  << "---- " << numRows << " x " << numCols << endl
5842  << "---- "
5843  << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
5844  << " indexed." << endl
5845  << "---- Its row map has " << rowMap->getGlobalNumElements ()
5846  << " elements." << endl
5847  << "---- Its col map has " << colMap->getGlobalNumElements ()
5848  << " elements." << endl;
5849  *err << os.str ();
5850  }
5851  // Make the "gather" row map, where Proc 0 owns all rows and
5852  // the other procs own no rows.
5853  const size_t localNumRows = (myRank == 0) ? numRows : 0;
5854  if (debug) {
5855  std::ostringstream os;
5856  os << "-- " << myRank << ": making gatherRowMap" << endl;
5857  *err << os.str ();
5858  }
5859  RCP<const map_type> gatherRowMap =
5860  Details::computeGatherMap (rowMap, err, debug);
5861 
5862  // Since the matrix may in general be non-square, we need to
5863  // make a column map as well. In this case, the column map
5864  // contains all the columns of the original matrix, because we
5865  // are gathering the whole matrix onto Proc 0. We call
5866  // computeGatherMap to preserve the original order of column
5867  // indices over all the processes.
5868  const size_t localNumCols = (myRank == 0) ? numCols : 0;
5869  RCP<const map_type> gatherColMap =
5870  Details::computeGatherMap (colMap, err, debug);
5871 
5872  // Current map is the source map, gather map is the target map.
5873  typedef Import<LO, GO, node_type> import_type;
5874  import_type importer (rowMap, gatherRowMap);
5875 
5876  // Create a new CrsMatrix to hold the result of the import.
5877  // The constructor needs a column map as well as a row map,
5878  // for the case that the matrix is not square.
5879  RCP<sparse_matrix_type> newMatrix =
5880  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
5881  static_cast<size_t> (0)));
5882  // Import the sparse matrix onto Proc 0.
5883  newMatrix->doImport (matrix, importer, INSERT);
5884 
5885  // fillComplete() needs the domain and range maps for the case
5886  // that the matrix is not square.
5887  {
5888  RCP<const map_type> gatherDomainMap =
5889  rcp (new map_type (numCols, localNumCols,
5890  domainMap->getIndexBase (),
5891  comm));
5892  RCP<const map_type> gatherRangeMap =
5893  rcp (new map_type (numRows, localNumRows,
5894  rangeMap->getIndexBase (),
5895  comm));
5896  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
5897  }
5898 
5899  if (debugPrint) {
5900  cerr << "-- Output sparse matrix is:"
5901  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
5902  << " x "
5903  << newMatrix->getDomainMap ()->getGlobalNumElements ()
5904  << " with "
5905  << newMatrix->getGlobalNumEntries () << " entries;" << endl
5906  << "---- "
5907  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
5908  << " indexed." << endl
5909  << "---- Its row map has "
5910  << newMatrix->getRowMap ()->getGlobalNumElements ()
5911  << " elements, with index base "
5912  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
5913  << "---- Its col map has "
5914  << newMatrix->getColMap ()->getGlobalNumElements ()
5915  << " elements, with index base "
5916  << newMatrix->getColMap ()->getIndexBase () << "." << endl
5917  << "---- Element count of output matrix's column Map may differ "
5918  << "from that of the input matrix's column Map, if some columns "
5919  << "of the matrix contain no entries." << endl;
5920  }
5921 
5922  //
5923  // Print the metadata and the matrix entries on Rank 0.
5924  //
5925  if (myRank == 0) {
5926  // Print the Matrix Market banner line. CrsMatrix stores
5927  // data nonsymmetrically ("general"). This implies that
5928  // readSparse() on a symmetrically stored input file,
5929  // followed by writeSparse() on the resulting sparse matrix,
5930  // will result in an output file with a different banner
5931  // line than the original input file.
5932  out << "%%MatrixMarket matrix coordinate "
5933  << (STS::isComplex ? "complex" : "real")
5934  << " general" << endl;
5935 
5936  // Print comments (the matrix name and / or description).
5937  if (matrixName != "") {
5938  printAsComment (out, matrixName);
5939  }
5940  if (matrixDescription != "") {
5941  printAsComment (out, matrixDescription);
5942  }
5943 
5944  // Print the Matrix Market header (# rows, # columns, #
5945  // nonzeros). Use the range resp. domain map for the number
5946  // of rows resp. columns, since Tpetra::CrsMatrix uses the
5947  // column map for the number of columns. That only
5948  // corresponds to the "linear-algebraic" number of columns
5949  // when the column map is uniquely owned (a.k.a. one-to-one),
5950  // which only happens if the matrix is (block) diagonal.
5951  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
5952  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
5953  << newMatrix->getGlobalNumEntries () << endl;
5954 
5955  // The Matrix Market format expects one-based row and column
5956  // indices. We'll convert the indices on output from
5957  // whatever index base they use to one-based indices.
5958  const GO rowIndexBase = gatherRowMap->getIndexBase ();
5959  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
5960  //
5961  // Print the entries of the matrix.
5962  //
5963  // newMatrix can never be globally indexed, since we called
5964  // fillComplete() on it. We include code for both cases
5965  // (globally or locally indexed) just in case that ever
5966  // changes.
5967  if (newMatrix->isGloballyIndexed()) {
5968  // We know that the "gather" row Map is contiguous, so we
5969  // don't need to get the list of GIDs.
5970  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
5971  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
5972  for (GO globalRowIndex = minAllGlobalIndex;
5973  globalRowIndex <= maxAllGlobalIndex; // inclusive range
5974  ++globalRowIndex) {
5975  ArrayView<const GO> ind;
5976  ArrayView<const ST> val;
5977  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
5978  auto indIter = ind.begin ();
5979  auto valIter = val.begin ();
5980  for (; indIter != ind.end() && valIter != val.end();
5981  ++indIter, ++valIter) {
5982  const GO globalColIndex = *indIter;
5983  // Convert row and column indices to 1-based.
5984  // This works because the global index type is signed.
5985  out << (globalRowIndex + 1 - rowIndexBase) << " "
5986  << (globalColIndex + 1 - colIndexBase) << " ";
5987  if (STS::isComplex) {
5988  out << STS::real (*valIter) << " " << STS::imag (*valIter);
5989  } else {
5990  out << *valIter;
5991  }
5992  out << endl;
5993  } // For each entry in the current row
5994  } // For each row of the "gather" matrix
5995  }
5996  else { // newMatrix is locally indexed
5997  using OTG = Teuchos::OrdinalTraits<GO>;
5998  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
5999  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6000  ++localRowIndex) {
6001  // Convert from local to global row index.
6002  const GO globalRowIndex =
6003  gatherRowMap->getGlobalElement (localRowIndex);
6004  TEUCHOS_TEST_FOR_EXCEPTION(
6005  globalRowIndex == OTG::invalid(), std::logic_error,
6006  "Failed to convert the supposed local row index "
6007  << localRowIndex << " into a global row index. "
6008  "Please report this bug to the Tpetra developers.");
6009  ArrayView<const LO> ind;
6010  ArrayView<const ST> val;
6011  newMatrix->getLocalRowView (localRowIndex, ind, val);
6012  auto indIter = ind.begin ();
6013  auto valIter = val.begin ();
6014  for (; indIter != ind.end() && valIter != val.end();
6015  ++indIter, ++valIter) {
6016  // Convert the column index from local to global.
6017  const GO globalColIndex =
6018  newMatrix->getColMap()->getGlobalElement (*indIter);
6019  TEUCHOS_TEST_FOR_EXCEPTION(
6020  globalColIndex == OTG::invalid(), std::logic_error,
6021  "On local row " << localRowIndex << " of the sparse matrix: "
6022  "Failed to convert the supposed local column index "
6023  << *indIter << " into a global column index. Please report "
6024  "this bug to the Tpetra developers.");
6025  // Convert row and column indices to 1-based.
6026  // This works because the global index type is signed.
6027  out << (globalRowIndex + 1 - rowIndexBase) << " "
6028  << (globalColIndex + 1 - colIndexBase) << " ";
6029  if (STS::isComplex) {
6030  out << STS::real (*valIter) << " " << STS::imag (*valIter);
6031  } else {
6032  out << *valIter;
6033  }
6034  out << endl;
6035  } // For each entry in the current row
6036  } // For each row of the "gather" matrix
6037  } // Whether the "gather" matrix is locally or globally indexed
6038  } // If my process' rank is 0
6039  }
6040 
6042  static void
6043  writeSparse (std::ostream& out,
6044  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6045  const std::string& matrixName,
6046  const std::string& matrixDescription,
6047  const bool debug=false)
6048  {
6049  TEUCHOS_TEST_FOR_EXCEPTION
6050  (pMatrix.is_null (), std::invalid_argument,
6051  "The input matrix is null.");
6052  writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6053  }
6054 
6085  static void
6086  writeSparseGraph (std::ostream& out,
6087  const crs_graph_type& graph,
6088  const std::string& graphName,
6089  const std::string& graphDescription,
6090  const bool debug=false)
6091  {
6092  using Teuchos::ArrayView;
6093  using Teuchos::Comm;
6094  using Teuchos::FancyOStream;
6095  using Teuchos::getFancyOStream;
6096  using Teuchos::null;
6097  using Teuchos::RCP;
6098  using Teuchos::rcpFromRef;
6099  using std::cerr;
6100  using std::endl;
6101  typedef local_ordinal_type LO;
6102  typedef global_ordinal_type GO;
6103 
6104  // Get the graph's communicator. Processes on which the
6105  // graph's Map or communicator is null don't participate in
6106  // this operation. This function shouldn't even be called on
6107  // those processes.
6108  auto rowMap = graph.getRowMap ();
6109  if (rowMap.is_null ()) {
6110  return;
6111  }
6112  auto comm = rowMap->getComm ();
6113  if (comm.is_null ()) {
6114  return;
6115  }
6116  const int myRank = comm->getRank ();
6117 
6118  // Optionally, make a stream for debugging output.
6119  RCP<FancyOStream> err =
6120  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6121  if (debug) {
6122  std::ostringstream os;
6123  os << myRank << ": writeSparseGraph" << endl;
6124  *err << os.str ();
6125  comm->barrier ();
6126  os << "-- " << myRank << ": past barrier" << endl;
6127  *err << os.str ();
6128  }
6129 
6130  // Whether to print debugging output to stderr.
6131  const bool debugPrint = debug && myRank == 0;
6132 
6133  // We've already gotten the rowMap above.
6134  auto colMap = graph.getColMap ();
6135  auto domainMap = graph.getDomainMap ();
6136  auto rangeMap = graph.getRangeMap ();
6137 
6138  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6139  const global_size_t numCols = domainMap->getGlobalNumElements ();
6140 
6141  if (debug && myRank == 0) {
6142  std::ostringstream os;
6143  os << "-- Input sparse graph is:"
6144  << "---- " << numRows << " x " << numCols << " with "
6145  << graph.getGlobalNumEntries () << " entries;" << endl
6146  << "---- "
6147  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6148  << " indexed." << endl
6149  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6150  << " elements." << endl
6151  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6152  << " elements." << endl;
6153  *err << os.str ();
6154  }
6155  // Make the "gather" row map, where Proc 0 owns all rows and
6156  // the other procs own no rows.
6157  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6158  if (debug) {
6159  std::ostringstream os;
6160  os << "-- " << myRank << ": making gatherRowMap" << endl;
6161  *err << os.str ();
6162  }
6163  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6164 
6165  // Since the graph may in general be non-square, we need to
6166  // make a column map as well. In this case, the column map
6167  // contains all the columns of the original graph, because we
6168  // are gathering the whole graph onto Proc 0. We call
6169  // computeGatherMap to preserve the original order of column
6170  // indices over all the processes.
6171  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6172  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6173 
6174  // Current map is the source map, gather map is the target map.
6175  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6176 
6177  // Create a new CrsGraph to hold the result of the import.
6178  // The constructor needs a column map as well as a row map,
6179  // for the case that the graph is not square.
6180  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6181  static_cast<size_t> (0));
6182  // Import the sparse graph onto Proc 0.
6183  newGraph.doImport (graph, importer, INSERT);
6184 
6185  // fillComplete() needs the domain and range maps for the case
6186  // that the graph is not square.
6187  {
6188  RCP<const map_type> gatherDomainMap =
6189  rcp (new map_type (numCols, localNumCols,
6190  domainMap->getIndexBase (),
6191  comm));
6192  RCP<const map_type> gatherRangeMap =
6193  rcp (new map_type (numRows, localNumRows,
6194  rangeMap->getIndexBase (),
6195  comm));
6196  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6197  }
6198 
6199  if (debugPrint) {
6200  cerr << "-- Output sparse graph is:"
6201  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6202  << " x "
6203  << newGraph.getDomainMap ()->getGlobalNumElements ()
6204  << " with "
6205  << newGraph.getGlobalNumEntries () << " entries;" << endl
6206  << "---- "
6207  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6208  << " indexed." << endl
6209  << "---- Its row map has "
6210  << newGraph.getRowMap ()->getGlobalNumElements ()
6211  << " elements, with index base "
6212  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6213  << "---- Its col map has "
6214  << newGraph.getColMap ()->getGlobalNumElements ()
6215  << " elements, with index base "
6216  << newGraph.getColMap ()->getIndexBase () << "." << endl
6217  << "---- Element count of output graph's column Map may differ "
6218  << "from that of the input matrix's column Map, if some columns "
6219  << "of the matrix contain no entries." << endl;
6220  }
6221 
6222  //
6223  // Print the metadata and the graph entries on Process 0 of
6224  // the graph's communicator.
6225  //
6226  if (myRank == 0) {
6227  // Print the Matrix Market banner line. CrsGraph stores
6228  // data nonsymmetrically ("general"). This implies that
6229  // readSparseGraph() on a symmetrically stored input file,
6230  // followed by writeSparseGraph() on the resulting sparse
6231  // graph, will result in an output file with a different
6232  // banner line than the original input file.
6233  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6234 
6235  // Print comments (the graph name and / or description).
6236  if (graphName != "") {
6237  printAsComment (out, graphName);
6238  }
6239  if (graphDescription != "") {
6240  printAsComment (out, graphDescription);
6241  }
6242 
6243  // Print the Matrix Market header (# rows, # columns, #
6244  // stored entries). Use the range resp. domain map for the
6245  // number of rows resp. columns, since Tpetra::CrsGraph uses
6246  // the column map for the number of columns. That only
6247  // corresponds to the "linear-algebraic" number of columns
6248  // when the column map is uniquely owned
6249  // (a.k.a. one-to-one), which only happens if the graph is
6250  // block diagonal (one block per process).
6251  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6252  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6253  << newGraph.getGlobalNumEntries () << endl;
6254 
6255  // The Matrix Market format expects one-based row and column
6256  // indices. We'll convert the indices on output from
6257  // whatever index base they use to one-based indices.
6258  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6259  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6260  //
6261  // Print the entries of the graph.
6262  //
6263  // newGraph can never be globally indexed, since we called
6264  // fillComplete() on it. We include code for both cases
6265  // (globally or locally indexed) just in case that ever
6266  // changes.
6267  if (newGraph.isGloballyIndexed ()) {
6268  // We know that the "gather" row Map is contiguous, so we
6269  // don't need to get the list of GIDs.
6270  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6271  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6272  for (GO globalRowIndex = minAllGlobalIndex;
6273  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6274  ++globalRowIndex) {
6275  ArrayView<const GO> ind;
6276  newGraph.getGlobalRowView (globalRowIndex, ind);
6277  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6278  const GO globalColIndex = *indIter;
6279  // Convert row and column indices to 1-based.
6280  // This works because the global index type is signed.
6281  out << (globalRowIndex + 1 - rowIndexBase) << " "
6282  << (globalColIndex + 1 - colIndexBase) << " ";
6283  out << endl;
6284  } // For each entry in the current row
6285  } // For each row of the "gather" graph
6286  }
6287  else { // newGraph is locally indexed
6288  typedef Teuchos::OrdinalTraits<GO> OTG;
6289  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6290  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6291  ++localRowIndex) {
6292  // Convert from local to global row index.
6293  const GO globalRowIndex =
6294  gatherRowMap->getGlobalElement (localRowIndex);
6295  TEUCHOS_TEST_FOR_EXCEPTION
6296  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6297  "to convert the supposed local row index " << localRowIndex <<
6298  " into a global row index. Please report this bug to the "
6299  "Tpetra developers.");
6300  ArrayView<const LO> ind;
6301  newGraph.getLocalRowView (localRowIndex, ind);
6302  for (auto indIter = ind.begin (); indIter != ind.end (); ++indIter) {
6303  // Convert the column index from local to global.
6304  const GO globalColIndex =
6305  newGraph.getColMap ()->getGlobalElement (*indIter);
6306  TEUCHOS_TEST_FOR_EXCEPTION(
6307  globalColIndex == OTG::invalid(), std::logic_error,
6308  "On local row " << localRowIndex << " of the sparse graph: "
6309  "Failed to convert the supposed local column index "
6310  << *indIter << " into a global column index. Please report "
6311  "this bug to the Tpetra developers.");
6312  // Convert row and column indices to 1-based.
6313  // This works because the global index type is signed.
6314  out << (globalRowIndex + 1 - rowIndexBase) << " "
6315  << (globalColIndex + 1 - colIndexBase) << " ";
6316  out << endl;
6317  } // For each entry in the current row
6318  } // For each row of the "gather" graph
6319  } // Whether the "gather" graph is locally or globally indexed
6320  } // If my process' rank is 0
6321  }
6322 
6328  static void
6329  writeSparseGraph (std::ostream& out,
6330  const crs_graph_type& graph,
6331  const bool debug=false)
6332  {
6333  writeSparseGraph (out, graph, "", "", debug);
6334  }
6335 
6370  static void
6371  writeSparseGraphFile (const std::string& filename,
6372  const crs_graph_type& graph,
6373  const std::string& graphName,
6374  const std::string& graphDescription,
6375  const bool debug=false)
6376  {
6377  auto comm = graph.getComm ();
6378  if (comm.is_null ()) {
6379  // Processes on which the communicator is null shouldn't
6380  // even call this function. The convention is that
6381  // processes on which the object's communicator is null do
6382  // not participate in collective operations involving the
6383  // object.
6384  return;
6385  }
6386  const int myRank = comm->getRank ();
6387  std::ofstream out;
6388 
6389  // Only open the file on Process 0.
6390  if (myRank == 0) {
6391  out.open (filename.c_str ());
6392  }
6393  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6394  // We can rely on the destructor of the output stream to close
6395  // the file on scope exit, even if writeSparseGraph() throws
6396  // an exception.
6397  }
6398 
6403  static void
6404  writeSparseGraphFile (const std::string& filename,
6405  const crs_graph_type& graph,
6406  const bool debug=false)
6407  {
6408  writeSparseGraphFile (filename, graph, "", "", debug);
6409  }
6410 
6419  static void
6420  writeSparseGraphFile (const std::string& filename,
6421  const Teuchos::RCP<const crs_graph_type>& pGraph,
6422  const std::string& graphName,
6423  const std::string& graphDescription,
6424  const bool debug=false)
6425  {
6426  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6427  }
6428 
6438  static void
6439  writeSparseGraphFile (const std::string& filename,
6440  const Teuchos::RCP<const crs_graph_type>& pGraph,
6441  const bool debug=false)
6442  {
6443  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6444  }
6445 
6468  static void
6469  writeSparse (std::ostream& out,
6470  const sparse_matrix_type& matrix,
6471  const bool debug=false)
6472  {
6473  writeSparse (out, matrix, "", "", debug);
6474  }
6475 
6477  static void
6478  writeSparse (std::ostream& out,
6479  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6480  const bool debug=false)
6481  {
6482  writeSparse (out, *pMatrix, "", "", debug);
6483  }
6484 
6513  static void
6514  writeDenseFile (const std::string& filename,
6515  const multivector_type& X,
6516  const std::string& matrixName,
6517  const std::string& matrixDescription,
6518  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6519  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6520  {
6521  const int myRank = X.getMap ().is_null () ? 0 :
6522  (X.getMap ()->getComm ().is_null () ? 0 :
6523  X.getMap ()->getComm ()->getRank ());
6524  std::ofstream out;
6525 
6526  if (myRank == 0) { // Only open the file on Process 0.
6527  out.open (filename.c_str());
6528  }
6529 
6530  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6531  // We can rely on the destructor of the output stream to close
6532  // the file on scope exit, even if writeDense() throws an
6533  // exception.
6534  }
6535 
6541  static void
6542  writeDenseFile (const std::string& filename,
6543  const Teuchos::RCP<const multivector_type>& X,
6544  const std::string& matrixName,
6545  const std::string& matrixDescription,
6546  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6547  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6548  {
6549  TEUCHOS_TEST_FOR_EXCEPTION(
6550  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6551  "writeDenseFile: The input MultiVector X is null.");
6552  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6553  }
6554 
6560  static void
6561  writeDenseFile (const std::string& filename,
6562  const multivector_type& X,
6563  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6564  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6565  {
6566  writeDenseFile (filename, X, "", "", err, dbg);
6567  }
6568 
6574  static void
6575  writeDenseFile (const std::string& filename,
6576  const Teuchos::RCP<const multivector_type>& X,
6577  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6578  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6579  {
6580  TEUCHOS_TEST_FOR_EXCEPTION(
6581  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6582  "writeDenseFile: The input MultiVector X is null.");
6583  writeDenseFile (filename, *X, err, dbg);
6584  }
6585 
6586 
6617  static void
6618  writeDense (std::ostream& out,
6619  const multivector_type& X,
6620  const std::string& matrixName,
6621  const std::string& matrixDescription,
6622  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6623  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6624  {
6625  using Teuchos::Comm;
6626  using Teuchos::outArg;
6627  using Teuchos::REDUCE_MAX;
6628  using Teuchos::reduceAll;
6629  using Teuchos::RCP;
6630  using std::endl;
6631 
6632  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6633  Teuchos::null : X.getMap ()->getComm ();
6634  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6635 
6636  // If the caller provides a nonnull debug output stream, we
6637  // print debugging output to it. This is a local thing; we
6638  // don't have to check across processes.
6639  const bool debug = ! dbg.is_null ();
6640  if (debug) {
6641  dbg->pushTab ();
6642  std::ostringstream os;
6643  os << myRank << ": writeDense" << endl;
6644  *dbg << os.str ();
6645  dbg->pushTab ();
6646  }
6647  // Print the Matrix Market header.
6648  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6649 
6650  // Print each column one at a time. This is a (perhaps)
6651  // temporary fix for Bug 6288.
6652  const size_t numVecs = X.getNumVectors ();
6653  for (size_t j = 0; j < numVecs; ++j) {
6654  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6655  }
6656 
6657  if (debug) {
6658  dbg->popTab ();
6659  std::ostringstream os;
6660  os << myRank << ": writeDense: Done" << endl;
6661  *dbg << os.str ();
6662  dbg->popTab ();
6663  }
6664  }
6665 
6666  private:
6667 
6693  static void
6694  writeDenseHeader (std::ostream& out,
6695  const multivector_type& X,
6696  const std::string& matrixName,
6697  const std::string& matrixDescription,
6698  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6699  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6700  {
6701  using Teuchos::Comm;
6702  using Teuchos::outArg;
6703  using Teuchos::RCP;
6704  using Teuchos::REDUCE_MAX;
6705  using Teuchos::reduceAll;
6706  using std::endl;
6707  typedef Teuchos::ScalarTraits<scalar_type> STS;
6708  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
6709 
6710  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6711  Teuchos::null : X.getMap ()->getComm ();
6712  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6713  int lclErr = 0; // whether this MPI process has seen an error
6714  int gblErr = 0; // whether we know if some MPI process has seen an error
6715 
6716  // If the caller provides a nonnull debug output stream, we
6717  // print debugging output to it. This is a local thing; we
6718  // don't have to check across processes.
6719  const bool debug = ! dbg.is_null ();
6720 
6721  if (debug) {
6722  dbg->pushTab ();
6723  std::ostringstream os;
6724  os << myRank << ": writeDenseHeader" << endl;
6725  *dbg << os.str ();
6726  dbg->pushTab ();
6727  }
6728 
6729  //
6730  // Process 0: Write the MatrixMarket header.
6731  //
6732  if (myRank == 0) {
6733  try {
6734  // Print the Matrix Market header. MultiVector stores data
6735  // nonsymmetrically, hence "general" in the banner line.
6736  // Print first to a temporary string output stream, and then
6737  // write it to the main output stream, so that at least the
6738  // header output has transactional semantics. We can't
6739  // guarantee transactional semantics for the whole output,
6740  // since that would not be memory scalable. (This could be
6741  // done in the file system by using a temporary file; we
6742  // don't do this, but users could.)
6743  std::ostringstream hdr;
6744  {
6745  std::string dataType;
6746  if (STS::isComplex) {
6747  dataType = "complex";
6748  } else if (STS::isOrdinal) {
6749  dataType = "integer";
6750  } else {
6751  dataType = "real";
6752  }
6753  hdr << "%%MatrixMarket matrix array " << dataType << " general"
6754  << endl;
6755  }
6756 
6757  // Print comments (the matrix name and / or description).
6758  if (matrixName != "") {
6759  printAsComment (hdr, matrixName);
6760  }
6761  if (matrixDescription != "") {
6762  printAsComment (hdr, matrixDescription);
6763  }
6764  // Print the Matrix Market dimensions header for dense matrices.
6765  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
6766 
6767  // Write the MatrixMarket header to the output stream.
6768  out << hdr.str ();
6769  } catch (std::exception& e) {
6770  if (! err.is_null ()) {
6771  *err << prefix << "While writing the Matrix Market header, "
6772  "Process 0 threw an exception: " << e.what () << endl;
6773  }
6774  lclErr = 1;
6775  }
6776  } // if I am Process 0
6777 
6778  // Establish global agreement on the error state. It wouldn't
6779  // be good for other processes to keep going, if Process 0
6780  // finds out that it can't write to the given output stream.
6781  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
6782  TEUCHOS_TEST_FOR_EXCEPTION(
6783  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
6784  "which prevented this method from completing.");
6785 
6786  if (debug) {
6787  dbg->popTab ();
6788  *dbg << myRank << ": writeDenseHeader: Done" << endl;
6789  dbg->popTab ();
6790  }
6791  }
6792 
6810  static void
6811  writeDenseColumn (std::ostream& out,
6812  const multivector_type& X,
6813  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6814  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6815  {
6816  using Teuchos::arcp;
6817  using Teuchos::Array;
6818  using Teuchos::ArrayRCP;
6819  using Teuchos::ArrayView;
6820  using Teuchos::Comm;
6821  using Teuchos::CommRequest;
6822  using Teuchos::ireceive;
6823  using Teuchos::isend;
6824  using Teuchos::outArg;
6825  using Teuchos::REDUCE_MAX;
6826  using Teuchos::reduceAll;
6827  using Teuchos::RCP;
6828  using Teuchos::TypeNameTraits;
6829  using Teuchos::wait;
6830  using std::endl;
6831  typedef Teuchos::ScalarTraits<scalar_type> STS;
6832 
6833  const Comm<int>& comm = * (X.getMap ()->getComm ());
6834  const int myRank = comm.getRank ();
6835  const int numProcs = comm.getSize ();
6836  int lclErr = 0; // whether this MPI process has seen an error
6837  int gblErr = 0; // whether we know if some MPI process has seen an error
6838 
6839  // If the caller provides a nonnull debug output stream, we
6840  // print debugging output to it. This is a local thing; we
6841  // don't have to check across processes.
6842  const bool debug = ! dbg.is_null ();
6843 
6844  if (debug) {
6845  dbg->pushTab ();
6846  std::ostringstream os;
6847  os << myRank << ": writeDenseColumn" << endl;
6848  *dbg << os.str ();
6849  dbg->pushTab ();
6850  }
6851 
6852  // Make the output stream write floating-point numbers in
6853  // scientific notation. It will politely put the output
6854  // stream back to its state on input, when this scope
6855  // terminates.
6856  Teuchos::SetScientific<scalar_type> sci (out);
6857 
6858  const size_t myNumRows = X.getLocalLength ();
6859  const size_t numCols = X.getNumVectors ();
6860  // Use a different tag for the "size" messages than for the
6861  // "data" messages, in order to help us debug any mix-ups.
6862  const int sizeTag = 1337;
6863  const int dataTag = 1338;
6864 
6865  // Process 0 pipelines nonblocking receives with file output.
6866  //
6867  // Constraints:
6868  // - Process 0 can't post a receive for another process'
6869  // actual data, until it posts and waits on the receive
6870  // from that process with the amount of data to receive.
6871  // (We could just post receives with a max data size, but
6872  // I feel uncomfortable about that.)
6873  // - The C++ standard library doesn't allow nonblocking
6874  // output to an std::ostream. (Thus, we have to start a
6875  // receive or send before starting the write, and hope
6876  // that MPI completes it in the background.)
6877  //
6878  // Process 0: Post receive-size receives from Processes 1 and 2.
6879  // Process 1: Post send-size send to Process 0.
6880  // Process 2: Post send-size send to Process 0.
6881  //
6882  // All processes: Pack my entries.
6883  //
6884  // Process 1:
6885  // - Post send-data send to Process 0.
6886  // - Wait on my send-size send to Process 0.
6887  //
6888  // Process 0:
6889  // - Print MatrixMarket header.
6890  // - Print my entries.
6891  // - Wait on receive-size receive from Process 1.
6892  // - Post receive-data receive from Process 1.
6893  //
6894  // For each process p = 1, 2, ... numProcs-1:
6895  // If I am Process 0:
6896  // - Post receive-size receive from Process p + 2
6897  // - Wait on receive-size receive from Process p + 1
6898  // - Post receive-data receive from Process p + 1
6899  // - Wait on receive-data receive from Process p
6900  // - Write data from Process p.
6901  // Else if I am Process p:
6902  // - Wait on my send-data send.
6903  // Else if I am Process p+1:
6904  // - Post send-data send to Process 0.
6905  // - Wait on my send-size send.
6906  // Else if I am Process p+2:
6907  // - Post send-size send to Process 0.
6908  //
6909  // Pipelining has three goals here:
6910  // 1. Overlap communication (the receives) with file I/O
6911  // 2. Give Process 0 a chance to prepost some receives,
6912  // before sends show up, by packing local data before
6913  // posting sends
6914  // 3. Don't post _all_ receives or _all_ sends, because that
6915  // wouldn't be memory scalable. (Just because we can't
6916  // see how much memory MPI consumes, doesn't mean that it
6917  // doesn't consume any!)
6918 
6919  // These are used on every process. sendReqSize[0] holds the
6920  // number of rows on this process, and sendReqBuf holds this
6921  // process' data. Process 0 packs into sendReqBuf, but
6922  // doesn't send; it only uses that for printing. All other
6923  // processes send both of these to Process 0.
6924  RCP<CommRequest<int> > sendReqSize, sendReqData;
6925 
6926  // These are used only on Process 0, for received data. Keep
6927  // 3 of each, and treat the arrays as circular buffers. When
6928  // receiving from Process p, the corresponding array index
6929  // here is p % 3.
6930  Array<ArrayRCP<size_t> > recvSizeBufs (3);
6931  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
6932  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
6933  Array<RCP<CommRequest<int> > > recvDataReqs (3);
6934 
6935  // Buffer for nonblocking send of the "send size."
6936  ArrayRCP<size_t> sendDataSize (1);
6937  sendDataSize[0] = myNumRows;
6938 
6939  if (myRank == 0) {
6940  if (debug) {
6941  std::ostringstream os;
6942  os << myRank << ": Post receive-size receives from "
6943  "Procs 1 and 2: tag = " << sizeTag << endl;
6944  *dbg << os.str ();
6945  }
6946  // Process 0: Post receive-size receives from Processes 1 and 2.
6947  recvSizeBufs[0].resize (1);
6948  // Set these three to an invalid value as a flag. If we
6949  // don't get these messages, then the invalid value will
6950  // remain, so we can test for it.
6951  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6952  recvSizeBufs[1].resize (1);
6953  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6954  recvSizeBufs[2].resize (1);
6955  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6956  if (numProcs > 1) {
6957  recvSizeReqs[1] =
6958  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
6959  }
6960  if (numProcs > 2) {
6961  recvSizeReqs[2] =
6962  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
6963  }
6964  }
6965  else if (myRank == 1 || myRank == 2) {
6966  if (debug) {
6967  std::ostringstream os;
6968  os << myRank << ": Post send-size send: size = "
6969  << sendDataSize[0] << ", tag = " << sizeTag << endl;
6970  *dbg << os.str ();
6971  }
6972  // Prime the pipeline by having Processes 1 and 2 start
6973  // their send-size sends. We don't want _all_ the processes
6974  // to start their send-size sends, because that wouldn't be
6975  // memory scalable.
6976  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
6977  }
6978  else {
6979  if (debug) {
6980  std::ostringstream os;
6981  os << myRank << ": Not posting my send-size send yet" << endl;
6982  *dbg << os.str ();
6983  }
6984  }
6985 
6986  //
6987  // Pack my entries, in column-major order.
6988  //
6989  if (debug) {
6990  std::ostringstream os;
6991  os << myRank << ": Pack my entries" << endl;
6992  *dbg << os.str ();
6993  }
6994  ArrayRCP<scalar_type> sendDataBuf;
6995  try {
6996  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
6997  X.get1dCopy (sendDataBuf (), myNumRows);
6998  }
6999  catch (std::exception& e) {
7000  lclErr = 1;
7001  if (! err.is_null ()) {
7002  std::ostringstream os;
7003  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7004  "entries threw an exception: " << e.what () << endl;
7005  *err << os.str ();
7006  }
7007  }
7008  if (debug) {
7009  std::ostringstream os;
7010  os << myRank << ": Done packing my entries" << endl;
7011  *dbg << os.str ();
7012  }
7013 
7014  //
7015  // Process 1: post send-data send to Process 0.
7016  //
7017  if (myRank == 1) {
7018  if (debug) {
7019  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7020  << endl;
7021  }
7022  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7023  }
7024 
7025  //
7026  // Process 0: Write my entries.
7027  //
7028  if (myRank == 0) {
7029  if (debug) {
7030  std::ostringstream os;
7031  os << myRank << ": Write my entries" << endl;
7032  *dbg << os.str ();
7033  }
7034 
7035  // Write Process 0's data to the output stream.
7036  // Matrix Market prints dense matrices in column-major order.
7037  const size_t printNumRows = myNumRows;
7038  ArrayView<const scalar_type> printData = sendDataBuf ();
7039  const size_t printStride = printNumRows;
7040  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7041  lclErr = 1;
7042  if (! err.is_null ()) {
7043  std::ostringstream os;
7044  os << "Process " << myRank << ": My MultiVector data's size "
7045  << printData.size () << " does not match my local dimensions "
7046  << printStride << " x " << numCols << "." << endl;
7047  *err << os.str ();
7048  }
7049  }
7050  else {
7051  // Matrix Market dense format wants one number per line.
7052  // It wants each complex number as two real numbers (real
7053  // resp. imaginary parts) with a space between.
7054  for (size_t col = 0; col < numCols; ++col) {
7055  for (size_t row = 0; row < printNumRows; ++row) {
7056  if (STS::isComplex) {
7057  out << STS::real (printData[row + col * printStride]) << " "
7058  << STS::imag (printData[row + col * printStride]) << endl;
7059  } else {
7060  out << printData[row + col * printStride] << endl;
7061  }
7062  }
7063  }
7064  }
7065  }
7066 
7067  if (myRank == 0) {
7068  // Wait on receive-size receive from Process 1.
7069  const int recvRank = 1;
7070  const int circBufInd = recvRank % 3;
7071  if (debug) {
7072  std::ostringstream os;
7073  os << myRank << ": Wait on receive-size receive from Process "
7074  << recvRank << endl;
7075  *dbg << os.str ();
7076  }
7077  if (numProcs > 1) {
7078  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7079 
7080  // We received the number of rows of data. (The data
7081  // come in two columns.)
7082  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7083  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7084  lclErr = 1;
7085  if (! err.is_null ()) {
7086  std::ostringstream os;
7087  os << myRank << ": Result of receive-size receive from Process "
7088  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7089  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7090  "This should never happen, and suggests that the receive never "
7091  "got posted. Please report this bug to the Tpetra developers."
7092  << endl;
7093  *err << os.str ();
7094  }
7095 
7096  // If we're going to continue after error, set the
7097  // number of rows to receive to a reasonable size. This
7098  // may cause MPI_ERR_TRUNCATE if the sending process is
7099  // sending more than 0 rows, but that's better than MPI
7100  // overflowing due to the huge positive value that is
7101  // Teuchos::OrdinalTraits<size_t>::invalid().
7102  recvNumRows = 0;
7103  }
7104 
7105  // Post receive-data receive from Process 1.
7106  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7107  if (debug) {
7108  std::ostringstream os;
7109  os << myRank << ": Post receive-data receive from Process "
7110  << recvRank << ": tag = " << dataTag << ", buffer size = "
7111  << recvDataBufs[circBufInd].size () << endl;
7112  *dbg << os.str ();
7113  }
7114  if (! recvSizeReqs[circBufInd].is_null ()) {
7115  lclErr = 1;
7116  if (! err.is_null ()) {
7117  std::ostringstream os;
7118  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7119  "null, before posting the receive-data receive from Process "
7120  << recvRank << ". This should never happen. Please report "
7121  "this bug to the Tpetra developers." << endl;
7122  *err << os.str ();
7123  }
7124  }
7125  recvDataReqs[circBufInd] =
7126  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7127  recvRank, dataTag, comm);
7128  } // numProcs > 1
7129  }
7130  else if (myRank == 1) {
7131  // Wait on my send-size send.
7132  if (debug) {
7133  std::ostringstream os;
7134  os << myRank << ": Wait on my send-size send" << endl;
7135  *dbg << os.str ();
7136  }
7137  wait<int> (comm, outArg (sendReqSize));
7138  }
7139 
7140  //
7141  // Pipeline loop
7142  //
7143  for (int p = 1; p < numProcs; ++p) {
7144  if (myRank == 0) {
7145  if (p + 2 < numProcs) {
7146  // Post receive-size receive from Process p + 2.
7147  const int recvRank = p + 2;
7148  const int circBufInd = recvRank % 3;
7149  if (debug) {
7150  std::ostringstream os;
7151  os << myRank << ": Post receive-size receive from Process "
7152  << recvRank << ": tag = " << sizeTag << endl;
7153  *dbg << os.str ();
7154  }
7155  if (! recvSizeReqs[circBufInd].is_null ()) {
7156  lclErr = 1;
7157  if (! err.is_null ()) {
7158  std::ostringstream os;
7159  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7160  << "null, for the receive-size receive from Process "
7161  << recvRank << "! This may mean that this process never "
7162  << "finished waiting for the receive from Process "
7163  << (recvRank - 3) << "." << endl;
7164  *err << os.str ();
7165  }
7166  }
7167  recvSizeReqs[circBufInd] =
7168  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7169  recvRank, sizeTag, comm);
7170  }
7171 
7172  if (p + 1 < numProcs) {
7173  const int recvRank = p + 1;
7174  const int circBufInd = recvRank % 3;
7175 
7176  // Wait on receive-size receive from Process p + 1.
7177  if (debug) {
7178  std::ostringstream os;
7179  os << myRank << ": Wait on receive-size receive from Process "
7180  << recvRank << endl;
7181  *dbg << os.str ();
7182  }
7183  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7184 
7185  // We received the number of rows of data. (The data
7186  // come in two columns.)
7187  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7188  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7189  lclErr = 1;
7190  if (! err.is_null ()) {
7191  std::ostringstream os;
7192  os << myRank << ": Result of receive-size receive from Process "
7193  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7194  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7195  "This should never happen, and suggests that the receive never "
7196  "got posted. Please report this bug to the Tpetra developers."
7197  << endl;
7198  *err << os.str ();
7199  }
7200  // If we're going to continue after error, set the
7201  // number of rows to receive to a reasonable size.
7202  // This may cause MPI_ERR_TRUNCATE if the sending
7203  // process sends more than 0 rows, but that's better
7204  // than MPI overflowing due to the huge positive value
7205  // Teuchos::OrdinalTraits<size_t>::invalid().
7206  recvNumRows = 0;
7207  }
7208 
7209  // Post receive-data receive from Process p + 1.
7210  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7211  if (debug) {
7212  std::ostringstream os;
7213  os << myRank << ": Post receive-data receive from Process "
7214  << recvRank << ": tag = " << dataTag << ", buffer size = "
7215  << recvDataBufs[circBufInd].size () << endl;
7216  *dbg << os.str ();
7217  }
7218  if (! recvDataReqs[circBufInd].is_null ()) {
7219  lclErr = 1;
7220  if (! err.is_null ()) {
7221  std::ostringstream os;
7222  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7223  << "null, for the receive-data receive from Process "
7224  << recvRank << "! This may mean that this process never "
7225  << "finished waiting for the receive from Process "
7226  << (recvRank - 3) << "." << endl;
7227  *err << os.str ();
7228  }
7229  }
7230  recvDataReqs[circBufInd] =
7231  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7232  recvRank, dataTag, comm);
7233  }
7234 
7235  // Wait on receive-data receive from Process p.
7236  const int recvRank = p;
7237  const int circBufInd = recvRank % 3;
7238  if (debug) {
7239  std::ostringstream os;
7240  os << myRank << ": Wait on receive-data receive from Process "
7241  << recvRank << endl;
7242  *dbg << os.str ();
7243  }
7244  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7245 
7246  // Write Process p's data. Number of rows lives in
7247  // recvSizeBufs[circBufInd], and the actual data live in
7248  // recvDataBufs[circBufInd]. Do this after posting receives,
7249  // in order to expose overlap of comm. with file I/O.
7250  if (debug) {
7251  std::ostringstream os;
7252  os << myRank << ": Write entries from Process " << recvRank
7253  << endl;
7254  *dbg << os.str () << endl;
7255  }
7256  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7257  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7258  lclErr = 1;
7259  if (! err.is_null ()) {
7260  std::ostringstream os;
7261  os << myRank << ": Result of receive-size receive from Process "
7262  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7263  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7264  << ". This should never happen, and suggests that its "
7265  "receive-size receive was never posted. "
7266  "Please report this bug to the Tpetra developers." << endl;
7267  *err << os.str ();
7268  }
7269  // If we're going to continue after error, set the
7270  // number of rows to print to a reasonable size.
7271  printNumRows = 0;
7272  }
7273  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7274  lclErr = 1;
7275  if (! err.is_null ()) {
7276  std::ostringstream os;
7277  os << myRank << ": Result of receive-size receive from Proc "
7278  << recvRank << " was " << printNumRows << " > 0, but "
7279  "recvDataBufs[" << circBufInd << "] is null. This should "
7280  "never happen. Please report this bug to the Tpetra "
7281  "developers." << endl;
7282  *err << os.str ();
7283  }
7284  // If we're going to continue after error, set the
7285  // number of rows to print to a reasonable size.
7286  printNumRows = 0;
7287  }
7288 
7289  // Write the received data to the output stream.
7290  // Matrix Market prints dense matrices in column-major order.
7291  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7292  const size_t printStride = printNumRows;
7293  // Matrix Market dense format wants one number per line.
7294  // It wants each complex number as two real numbers (real
7295  // resp. imaginary parts) with a space between.
7296  for (size_t col = 0; col < numCols; ++col) {
7297  for (size_t row = 0; row < printNumRows; ++row) {
7298  if (STS::isComplex) {
7299  out << STS::real (printData[row + col * printStride]) << " "
7300  << STS::imag (printData[row + col * printStride]) << endl;
7301  } else {
7302  out << printData[row + col * printStride] << endl;
7303  }
7304  }
7305  }
7306  }
7307  else if (myRank == p) { // Process p
7308  // Wait on my send-data send.
7309  if (debug) {
7310  std::ostringstream os;
7311  os << myRank << ": Wait on my send-data send" << endl;
7312  *dbg << os.str ();
7313  }
7314  wait<int> (comm, outArg (sendReqData));
7315  }
7316  else if (myRank == p + 1) { // Process p + 1
7317  // Post send-data send to Process 0.
7318  if (debug) {
7319  std::ostringstream os;
7320  os << myRank << ": Post send-data send: tag = " << dataTag
7321  << endl;
7322  *dbg << os.str ();
7323  }
7324  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7325  // Wait on my send-size send.
7326  if (debug) {
7327  std::ostringstream os;
7328  os << myRank << ": Wait on my send-size send" << endl;
7329  *dbg << os.str ();
7330  }
7331  wait<int> (comm, outArg (sendReqSize));
7332  }
7333  else if (myRank == p + 2) { // Process p + 2
7334  // Post send-size send to Process 0.
7335  if (debug) {
7336  std::ostringstream os;
7337  os << myRank << ": Post send-size send: size = "
7338  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7339  *dbg << os.str ();
7340  }
7341  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7342  }
7343  }
7344 
7345  // Establish global agreement on the error state.
7346  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7347  TEUCHOS_TEST_FOR_EXCEPTION(
7348  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7349  "experienced some kind of error and was unable to complete.");
7350 
7351  if (debug) {
7352  dbg->popTab ();
7353  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7354  dbg->popTab ();
7355  }
7356  }
7357 
7358  public:
7359 
7365  static void
7366  writeDense (std::ostream& out,
7367  const Teuchos::RCP<const multivector_type>& X,
7368  const std::string& matrixName,
7369  const std::string& matrixDescription,
7370  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7371  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7372  {
7373  TEUCHOS_TEST_FOR_EXCEPTION(
7374  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7375  "writeDense: The input MultiVector X is null.");
7376  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7377  }
7378 
7384  static void
7385  writeDense (std::ostream& out,
7386  const multivector_type& X,
7387  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7388  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7389  {
7390  writeDense (out, X, "", "", err, dbg);
7391  }
7392 
7398  static void
7399  writeDense (std::ostream& out,
7400  const Teuchos::RCP<const multivector_type>& X,
7401  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7402  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7403  {
7404  TEUCHOS_TEST_FOR_EXCEPTION(
7405  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7406  "writeDense: The input MultiVector X is null.");
7407  writeDense (out, *X, "", "", err, dbg);
7408  }
7409 
7429  static void
7430  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7431  {
7432  Teuchos::RCP<Teuchos::FancyOStream> err =
7433  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7434  writeMap (out, map, err, debug);
7435  }
7436 
7445  static void
7446  writeMap (std::ostream& out,
7447  const map_type& map,
7448  const Teuchos::RCP<Teuchos::FancyOStream>& err,
7449  const bool debug=false)
7450  {
7451  using Teuchos::Array;
7452  using Teuchos::ArrayRCP;
7453  using Teuchos::ArrayView;
7454  using Teuchos::Comm;
7455  using Teuchos::CommRequest;
7456  using Teuchos::ireceive;
7457  using Teuchos::isend;
7458  using Teuchos::RCP;
7459  using Teuchos::TypeNameTraits;
7460  using Teuchos::wait;
7461  using std::endl;
7462  typedef global_ordinal_type GO;
7463  typedef int pid_type;
7464 
7465  // Treat the Map as a 1-column "multivector." This differs
7466  // from the previous two-column format, in which column 0 held
7467  // the GIDs, and column 1 held the corresponding PIDs. It
7468  // differs because printing that format requires knowing the
7469  // entire first column -- that is, all the GIDs -- in advance.
7470  // Sending messages from each process one at a time saves
7471  // memory, but it means that Process 0 doesn't ever have all
7472  // the GIDs at once.
7473  //
7474  // We pack the entries as ptrdiff_t, since this should be the
7475  // biggest signed built-in integer type that can hold any GO
7476  // or pid_type (= int) quantity without overflow. Test this
7477  // assumption at run time.
7478  typedef ptrdiff_t int_type;
7479  TEUCHOS_TEST_FOR_EXCEPTION(
7480  sizeof (GO) > sizeof (int_type), std::logic_error,
7481  "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7482  << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7483  << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7484  TEUCHOS_TEST_FOR_EXCEPTION(
7485  sizeof (pid_type) > sizeof (int_type), std::logic_error,
7486  "The (MPI) process rank type pid_type=" <<
7487  TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7488  "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7489  " = " << sizeof (ptrdiff_t) << ".");
7490 
7491  const Comm<int>& comm = * (map.getComm ());
7492  const int myRank = comm.getRank ();
7493  const int numProcs = comm.getSize ();
7494 
7495  if (! err.is_null ()) {
7496  err->pushTab ();
7497  }
7498  if (debug) {
7499  std::ostringstream os;
7500  os << myRank << ": writeMap" << endl;
7501  *err << os.str ();
7502  }
7503  if (! err.is_null ()) {
7504  err->pushTab ();
7505  }
7506 
7507  const size_t myNumRows = map.getNodeNumElements ();
7508  // Use a different tag for the "size" messages than for the
7509  // "data" messages, in order to help us debug any mix-ups.
7510  const int sizeTag = 1337;
7511  const int dataTag = 1338;
7512 
7513  // Process 0 pipelines nonblocking receives with file output.
7514  //
7515  // Constraints:
7516  // - Process 0 can't post a receive for another process'
7517  // actual data, until it posts and waits on the receive
7518  // from that process with the amount of data to receive.
7519  // (We could just post receives with a max data size, but
7520  // I feel uncomfortable about that.)
7521  // - The C++ standard library doesn't allow nonblocking
7522  // output to an std::ostream.
7523  //
7524  // Process 0: Post receive-size receives from Processes 1 and 2.
7525  // Process 1: Post send-size send to Process 0.
7526  // Process 2: Post send-size send to Process 0.
7527  //
7528  // All processes: Pack my GIDs and PIDs.
7529  //
7530  // Process 1:
7531  // - Post send-data send to Process 0.
7532  // - Wait on my send-size send to Process 0.
7533  //
7534  // Process 0:
7535  // - Print MatrixMarket header.
7536  // - Print my GIDs and PIDs.
7537  // - Wait on receive-size receive from Process 1.
7538  // - Post receive-data receive from Process 1.
7539  //
7540  // For each process p = 1, 2, ... numProcs-1:
7541  // If I am Process 0:
7542  // - Post receive-size receive from Process p + 2
7543  // - Wait on receive-size receive from Process p + 1
7544  // - Post receive-data receive from Process p + 1
7545  // - Wait on receive-data receive from Process p
7546  // - Write data from Process p.
7547  // Else if I am Process p:
7548  // - Wait on my send-data send.
7549  // Else if I am Process p+1:
7550  // - Post send-data send to Process 0.
7551  // - Wait on my send-size send.
7552  // Else if I am Process p+2:
7553  // - Post send-size send to Process 0.
7554  //
7555  // Pipelining has three goals here:
7556  // 1. Overlap communication (the receives) with file I/O
7557  // 2. Give Process 0 a chance to prepost some receives,
7558  // before sends show up, by packing local data before
7559  // posting sends
7560  // 3. Don't post _all_ receives or _all_ sends, because that
7561  // wouldn't be memory scalable. (Just because we can't
7562  // see how much memory MPI consumes, doesn't mean that it
7563  // doesn't consume any!)
7564 
7565  // These are used on every process. sendReqSize[0] holds the
7566  // number of rows on this process, and sendReqBuf holds this
7567  // process' data. Process 0 packs into sendReqBuf, but
7568  // doesn't send; it only uses that for printing. All other
7569  // processes send both of these to Process 0.
7570  RCP<CommRequest<int> > sendReqSize, sendReqData;
7571 
7572  // These are used only on Process 0, for received data. Keep
7573  // 3 of each, and treat the arrays as circular buffers. When
7574  // receiving from Process p, the corresponding array index
7575  // here is p % 3.
7576  Array<ArrayRCP<int_type> > recvSizeBufs (3);
7577  Array<ArrayRCP<int_type> > recvDataBufs (3);
7578  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7579  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7580 
7581  // Buffer for nonblocking send of the "send size."
7582  ArrayRCP<int_type> sendDataSize (1);
7583  sendDataSize[0] = myNumRows;
7584 
7585  if (myRank == 0) {
7586  if (debug) {
7587  std::ostringstream os;
7588  os << myRank << ": Post receive-size receives from "
7589  "Procs 1 and 2: tag = " << sizeTag << endl;
7590  *err << os.str ();
7591  }
7592  // Process 0: Post receive-size receives from Processes 1 and 2.
7593  recvSizeBufs[0].resize (1);
7594  (recvSizeBufs[0])[0] = -1; // error flag
7595  recvSizeBufs[1].resize (1);
7596  (recvSizeBufs[1])[0] = -1; // error flag
7597  recvSizeBufs[2].resize (1);
7598  (recvSizeBufs[2])[0] = -1; // error flag
7599  if (numProcs > 1) {
7600  recvSizeReqs[1] =
7601  ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7602  }
7603  if (numProcs > 2) {
7604  recvSizeReqs[2] =
7605  ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7606  }
7607  }
7608  else if (myRank == 1 || myRank == 2) {
7609  if (debug) {
7610  std::ostringstream os;
7611  os << myRank << ": Post send-size send: size = "
7612  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7613  *err << os.str ();
7614  }
7615  // Prime the pipeline by having Processes 1 and 2 start
7616  // their send-size sends. We don't want _all_ the processes
7617  // to start their send-size sends, because that wouldn't be
7618  // memory scalable.
7619  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7620  }
7621  else {
7622  if (debug) {
7623  std::ostringstream os;
7624  os << myRank << ": Not posting my send-size send yet" << endl;
7625  *err << os.str ();
7626  }
7627  }
7628 
7629  //
7630  // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7631  // consecutively, for better locality.
7632  //
7633 
7634  if (debug) {
7635  std::ostringstream os;
7636  os << myRank << ": Pack my GIDs and PIDs" << endl;
7637  *err << os.str ();
7638  }
7639 
7640  ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7641 
7642  if (map.isContiguous ()) {
7643  const int_type myMinGblIdx =
7644  static_cast<int_type> (map.getMinGlobalIndex ());
7645  for (size_t k = 0; k < myNumRows; ++k) {
7646  const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7647  const int_type pid = static_cast<int_type> (myRank);
7648  sendDataBuf[2*k] = gid;
7649  sendDataBuf[2*k+1] = pid;
7650  }
7651  }
7652  else {
7653  ArrayView<const GO> myGblInds = map.getNodeElementList ();
7654  for (size_t k = 0; k < myNumRows; ++k) {
7655  const int_type gid = static_cast<int_type> (myGblInds[k]);
7656  const int_type pid = static_cast<int_type> (myRank);
7657  sendDataBuf[2*k] = gid;
7658  sendDataBuf[2*k+1] = pid;
7659  }
7660  }
7661 
7662  if (debug) {
7663  std::ostringstream os;
7664  os << myRank << ": Done packing my GIDs and PIDs" << endl;
7665  *err << os.str ();
7666  }
7667 
7668  if (myRank == 1) {
7669  // Process 1: post send-data send to Process 0.
7670  if (debug) {
7671  *err << myRank << ": Post send-data send: tag = " << dataTag
7672  << endl;
7673  }
7674  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7675  }
7676 
7677  if (myRank == 0) {
7678  if (debug) {
7679  *err << myRank << ": Write MatrixMarket header" << endl;
7680  }
7681 
7682  // Process 0: Write the MatrixMarket header.
7683  // Description section explains each column.
7684  std::ostringstream hdr;
7685 
7686  // Print the Matrix Market header. MultiVector stores data
7687  // nonsymmetrically, hence "general" in the banner line.
7688  hdr << "%%MatrixMarket matrix array integer general" << endl
7689  << "% Format: Version 2.0" << endl
7690  << "%" << endl
7691  << "% This file encodes a Tpetra::Map." << endl
7692  << "% It is stored as a dense vector, with twice as many " << endl
7693  << "% entries as the global number of GIDs (global indices)." << endl
7694  << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7695  << "% is the rank of the process owning that GID." << endl
7696  << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
7697  out << hdr.str ();
7698 
7699  if (debug) {
7700  std::ostringstream os;
7701  os << myRank << ": Write my GIDs and PIDs" << endl;
7702  *err << os.str ();
7703  }
7704 
7705  // Write Process 0's data to the output stream.
7706  // Matrix Market prints dense matrices in column-major order.
7707  const int_type printNumRows = myNumRows;
7708  ArrayView<const int_type> printData = sendDataBuf ();
7709  for (int_type k = 0; k < printNumRows; ++k) {
7710  const int_type gid = printData[2*k];
7711  const int_type pid = printData[2*k+1];
7712  out << gid << endl << pid << endl;
7713  }
7714  }
7715 
7716  if (myRank == 0) {
7717  // Wait on receive-size receive from Process 1.
7718  const int recvRank = 1;
7719  const int circBufInd = recvRank % 3;
7720  if (debug) {
7721  std::ostringstream os;
7722  os << myRank << ": Wait on receive-size receive from Process "
7723  << recvRank << endl;
7724  *err << os.str ();
7725  }
7726  if (numProcs > 1) {
7727  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7728 
7729  // We received the number of rows of data. (The data
7730  // come in two columns.)
7731  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7732  if (debug && recvNumRows == -1) {
7733  std::ostringstream os;
7734  os << myRank << ": Result of receive-size receive from Process "
7735  << recvRank << " is -1. This should never happen, and "
7736  "suggests that the receive never got posted. Please report "
7737  "this bug to the Tpetra developers." << endl;
7738  *err << os.str ();
7739  }
7740 
7741  // Post receive-data receive from Process 1.
7742  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7743  if (debug) {
7744  std::ostringstream os;
7745  os << myRank << ": Post receive-data receive from Process "
7746  << recvRank << ": tag = " << dataTag << ", buffer size = "
7747  << recvDataBufs[circBufInd].size () << endl;
7748  *err << os.str ();
7749  }
7750  if (! recvSizeReqs[circBufInd].is_null ()) {
7751  std::ostringstream os;
7752  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7753  "null, before posting the receive-data receive from Process "
7754  << recvRank << ". This should never happen. Please report "
7755  "this bug to the Tpetra developers." << endl;
7756  *err << os.str ();
7757  }
7758  recvDataReqs[circBufInd] =
7759  ireceive<int, int_type> (recvDataBufs[circBufInd],
7760  recvRank, dataTag, comm);
7761  } // numProcs > 1
7762  }
7763  else if (myRank == 1) {
7764  // Wait on my send-size send.
7765  if (debug) {
7766  std::ostringstream os;
7767  os << myRank << ": Wait on my send-size send" << endl;
7768  *err << os.str ();
7769  }
7770  wait<int> (comm, outArg (sendReqSize));
7771  }
7772 
7773  //
7774  // Pipeline loop
7775  //
7776  for (int p = 1; p < numProcs; ++p) {
7777  if (myRank == 0) {
7778  if (p + 2 < numProcs) {
7779  // Post receive-size receive from Process p + 2.
7780  const int recvRank = p + 2;
7781  const int circBufInd = recvRank % 3;
7782  if (debug) {
7783  std::ostringstream os;
7784  os << myRank << ": Post receive-size receive from Process "
7785  << recvRank << ": tag = " << sizeTag << endl;
7786  *err << os.str ();
7787  }
7788  if (! recvSizeReqs[circBufInd].is_null ()) {
7789  std::ostringstream os;
7790  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7791  << "null, for the receive-size receive from Process "
7792  << recvRank << "! This may mean that this process never "
7793  << "finished waiting for the receive from Process "
7794  << (recvRank - 3) << "." << endl;
7795  *err << os.str ();
7796  }
7797  recvSizeReqs[circBufInd] =
7798  ireceive<int, int_type> (recvSizeBufs[circBufInd],
7799  recvRank, sizeTag, comm);
7800  }
7801 
7802  if (p + 1 < numProcs) {
7803  const int recvRank = p + 1;
7804  const int circBufInd = recvRank % 3;
7805 
7806  // Wait on receive-size receive from Process p + 1.
7807  if (debug) {
7808  std::ostringstream os;
7809  os << myRank << ": Wait on receive-size receive from Process "
7810  << recvRank << endl;
7811  *err << os.str ();
7812  }
7813  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7814 
7815  // We received the number of rows of data. (The data
7816  // come in two columns.)
7817  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7818  if (debug && recvNumRows == -1) {
7819  std::ostringstream os;
7820  os << myRank << ": Result of receive-size receive from Process "
7821  << recvRank << " is -1. This should never happen, and "
7822  "suggests that the receive never got posted. Please report "
7823  "this bug to the Tpetra developers." << endl;
7824  *err << os.str ();
7825  }
7826 
7827  // Post receive-data receive from Process p + 1.
7828  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7829  if (debug) {
7830  std::ostringstream os;
7831  os << myRank << ": Post receive-data receive from Process "
7832  << recvRank << ": tag = " << dataTag << ", buffer size = "
7833  << recvDataBufs[circBufInd].size () << endl;
7834  *err << os.str ();
7835  }
7836  if (! recvDataReqs[circBufInd].is_null ()) {
7837  std::ostringstream os;
7838  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7839  << "null, for the receive-data receive from Process "
7840  << recvRank << "! This may mean that this process never "
7841  << "finished waiting for the receive from Process "
7842  << (recvRank - 3) << "." << endl;
7843  *err << os.str ();
7844  }
7845  recvDataReqs[circBufInd] =
7846  ireceive<int, int_type> (recvDataBufs[circBufInd],
7847  recvRank, dataTag, comm);
7848  }
7849 
7850  // Wait on receive-data receive from Process p.
7851  const int recvRank = p;
7852  const int circBufInd = recvRank % 3;
7853  if (debug) {
7854  std::ostringstream os;
7855  os << myRank << ": Wait on receive-data receive from Process "
7856  << recvRank << endl;
7857  *err << os.str ();
7858  }
7859  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7860 
7861  // Write Process p's data. Number of rows lives in
7862  // recvSizeBufs[circBufInd], and the actual data live in
7863  // recvDataBufs[circBufInd]. Do this after posting receives,
7864  // in order to expose overlap of comm. with file I/O.
7865  if (debug) {
7866  std::ostringstream os;
7867  os << myRank << ": Write GIDs and PIDs from Process "
7868  << recvRank << endl;
7869  *err << os.str () << endl;
7870  }
7871  const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
7872  if (debug && printNumRows == -1) {
7873  std::ostringstream os;
7874  os << myRank << ": Result of receive-size receive from Process "
7875  << recvRank << " was -1. This should never happen, and "
7876  "suggests that its receive-size receive was never posted. "
7877  "Please report this bug to the Tpetra developers." << endl;
7878  *err << os.str ();
7879  }
7880  if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7881  std::ostringstream os;
7882  os << myRank << ": Result of receive-size receive from Proc "
7883  << recvRank << " was " << printNumRows << " > 0, but "
7884  "recvDataBufs[" << circBufInd << "] is null. This should "
7885  "never happen. Please report this bug to the Tpetra "
7886  "developers." << endl;
7887  *err << os.str ();
7888  }
7889  ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
7890  for (int_type k = 0; k < printNumRows; ++k) {
7891  const int_type gid = printData[2*k];
7892  const int_type pid = printData[2*k+1];
7893  out << gid << endl << pid << endl;
7894  }
7895  }
7896  else if (myRank == p) { // Process p
7897  // Wait on my send-data send.
7898  if (debug) {
7899  std::ostringstream os;
7900  os << myRank << ": Wait on my send-data send" << endl;
7901  *err << os.str ();
7902  }
7903  wait<int> (comm, outArg (sendReqData));
7904  }
7905  else if (myRank == p + 1) { // Process p + 1
7906  // Post send-data send to Process 0.
7907  if (debug) {
7908  std::ostringstream os;
7909  os << myRank << ": Post send-data send: tag = " << dataTag
7910  << endl;
7911  *err << os.str ();
7912  }
7913  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7914  // Wait on my send-size send.
7915  if (debug) {
7916  std::ostringstream os;
7917  os << myRank << ": Wait on my send-size send" << endl;
7918  *err << os.str ();
7919  }
7920  wait<int> (comm, outArg (sendReqSize));
7921  }
7922  else if (myRank == p + 2) { // Process p + 2
7923  // Post send-size send to Process 0.
7924  if (debug) {
7925  std::ostringstream os;
7926  os << myRank << ": Post send-size send: size = "
7927  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7928  *err << os.str ();
7929  }
7930  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7931  }
7932  }
7933 
7934  if (! err.is_null ()) {
7935  err->popTab ();
7936  }
7937  if (debug) {
7938  *err << myRank << ": writeMap: Done" << endl;
7939  }
7940  if (! err.is_null ()) {
7941  err->popTab ();
7942  }
7943  }
7944 
7946  static void
7947  writeMapFile (const std::string& filename,
7948  const map_type& map)
7949  {
7950  const int myRank = map.getComm ()->getRank ();
7951  std::ofstream out;
7952  if (myRank == 0) { // Only open the file on Proc 0.
7953  out.open (filename.c_str());
7954  }
7955  writeMap (out, map);
7956  // We can rely on the destructor of the output stream to close
7957  // the file on scope exit, even if writeDense() throws an
7958  // exception.
7959  }
7960 
7961  private:
7985  static void
7986  printAsComment (std::ostream& out, const std::string& str)
7987  {
7988  using std::endl;
7989  std::istringstream inpstream (str);
7990  std::string line;
7991 
7992  while (getline (inpstream, line)) {
7993  if (! line.empty()) {
7994  // Note that getline() doesn't store '\n', so we have to
7995  // append the endline ourselves.
7996  if (line[0] == '%') { // Line starts with a comment character.
7997  out << line << endl;
7998  }
7999  else { // Line doesn't start with a comment character.
8000  out << "%% " << line << endl;
8001  }
8002  }
8003  }
8004  }
8005 
8006  public:
8007 
8026  static void
8027  writeOperator(const std::string& fileName, operator_type const &A) {
8028  Teuchos::ParameterList pl;
8029  writeOperator(fileName, A, pl);
8030  }
8031 
8052  static void
8053  writeOperator (std::ostream& out, const operator_type& A) {
8054  Teuchos::ParameterList pl;
8055  writeOperator (out, A, pl);
8056  }
8057 
8094  static void
8095  writeOperator (const std::string& fileName,
8096  const operator_type& A,
8097  const Teuchos::ParameterList& params)
8098  {
8099  std::ofstream out;
8100  std::string tmpFile = "__TMP__" + fileName;
8101  const int myRank = A.getDomainMap()->getComm()->getRank();
8102  bool precisionChanged=false;
8103  int oldPrecision;
8104  // The number of nonzero entries in a Tpetra::Operator is
8105  // unknown until probing is completed. In order to write a
8106  // MatrixMarket header, we write the matrix to a temporary
8107  // file.
8108  //
8109  // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8110  // TEMPORARY FILE.
8111  if (myRank==0) {
8112  if (std::ifstream(tmpFile))
8113  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8114  "writeOperator: temporary file " << tmpFile << " already exists");
8115  out.open(tmpFile.c_str());
8116  if (params.isParameter("precision")) {
8117  oldPrecision = out.precision(params.get<int>("precision"));
8118  precisionChanged=true;
8119  }
8120  }
8121 
8122  const std::string header = writeOperatorImpl(out, A, params);
8123 
8124  if (myRank==0) {
8125  if (precisionChanged)
8126  out.precision(oldPrecision);
8127  out.close();
8128  out.open(fileName.c_str(), std::ios::binary);
8129  bool printMatrixMarketHeader = true;
8130  if (params.isParameter("print MatrixMarket header"))
8131  printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8132  if (printMatrixMarketHeader && myRank == 0) {
8133  // Write header to final file.
8134  out << header;
8135  }
8136  // Append matrix from temporary to final file.
8137  std::ifstream src(tmpFile, std::ios_base::binary);
8138  out << src.rdbuf();
8139  src.close();
8140  // Delete the temporary file.
8141  remove(tmpFile.c_str());
8142  }
8143  }
8144 
8183  static void
8184  writeOperator (std::ostream& out,
8185  const operator_type& A,
8186  const Teuchos::ParameterList& params)
8187  {
8188  const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8189 
8190  // The number of nonzero entries in a Tpetra::Operator is
8191  // unknown until probing is completed. In order to write a
8192  // MatrixMarket header, we write the matrix to a temporary
8193  // output stream.
8194  //
8195  // NOTE (mfh 23 May 2015): Writing to a temporary output
8196  // stream may double the memory usage, depending on whether
8197  // 'out' is a file stream or an in-memory output stream (e.g.,
8198  // std::ostringstream). It might be wise to use a temporary
8199  // file instead. However, please look carefully at POSIX
8200  // functions for safe creation of temporary files. Don't just
8201  // prepend "__TMP__" to the filename and hope for the best.
8202  // Furthermore, it should be valid to call the std::ostream
8203  // overload of this method even when Process 0 does not have
8204  // access to a file system.
8205  std::ostringstream tmpOut;
8206  if (myRank == 0) {
8207  if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8208  (void) tmpOut.precision (params.get<int> ("precision"));
8209  }
8210  }
8211 
8212  const std::string header = writeOperatorImpl (tmpOut, A, params);
8213 
8214  if (myRank == 0) {
8215  bool printMatrixMarketHeader = true;
8216  if (params.isParameter ("print MatrixMarket header") &&
8217  params.isType<bool> ("print MatrixMarket header")) {
8218  printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8219  }
8220  if (printMatrixMarketHeader && myRank == 0) {
8221  out << header; // write header to final output stream
8222  }
8223  // Append matrix from temporary output stream to final output stream.
8224  //
8225  // NOTE (mfh 23 May 2015) This might use a lot of memory.
8226  // However, we should not use temporary files in this
8227  // method. Since it does not access the file system (unlike
8228  // the overload that takes a file name), it should not
8229  // require the file system at all.
8230  //
8231  // If memory usage becomes a problem, one thing we could do
8232  // is write the entries of the Operator one column (or a few
8233  // columns) at a time. The Matrix Market sparse format does
8234  // not impose an order on its entries, so it would be OK to
8235  // write them in that order.
8236  out << tmpOut.str ();
8237  }
8238  }
8239 
8240  private:
8241 
8249  static std::string
8250  writeOperatorImpl (std::ostream& os,
8251  const operator_type& A,
8252  const Teuchos::ParameterList& params)
8253  {
8254  using Teuchos::RCP;
8255  using Teuchos::rcp;
8256  using Teuchos::ArrayRCP;
8257  using Teuchos::Array;
8258 
8259  typedef local_ordinal_type LO;
8260  typedef global_ordinal_type GO;
8261  typedef scalar_type Scalar;
8262  typedef Teuchos::OrdinalTraits<LO> TLOT;
8263  typedef Teuchos::OrdinalTraits<GO> TGOT;
8264  typedef Tpetra::Import<LO, GO, node_type> import_type;
8265  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
8266 
8267  const map_type& domainMap = *(A.getDomainMap());
8268  RCP<const map_type> rangeMap = A.getRangeMap();
8269  RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8270  const int myRank = comm->getRank();
8271  const size_t numProcs = comm->getSize();
8272 
8273  size_t numMVs = 10;
8274  if (params.isParameter("probing size"))
8275  numMVs = params.get<int>("probing size");
8276 
8277  GO globalNnz = 0;
8278  GO minColGid = domainMap.getMinAllGlobalIndex();
8279  GO maxColGid = domainMap.getMaxAllGlobalIndex();
8280  // Rather than replicating the domainMap on all processors, we instead
8281  // iterate from the min GID to the max GID. If the map is gappy,
8282  // there will be invalid GIDs, i.e., GIDs no one has. This will require
8283  // unnecessary matvecs against potentially zero vectors.
8284  GO numGlobElts = maxColGid - minColGid + TGOT::one();
8285  GO numChunks = numGlobElts / numMVs;
8286  GO rem = numGlobElts % numMVs;
8287  GO indexBase = rangeMap->getIndexBase();
8288 
8289  int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8290  if (params.isParameter("zero-based indexing")) {
8291  if (params.get<bool>("zero-based indexing") == true)
8292  offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8293  }
8294 
8295  // Create map that replicates the range map on pid 0 and is empty for all other pids
8296  size_t numLocalRangeEntries = rangeMap->getNodeNumElements();
8297 
8298  // Create contiguous source map
8299  RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8300  indexBase, comm));
8301  // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8302  mv_type_go allGids(allGidsMap,1);
8303  Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8304 
8305  for (size_t i=0; i<numLocalRangeEntries; i++)
8306  allGidsData[i] = rangeMap->getGlobalElement(i);
8307  allGidsData = Teuchos::null;
8308 
8309  // Create target map that is nontrivial only on pid 0
8310  GO numTargetMapEntries=TGOT::zero();
8311  Teuchos::Array<GO> importGidList;
8312  if (myRank==0) {
8313  numTargetMapEntries = rangeMap->getGlobalNumElements();
8314  importGidList.reserve(numTargetMapEntries);
8315  for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8316  } else {
8317  importGidList.reserve(numTargetMapEntries);
8318  }
8319  RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8320 
8321  // Import all rangeMap GIDs to pid 0
8322  import_type gidImporter(allGidsMap, importGidMap);
8323  mv_type_go importedGids(importGidMap, 1);
8324  importedGids.doImport(allGids, gidImporter, INSERT);
8325 
8326  // The following import map will be non-trivial only on pid 0.
8327  ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8328  RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8329 
8330  // Importer from original range map to pid 0
8331  import_type importer(rangeMap, importMap);
8332  // Target vector on pid 0
8333  RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8334 
8335  RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8336  RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8337 
8338  Array<GO> globalColsArray, localColsArray;
8339  globalColsArray.reserve(numMVs);
8340  localColsArray.reserve(numMVs);
8341 
8342  ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8343  for (size_t i=0; i<numMVs; ++i)
8344  eiData[i] = ei->getDataNonConst(i);
8345 
8346  // //////////////////////////////////////
8347  // Discover A by chunks
8348  // //////////////////////////////////////
8349  for (GO k=0; k<numChunks; ++k) {
8350  for (size_t j=0; j<numMVs; ++j ) {
8351  //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8352  GO curGlobalCol = minColGid + k*numMVs + j;
8353  globalColsArray.push_back(curGlobalCol);
8354  //TODO extract the g2l map outside of this loop loop
8355  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8356  if (curLocalCol != TLOT::invalid()) {
8357  eiData[j][curLocalCol] = TGOT::one();
8358  localColsArray.push_back(curLocalCol);
8359  }
8360  }
8361  //TODO Do the views eiData need to be released prior to the matvec?
8362 
8363  // probe
8364  A.apply(*ei,*colsA);
8365 
8366  colsOnPid0->doImport(*colsA,importer,INSERT);
8367 
8368  if (myRank==0)
8369  globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8370  globalColsArray, offsetToUseInPrinting);
8371 
8372  //zero out the ei's
8373  for (size_t j=0; j<numMVs; ++j ) {
8374  for (int i=0; i<localColsArray.size(); ++i)
8375  eiData[j][localColsArray[i]] = TGOT::zero();
8376  }
8377  globalColsArray.clear();
8378  localColsArray.clear();
8379 
8380  }
8381 
8382  // //////////////////////////////////////
8383  // Handle leftover part of A
8384  // //////////////////////////////////////
8385  if (rem > 0) {
8386  for (int j=0; j<rem; ++j ) {
8387  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8388  globalColsArray.push_back(curGlobalCol);
8389  //TODO extract the g2l map outside of this loop loop
8390  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8391  if (curLocalCol != TLOT::invalid()) {
8392  eiData[j][curLocalCol] = TGOT::one();
8393  localColsArray.push_back(curLocalCol);
8394  }
8395  }
8396  //TODO Do the views eiData need to be released prior to the matvec?
8397 
8398  // probe
8399  A.apply(*ei,*colsA);
8400 
8401  colsOnPid0->doImport(*colsA,importer,INSERT);
8402  if (myRank==0)
8403  globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8404  globalColsArray, offsetToUseInPrinting);
8405 
8406  //zero out the ei's
8407  for (int j=0; j<rem; ++j ) {
8408  for (int i=0; i<localColsArray.size(); ++i)
8409  eiData[j][localColsArray[i]] = TGOT::zero();
8410  }
8411  globalColsArray.clear();
8412  localColsArray.clear();
8413 
8414  }
8415 
8416  // Return the Matrix Market header. It includes the header
8417  // line (that starts with "%%"), some comments, and the triple
8418  // of matrix dimensions and number of nonzero entries. We
8419  // don't actually print this here, because we don't know the
8420  // number of nonzero entries until after probing.
8421  std::ostringstream oss;
8422  if (myRank == 0) {
8423  oss << "%%MatrixMarket matrix coordinate ";
8424  if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8425  oss << "complex";
8426  } else {
8427  oss << "real";
8428  }
8429  oss << " general" << std::endl;
8430  oss << "% Tpetra::Operator" << std::endl;
8431  std::time_t now = std::time(NULL);
8432  oss << "% time stamp: " << ctime(&now);
8433  oss << "% written from " << numProcs << " processes" << std::endl;
8434  size_t numRows = rangeMap->getGlobalNumElements();
8435  size_t numCols = domainMap.getGlobalNumElements();
8436  oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8437  }
8438 
8439  return oss.str ();
8440  }
8441 
8442  static global_ordinal_type
8443  writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8444  Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8445  Teuchos::Array<global_ordinal_type> const &colsArray,
8446  global_ordinal_type const & indexBase) {
8447 
8448  typedef global_ordinal_type GO;
8449  typedef scalar_type Scalar;
8450  typedef Teuchos::ScalarTraits<Scalar> STS;
8451 
8452  GO nnz=0;
8453  const Scalar zero = STS::zero();
8454  const size_t numRows = colsA.getGlobalLength();
8455  for (size_t j=0; j<numCols; ++j) {
8456  Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8457  const GO J = colsArray[j];
8458  for (size_t i=0; i<numRows; ++i) {
8459  const Scalar val = curCol[i];
8460  if (val!=zero) {
8461  os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8462  ++nnz;
8463  }
8464  }
8465  }
8466 
8467  return nnz;
8468 
8469  }
8470 
8471  public:
8472 
8473  }; // class Writer
8474 
8475  } // namespace MatrixMarket
8476 } // namespace Tpetra
8477 
8478 #endif // __MatrixMarket_Tpetra_hpp
From a distributed map build a map with all GIDs on the root node.
Declaration of a function that prints strings from each process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
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...
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
bool isGloballyIndexed() const override
Whether the graph's column indices are stored as global indices.
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...
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").
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
A parallel distribution of indices over processes.
Teuchos::ArrayView< const global_ordinal_type > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Matrix Market file reader for CrsMatrix and MultiVector.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
SparseMatrixType::global_ordinal_type global_ordinal_type
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< sparse_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.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
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.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static 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.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType sparse_matrix_type
This class' template parameter; a specialization of CrsMatrix.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
static 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.
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.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const 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.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
SparseMatrixType::scalar_type scalar_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
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.
Matrix Market file writer for CrsMatrix and MultiVector.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
static 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.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
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.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments.
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void 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,...
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
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.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
static void 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.
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.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void 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.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
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.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
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.
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.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
One or more distributed dense vectors.
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.
size_t getNumVectors() const
Number of columns in the multivector.
Abstract interface for operators (e.g., matrices and preconditioners).
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....
A distributed dense vector.
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp....
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,...
Namespace Tpetra contains the class and methods constituting the Tpetra library.
size_t global_size_t
Global size_t object.
@ INSERT
Insert new values that don't currently exist.