Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef __MatrixMarket_Tpetra_hpp
43 #define __MatrixMarket_Tpetra_hpp
44 
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 #include "Teuchos_TimeMonitor.hpp"
70 
71 extern "C" {
72 #include "mmio_Tpetra.h"
73 }
74 #include "Tpetra_Distribution.hpp"
75 
76 
77 #include <algorithm>
78 #include <fstream>
79 #include <iostream>
80 #include <iterator>
81 #include <vector>
82 #include <stdexcept>
83 #include <numeric>
84 
85 namespace Tpetra {
115  namespace MatrixMarket {
171  template<class SparseMatrixType>
172  class Reader {
173  public:
175  typedef SparseMatrixType sparse_matrix_type;
176  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
177 
180  typedef typename SparseMatrixType::scalar_type scalar_type;
183  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
191  typedef typename SparseMatrixType::global_ordinal_type
194  typedef typename SparseMatrixType::node_type node_type;
195 
200 
202  typedef MultiVector<scalar_type,
206 
208  typedef Vector<scalar_type,
212 
213  typedef Teuchos::Comm<int> comm_type;
215 
216 
217  private:
223  typedef Teuchos::ArrayRCP<int>::size_type size_type;
224 
235  static Teuchos::RCP<const map_type>
236  makeRangeMap (const Teuchos::RCP<const comm_type>& pComm,
237  const global_ordinal_type numRows)
238  {
239  // Return a conventional, uniformly partitioned, contiguous map.
240  return rcp (new map_type (static_cast<global_size_t> (numRows),
241  static_cast<global_ordinal_type> (0),
242  pComm, GloballyDistributed));
243  }
244 
272  static Teuchos::RCP<const map_type>
273  makeRowMap (const Teuchos::RCP<const map_type>& pRowMap,
274  const Teuchos::RCP<const comm_type>& pComm,
275  const global_ordinal_type numRows)
276  {
277  // If the caller didn't provide a map, return a conventional,
278  // uniformly partitioned, contiguous map.
279  if (pRowMap.is_null ()) {
280  return rcp (new map_type (static_cast<global_size_t> (numRows),
281  static_cast<global_ordinal_type> (0),
282  pComm, GloballyDistributed));
283  }
284  else {
285  TEUCHOS_TEST_FOR_EXCEPTION
286  (! pRowMap->isDistributed () && pComm->getSize () > 1,
287  std::invalid_argument, "The specified row map is not distributed, "
288  "but the given communicator includes more than one process (in "
289  "fact, there are " << pComm->getSize () << " processes).");
290  TEUCHOS_TEST_FOR_EXCEPTION
291  (pRowMap->getComm () != pComm, std::invalid_argument,
292  "The specified row Map's communicator (pRowMap->getComm()) "
293  "differs from the given separately supplied communicator pComm.");
294  return pRowMap;
295  }
296  }
297 
312  static Teuchos::RCP<const map_type>
313  makeDomainMap (const Teuchos::RCP<const map_type>& pRangeMap,
314  const global_ordinal_type numRows,
315  const global_ordinal_type numCols)
316  {
317  // Abbreviations so that the map creation call isn't too long.
318  typedef local_ordinal_type LO;
319  typedef global_ordinal_type GO;
320  typedef node_type NT;
321 
322  if (numRows == numCols) {
323  return pRangeMap;
324  } else {
325  return createUniformContigMapWithNode<LO,GO,NT> (numCols,
326  pRangeMap->getComm ());
327  }
328  }
329 
402  static void
403  distribute (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
404  Teuchos::ArrayRCP<size_t>& myRowPtr,
405  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
406  Teuchos::ArrayRCP<scalar_type>& myValues,
407  const Teuchos::RCP<const map_type>& pRowMap,
408  Teuchos::ArrayRCP<size_t>& numEntriesPerRow,
409  Teuchos::ArrayRCP<size_t>& rowPtr,
410  Teuchos::ArrayRCP<global_ordinal_type>& colInd,
411  Teuchos::ArrayRCP<scalar_type>& values,
412  const bool debug=false)
413  {
414  using Teuchos::arcp;
415  using Teuchos::ArrayRCP;
416  using Teuchos::ArrayView;
417  using Teuchos::as;
418  using Teuchos::Comm;
419  using Teuchos::CommRequest;
420  using Teuchos::null;
421  using Teuchos::RCP;
422  using Teuchos::receive;
423  using Teuchos::send;
424  using std::cerr;
425  using std::endl;
426 
427  const bool extraDebug = false;
428  RCP<const comm_type> pComm = pRowMap->getComm ();
429  const int numProcs = pComm->getSize ();
430  const int myRank = pComm->getRank ();
431  const int rootRank = 0;
432 
433  // Type abbreviations to make the code more concise.
434  typedef global_ordinal_type GO;
435 
436  // List of the global indices of my rows. They may or may
437  // not be contiguous, and the row map need not be one-to-one.
438  ArrayView<const GO> myRows = pRowMap->getLocalElementList();
439  const size_type myNumRows = myRows.size();
440  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
441  pRowMap->getLocalNumElements(),
442  std::logic_error,
443  "pRowMap->getLocalElementList().size() = "
444  << myNumRows
445  << " != pRowMap->getLocalNumElements() = "
446  << pRowMap->getLocalNumElements() << ". "
447  "Please report this bug to the Tpetra developers.");
448  TEUCHOS_TEST_FOR_EXCEPTION(myRank == 0 && numEntriesPerRow.size() < myNumRows,
449  std::logic_error,
450  "On Proc 0: numEntriesPerRow.size() = "
451  << numEntriesPerRow.size()
452  << " != pRowMap->getLocalElementList().size() = "
453  << myNumRows << ". Please report this bug to the "
454  "Tpetra developers.");
455 
456  // Space for my proc's number of entries per row. Will be
457  // filled in below.
458  myNumEntriesPerRow = arcp<size_t> (myNumRows);
459 
460  if (myRank != rootRank) {
461  // Tell the root how many rows we have. If we're sending
462  // none, then we don't have anything else to send, nor does
463  // the root have to receive anything else.
464  send (*pComm, myNumRows, rootRank);
465  if (myNumRows != 0) {
466  // Now send my rows' global indices. Hopefully the cast
467  // to int doesn't overflow. This is unlikely, since it
468  // should fit in a LO, even though it is a GO.
469  send (*pComm, static_cast<int> (myNumRows),
470  myRows.getRawPtr(), rootRank);
471 
472  // I (this proc) don't care if my global row indices are
473  // contiguous, though the root proc does (since otherwise
474  // it needs to pack noncontiguous data into contiguous
475  // storage before sending). That's why we don't check
476  // for contiguousness here.
477 
478  // Ask the root process for my part of the array of the
479  // number of entries per row.
480  receive (*pComm, rootRank,
481  static_cast<int> (myNumRows),
482  myNumEntriesPerRow.getRawPtr());
483 
484  // Use the resulting array to figure out how many column
485  // indices and values I should ask from the root process.
486  const local_ordinal_type myNumEntries =
487  std::accumulate (myNumEntriesPerRow.begin(),
488  myNumEntriesPerRow.end(), 0);
489 
490  // Make space for my entries of the sparse matrix. Note
491  // that they don't have to be sorted by row index.
492  // Iterating through all my rows requires computing a
493  // running sum over myNumEntriesPerRow.
494  myColInd = arcp<GO> (myNumEntries);
495  myValues = arcp<scalar_type> (myNumEntries);
496  if (myNumEntries > 0) {
497  // Ask for that many column indices and values, if
498  // there are any.
499  receive (*pComm, rootRank,
500  static_cast<int> (myNumEntries),
501  myColInd.getRawPtr());
502  receive (*pComm, rootRank,
503  static_cast<int> (myNumEntries),
504  myValues.getRawPtr());
505  }
506  } // If I own at least one row
507  } // If I am not the root processor
508  else { // I _am_ the root processor
509  if (debug) {
510  cerr << "-- Proc 0: Copying my data from global arrays" << endl;
511  }
512  // Proc 0 still needs to (allocate, if not done already)
513  // and fill its part of the matrix (my*).
514  for (size_type k = 0; k < myNumRows; ++k) {
515  const GO myCurRow = myRows[k];
516  const local_ordinal_type numEntriesInThisRow = numEntriesPerRow[myCurRow];
517  myNumEntriesPerRow[k] = numEntriesInThisRow;
518  }
519  if (extraDebug && debug) {
520  cerr << "Proc " << pRowMap->getComm ()->getRank ()
521  << ": myNumEntriesPerRow[0.." << (myNumRows-1) << "] = [";
522  for (size_type k = 0; k < myNumRows; ++k) {
523  cerr << myNumEntriesPerRow[k];
524  if (k < myNumRows-1) {
525  cerr << " ";
526  }
527  }
528  cerr << "]" << endl;
529  }
530  // The total number of matrix entries that my proc owns.
531  const local_ordinal_type myNumEntries =
532  std::accumulate (myNumEntriesPerRow.begin(),
533  myNumEntriesPerRow.end(), 0);
534  if (debug) {
535  cerr << "-- Proc 0: I own " << myNumRows << " rows and "
536  << myNumEntries << " entries" << endl;
537  }
538  myColInd = arcp<GO> (myNumEntries);
539  myValues = arcp<scalar_type> (myNumEntries);
540 
541  // Copy Proc 0's part of the matrix into the my* arrays.
542  // It's important that myCurPos be updated _before_ k,
543  // otherwise myCurPos will get the wrong number of entries
544  // per row (it should be for the row in the just-completed
545  // iteration, not for the next iteration's row).
546  local_ordinal_type myCurPos = 0;
547  for (size_type k = 0; k < myNumRows;
548  myCurPos += myNumEntriesPerRow[k], ++k) {
549  const local_ordinal_type curNumEntries = myNumEntriesPerRow[k];
550  const GO myRow = myRows[k];
551  const size_t curPos = rowPtr[myRow];
552  // Only copy if there are entries to copy, in order not
553  // to construct empty ranges for the ArrayRCP views.
554  if (curNumEntries > 0) {
555  ArrayView<GO> colIndView = colInd (curPos, curNumEntries);
556  ArrayView<GO> myColIndView = myColInd (myCurPos, curNumEntries);
557  std::copy (colIndView.begin(), colIndView.end(),
558  myColIndView.begin());
559 
560  ArrayView<scalar_type> valuesView =
561  values (curPos, curNumEntries);
562  ArrayView<scalar_type> myValuesView =
563  myValues (myCurPos, curNumEntries);
564  std::copy (valuesView.begin(), valuesView.end(),
565  myValuesView.begin());
566  }
567  }
568 
569  // Proc 0 processes each other proc p in turn.
570  for (int p = 1; p < numProcs; ++p) {
571  if (debug) {
572  cerr << "-- Proc 0: Processing proc " << p << endl;
573  }
574 
575  size_type theirNumRows = 0;
576  // Ask Proc p how many rows it has. If it doesn't
577  // have any, we can move on to the next proc. This
578  // has to be a standard receive so that we can avoid
579  // the degenerate case of sending zero data.
580  receive (*pComm, p, &theirNumRows);
581  if (debug) {
582  cerr << "-- Proc 0: Proc " << p << " owns "
583  << theirNumRows << " rows" << endl;
584  }
585  if (theirNumRows != 0) {
586  // Ask Proc p which rows it owns. The resulting global
587  // row indices are not guaranteed to be contiguous or
588  // sorted. Global row indices are themselves indices
589  // into the numEntriesPerRow array.
590  ArrayRCP<GO> theirRows = arcp<GO> (theirNumRows);
591  receive (*pComm, p, as<int> (theirNumRows),
592  theirRows.getRawPtr ());
593  // Extra test to make sure that the rows we received
594  // are all sensible. This is a good idea since we are
595  // going to use the global row indices we've received
596  // to index into the numEntriesPerRow array. Better to
597  // catch any bugs here and print a sensible error
598  // message, rather than segfault and print a cryptic
599  // error message.
600  {
601  const global_size_t numRows = pRowMap->getGlobalNumElements ();
602  const GO indexBase = pRowMap->getIndexBase ();
603  bool theirRowsValid = true;
604  for (size_type k = 0; k < theirNumRows; ++k) {
605  if (theirRows[k] < indexBase ||
606  as<global_size_t> (theirRows[k] - indexBase) >= numRows) {
607  theirRowsValid = false;
608  }
609  }
610  if (! theirRowsValid) {
611  TEUCHOS_TEST_FOR_EXCEPTION(
612  ! theirRowsValid, std::logic_error,
613  "Proc " << p << " has at least one invalid row index. "
614  "Here are all of them: " <<
615  Teuchos::toString (theirRows ()) << ". Valid row index "
616  "range (zero-based): [0, " << (numRows - 1) << "].");
617  }
618  }
619 
620  // Perhaps we could save a little work if we check
621  // whether Proc p's row indices are contiguous. That
622  // would make lookups in the global data arrays
623  // faster. For now, we just implement the general
624  // case and don't prematurely optimize. (Remember
625  // that you're making Proc 0 read the whole file, so
626  // you've already lost scalability.)
627 
628  // Compute the number of entries in each of Proc p's
629  // rows. (Proc p will compute its row pointer array
630  // on its own, after it gets the data from Proc 0.)
631  ArrayRCP<size_t> theirNumEntriesPerRow;
632  theirNumEntriesPerRow = arcp<size_t> (theirNumRows);
633  for (size_type k = 0; k < theirNumRows; ++k) {
634  theirNumEntriesPerRow[k] = numEntriesPerRow[theirRows[k]];
635  }
636 
637  // Tell Proc p the number of entries in each of its
638  // rows. Hopefully the cast to int doesn't overflow.
639  // This is unlikely, since it should fit in a LO,
640  // even though it is a GO.
641  send (*pComm, static_cast<int> (theirNumRows),
642  theirNumEntriesPerRow.getRawPtr(), p);
643 
644  // Figure out how many entries Proc p owns.
645  const local_ordinal_type theirNumEntries =
646  std::accumulate (theirNumEntriesPerRow.begin(),
647  theirNumEntriesPerRow.end(), 0);
648 
649  if (debug) {
650  cerr << "-- Proc 0: Proc " << p << " owns "
651  << theirNumEntries << " entries" << endl;
652  }
653 
654  // If there are no entries to send, then we're done
655  // with Proc p.
656  if (theirNumEntries == 0) {
657  continue;
658  }
659 
660  // Construct (views of) proc p's column indices and
661  // values. Later, we might like to optimize for the
662  // (common) contiguous case, for which we don't need to
663  // copy data into separate "their*" arrays (we can just
664  // use contiguous views of the global arrays).
665  ArrayRCP<GO> theirColInd (theirNumEntries);
666  ArrayRCP<scalar_type> theirValues (theirNumEntries);
667  // Copy Proc p's part of the matrix into the their*
668  // arrays. It's important that theirCurPos be updated
669  // _before_ k, otherwise theirCurPos will get the wrong
670  // number of entries per row (it should be for the row
671  // in the just-completed iteration, not for the next
672  // iteration's row).
673  local_ordinal_type theirCurPos = 0;
674  for (size_type k = 0; k < theirNumRows;
675  theirCurPos += theirNumEntriesPerRow[k], k++) {
676  const local_ordinal_type curNumEntries = theirNumEntriesPerRow[k];
677  const GO theirRow = theirRows[k];
678  const local_ordinal_type curPos = rowPtr[theirRow];
679 
680  // Only copy if there are entries to copy, in order
681  // not to construct empty ranges for the ArrayRCP
682  // views.
683  if (curNumEntries > 0) {
684  ArrayView<GO> colIndView =
685  colInd (curPos, curNumEntries);
686  ArrayView<GO> theirColIndView =
687  theirColInd (theirCurPos, curNumEntries);
688  std::copy (colIndView.begin(), colIndView.end(),
689  theirColIndView.begin());
690 
691  ArrayView<scalar_type> valuesView =
692  values (curPos, curNumEntries);
693  ArrayView<scalar_type> theirValuesView =
694  theirValues (theirCurPos, curNumEntries);
695  std::copy (valuesView.begin(), valuesView.end(),
696  theirValuesView.begin());
697  }
698  }
699  // Send Proc p its column indices and values.
700  // Hopefully the cast to int doesn't overflow. This
701  // is unlikely, since it should fit in a LO, even
702  // though it is a GO.
703  send (*pComm, static_cast<int> (theirNumEntries),
704  theirColInd.getRawPtr(), p);
705  send (*pComm, static_cast<int> (theirNumEntries),
706  theirValues.getRawPtr(), p);
707 
708  if (debug) {
709  cerr << "-- Proc 0: Finished with proc " << p << endl;
710  }
711  } // If proc p owns at least one row
712  } // For each proc p not the root proc 0
713  } // If I'm (not) the root proc 0
714 
715  // Invalidate the input data to save space, since we don't
716  // need it anymore.
717  numEntriesPerRow = null;
718  rowPtr = null;
719  colInd = null;
720  values = null;
721 
722  if (debug && myRank == 0) {
723  cerr << "-- Proc 0: About to fill in myRowPtr" << endl;
724  }
725 
726  // Allocate and fill in myRowPtr (the row pointer array for
727  // my rank's rows). We delay this until the end because we
728  // don't need it to compute anything else in distribute().
729  // Each proc can do this work for itself, since it only needs
730  // myNumEntriesPerRow to do so.
731  myRowPtr = arcp<size_t> (myNumRows+1);
732  myRowPtr[0] = 0;
733  for (size_type k = 1; k < myNumRows+1; ++k) {
734  myRowPtr[k] = myRowPtr[k-1] + myNumEntriesPerRow[k-1];
735  }
736  if (extraDebug && debug) {
737  cerr << "Proc " << Teuchos::rank (*(pRowMap->getComm()))
738  << ": myRowPtr[0.." << myNumRows << "] = [";
739  for (size_type k = 0; k < myNumRows+1; ++k) {
740  cerr << myRowPtr[k];
741  if (k < myNumRows) {
742  cerr << " ";
743  }
744  }
745  cerr << "]" << endl << endl;
746  }
747 
748  if (debug && myRank == 0) {
749  cerr << "-- Proc 0: Done with distribute" << endl;
750  }
751  }
752 
766  static Teuchos::RCP<sparse_matrix_type>
767  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
768  Teuchos::ArrayRCP<size_t>& myRowPtr,
769  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
770  Teuchos::ArrayRCP<scalar_type>& myValues,
771  const Teuchos::RCP<const map_type>& pRowMap,
772  const Teuchos::RCP<const map_type>& pRangeMap,
773  const Teuchos::RCP<const map_type>& pDomainMap,
774  const bool callFillComplete = true)
775  {
776  using Teuchos::ArrayView;
777  using Teuchos::null;
778  using Teuchos::RCP;
779  using Teuchos::rcp;
780  using std::cerr;
781  using std::endl;
782  // Typedef to make certain type declarations shorter.
783  typedef global_ordinal_type GO;
784 
785  // The row pointer array always has at least one entry, even
786  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
787  // and myValues would all be empty arrays in that degenerate
788  // case, but the row and domain maps would still be nonnull
789  // (though they would be trivial maps).
790  TEUCHOS_TEST_FOR_EXCEPTION(myRowPtr.is_null(), std::logic_error,
791  "makeMatrix: myRowPtr array is null. "
792  "Please report this bug to the Tpetra developers.");
793  TEUCHOS_TEST_FOR_EXCEPTION(pDomainMap.is_null(), std::logic_error,
794  "makeMatrix: domain map is null. "
795  "Please report this bug to the Tpetra developers.");
796  TEUCHOS_TEST_FOR_EXCEPTION(pRangeMap.is_null(), std::logic_error,
797  "makeMatrix: range map is null. "
798  "Please report this bug to the Tpetra developers.");
799  TEUCHOS_TEST_FOR_EXCEPTION(pRowMap.is_null(), std::logic_error,
800  "makeMatrix: row map is null. "
801  "Please report this bug to the Tpetra developers.");
802 
803  // Construct the CrsMatrix, using the row map, with the
804  // constructor specifying the number of nonzeros for each row.
805  RCP<sparse_matrix_type> A =
806  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow ()));
807 
808  // List of the global indices of my rows.
809  // They may or may not be contiguous.
810  ArrayView<const GO> myRows = pRowMap->getLocalElementList ();
811  const size_type myNumRows = myRows.size ();
812 
813  // Add this processor's matrix entries to the CrsMatrix.
814  const GO indexBase = pRowMap->getIndexBase ();
815  for (size_type i = 0; i < myNumRows; ++i) {
816  const size_type myCurPos = myRowPtr[i];
817  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
818  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
819  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
820 
821  // Modify the column indices in place to have the right index base.
822  for (size_type k = 0; k < curNumEntries; ++k) {
823  curColInd[k] += indexBase;
824  }
825  // Avoid constructing empty views of ArrayRCP objects.
826  if (curNumEntries > 0) {
827  A->insertGlobalValues (myRows[i], curColInd, curValues);
828  }
829  }
830  // We've entered in all our matrix entries, so we can delete
831  // the original data. This will save memory when we call
832  // fillComplete(), so that we never keep more than two copies
833  // of the matrix's data in memory at once.
834  myNumEntriesPerRow = null;
835  myRowPtr = null;
836  myColInd = null;
837  myValues = null;
838 
839  if (callFillComplete) {
840  A->fillComplete (pDomainMap, pRangeMap);
841  }
842  return A;
843  }
844 
850  static Teuchos::RCP<sparse_matrix_type>
851  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
852  Teuchos::ArrayRCP<size_t>& myRowPtr,
853  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
854  Teuchos::ArrayRCP<scalar_type>& myValues,
855  const Teuchos::RCP<const map_type>& pRowMap,
856  const Teuchos::RCP<const map_type>& pRangeMap,
857  const Teuchos::RCP<const map_type>& pDomainMap,
858  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
859  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
860  {
861  using Teuchos::ArrayView;
862  using Teuchos::null;
863  using Teuchos::RCP;
864  using Teuchos::rcp;
865  using std::cerr;
866  using std::endl;
867  // Typedef to make certain type declarations shorter.
868  typedef global_ordinal_type GO;
869 
870  // The row pointer array always has at least one entry, even
871  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
872  // and myValues would all be empty arrays in that degenerate
873  // case, but the row and domain maps would still be nonnull
874  // (though they would be trivial maps).
875  TEUCHOS_TEST_FOR_EXCEPTION(
876  myRowPtr.is_null(), std::logic_error,
877  "makeMatrix: myRowPtr array is null. "
878  "Please report this bug to the Tpetra developers.");
879  TEUCHOS_TEST_FOR_EXCEPTION(
880  pDomainMap.is_null(), std::logic_error,
881  "makeMatrix: domain map is null. "
882  "Please report this bug to the Tpetra developers.");
883  TEUCHOS_TEST_FOR_EXCEPTION(
884  pRangeMap.is_null(), std::logic_error,
885  "makeMatrix: range map is null. "
886  "Please report this bug to the Tpetra developers.");
887  TEUCHOS_TEST_FOR_EXCEPTION(
888  pRowMap.is_null(), std::logic_error,
889  "makeMatrix: row map is null. "
890  "Please report this bug to the Tpetra developers.");
891 
892  // Construct the CrsMatrix, using the row map, with the
893  // constructor specifying the number of nonzeros for each row.
894  RCP<sparse_matrix_type> A =
895  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
896  constructorParams));
897 
898  // List of the global indices of my rows.
899  // They may or may not be contiguous.
900  ArrayView<const GO> myRows = pRowMap->getLocalElementList();
901  const size_type myNumRows = myRows.size();
902 
903  // Add this processor's matrix entries to the CrsMatrix.
904  const GO indexBase = pRowMap->getIndexBase ();
905  for (size_type i = 0; i < myNumRows; ++i) {
906  const size_type myCurPos = myRowPtr[i];
907  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
908  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
909  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
910 
911  // Modify the column indices in place to have the right index base.
912  for (size_type k = 0; k < curNumEntries; ++k) {
913  curColInd[k] += indexBase;
914  }
915  if (curNumEntries > 0) {
916  A->insertGlobalValues (myRows[i], curColInd, curValues);
917  }
918  }
919  // We've entered in all our matrix entries, so we can delete
920  // the original data. This will save memory when we call
921  // fillComplete(), so that we never keep more than two copies
922  // of the matrix's data in memory at once.
923  myNumEntriesPerRow = null;
924  myRowPtr = null;
925  myColInd = null;
926  myValues = null;
927 
928  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
929  return A;
930  }
931 
936  static Teuchos::RCP<sparse_matrix_type>
937  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
938  Teuchos::ArrayRCP<size_t>& myRowPtr,
939  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
940  Teuchos::ArrayRCP<scalar_type>& myValues,
941  const Teuchos::RCP<const map_type>& rowMap,
942  Teuchos::RCP<const map_type>& colMap,
943  const Teuchos::RCP<const map_type>& domainMap,
944  const Teuchos::RCP<const map_type>& rangeMap,
945  const bool callFillComplete = true)
946  {
947  using Teuchos::ArrayView;
948  using Teuchos::as;
949  using Teuchos::null;
950  using Teuchos::RCP;
951  using Teuchos::rcp;
952  typedef global_ordinal_type GO;
953 
954  // Construct the CrsMatrix.
955 
956  RCP<sparse_matrix_type> A; // the matrix to return.
957  if (colMap.is_null ()) { // the user didn't provide a column Map
958  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow));
959  } else { // the user provided a column Map
960  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow));
961  }
962 
963  // List of the global indices of my rows.
964  // They may or may not be contiguous.
965  ArrayView<const GO> myRows = rowMap->getLocalElementList ();
966  const size_type myNumRows = myRows.size ();
967 
968  // Add this process' matrix entries to the CrsMatrix.
969  const GO indexBase = rowMap->getIndexBase ();
970  for (size_type i = 0; i < myNumRows; ++i) {
971  const size_type myCurPos = myRowPtr[i];
972  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
973  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
974  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
975 
976  // Modify the column indices in place to have the right index base.
977  for (size_type k = 0; k < curNumEntries; ++k) {
978  curColInd[k] += indexBase;
979  }
980  if (curNumEntries > 0) {
981  A->insertGlobalValues (myRows[i], curColInd, curValues);
982  }
983  }
984  // We've entered in all our matrix entries, so we can delete
985  // the original data. This will save memory when we call
986  // fillComplete(), so that we never keep more than two copies
987  // of the matrix's data in memory at once.
988  myNumEntriesPerRow = null;
989  myRowPtr = null;
990  myColInd = null;
991  myValues = null;
992 
993  if (callFillComplete) {
994  A->fillComplete (domainMap, rangeMap);
995  if (colMap.is_null ()) {
996  colMap = A->getColMap ();
997  }
998  }
999  return A;
1000  }
1001 
1002  private:
1003 
1020  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1021  readBanner (std::istream& in,
1022  size_t& lineNumber,
1023  const bool tolerant=false,
1024  const bool /* debug */=false,
1025  const bool isGraph=false)
1026  {
1027  using Teuchos::MatrixMarket::Banner;
1028  using Teuchos::RCP;
1029  using Teuchos::rcp;
1030  using std::cerr;
1031  using std::endl;
1032  typedef Teuchos::ScalarTraits<scalar_type> STS;
1033 
1034  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1035  std::string line; // If read from stream successful: the Banner line
1036 
1037  // Try to read a line from the input stream.
1038  const bool readFailed = ! getline(in, line);
1039  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1040  "Failed to get Matrix Market banner line from input.");
1041 
1042  // We read a line from the input stream.
1043  lineNumber++;
1044 
1045  // Assume that the line we found is the Banner line.
1046  try {
1047  pBanner = rcp (new Banner (line, tolerant));
1048  } catch (std::exception& e) {
1049 
1050  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1051  "Matrix Market banner line contains syntax error(s): "
1052  << e.what());
1053  }
1054 
1055  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1056  std::invalid_argument, "The Matrix Market file does not contain "
1057  "matrix data. Its Banner (first) line says that its object type is \""
1058  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1059 
1060  // Validate the data type of the matrix, with respect to the
1061  // Scalar type of the CrsMatrix entries.
1062  TEUCHOS_TEST_FOR_EXCEPTION(
1063  ! STS::isComplex && pBanner->dataType() == "complex",
1064  std::invalid_argument,
1065  "The Matrix Market file contains complex-valued data, but you are "
1066  "trying to read it into a matrix containing entries of the real-"
1067  "valued Scalar type \""
1068  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1069  TEUCHOS_TEST_FOR_EXCEPTION(
1070  !isGraph &&
1071  pBanner->dataType() != "real" &&
1072  pBanner->dataType() != "complex" &&
1073  pBanner->dataType() != "integer",
1074  std::invalid_argument,
1075  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1076  "Matrix Market file may not contain a \"pattern\" matrix. A "
1077  "pattern matrix is really just a graph with no weights. It "
1078  "should be stored in a CrsGraph, not a CrsMatrix.");
1079 
1080  TEUCHOS_TEST_FOR_EXCEPTION(
1081  isGraph &&
1082  pBanner->dataType() != "pattern",
1083  std::invalid_argument,
1084  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1085  "Matrix Market file must contain a \"pattern\" matrix.");
1086 
1087  return pBanner;
1088  }
1089 
1112  static Teuchos::Tuple<global_ordinal_type, 3>
1113  readCoordDims (std::istream& in,
1114  size_t& lineNumber,
1115  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1116  const Teuchos::RCP<const comm_type>& pComm,
1117  const bool tolerant = false,
1118  const bool /* debug */ = false)
1119  {
1120  using Teuchos::MatrixMarket::readCoordinateDimensions;
1121  using Teuchos::Tuple;
1122 
1123  // Packed coordinate matrix dimensions (numRows, numCols,
1124  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1125  // ranks.
1126  Tuple<global_ordinal_type, 3> dims;
1127 
1128  // Read in the coordinate matrix dimensions from the input
1129  // stream. "success" tells us whether reading in the
1130  // coordinate matrix dimensions succeeded ("Guilty unless
1131  // proven innocent").
1132  bool success = false;
1133  if (pComm->getRank() == 0) {
1134  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1135  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1136  "only accepts \"coordinate\" (sparse) matrix data.");
1137  // Unpacked coordinate matrix dimensions
1138  global_ordinal_type numRows, numCols, numNonzeros;
1139  // Only MPI Rank 0 reads from the input stream
1140  success = readCoordinateDimensions (in, numRows, numCols,
1141  numNonzeros, lineNumber,
1142  tolerant);
1143  // Pack up the data into a Tuple so we can send them with
1144  // one broadcast instead of three.
1145  dims[0] = numRows;
1146  dims[1] = numCols;
1147  dims[2] = numNonzeros;
1148  }
1149  // Only Rank 0 did the reading, so it decides success.
1150  //
1151  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1152  // to send bools. For now, we convert to/from int instead,
1153  // using the usual "true is 1, false is 0" encoding.
1154  {
1155  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1156  Teuchos::broadcast (*pComm, 0, &the_success);
1157  success = (the_success == 1);
1158  }
1159  if (success) {
1160  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1161  // to all the other MPI ranks.
1162  Teuchos::broadcast (*pComm, 0, dims);
1163  }
1164  else {
1165  // Perhaps in tolerant mode, we could set all the
1166  // dimensions to zero for now, and deduce correct
1167  // dimensions by reading all of the file's entries and
1168  // computing the max(row index) and max(column index).
1169  // However, for now we just error out in that case.
1170  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1171  "Error reading Matrix Market sparse matrix: failed to read "
1172  "coordinate matrix dimensions.");
1173  }
1174  return dims;
1175  }
1176 
1187  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1188 
1189  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1190 
1216  static Teuchos::RCP<adder_type>
1217  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1218  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1219  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1220  const bool tolerant=false,
1221  const bool debug=false)
1222  {
1223  if (pComm->getRank () == 0) {
1224  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1226  raw_adder_type;
1227  Teuchos::RCP<raw_adder_type> pRaw =
1228  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1229  tolerant, debug));
1230  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1231  }
1232  else {
1233  return Teuchos::null;
1234  }
1235  }
1236 
1262  static Teuchos::RCP<graph_adder_type>
1263  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1264  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1265  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1266  const bool tolerant=false,
1267  const bool debug=false)
1268  {
1269  if (pComm->getRank () == 0) {
1270  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1271  Teuchos::RCP<raw_adder_type> pRaw =
1272  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1273  tolerant, debug));
1274  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1275  }
1276  else {
1277  return Teuchos::null;
1278  }
1279  }
1280 
1282  static Teuchos::RCP<sparse_graph_type>
1283  readSparseGraphHelper (std::istream& in,
1284  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1285  const Teuchos::RCP<const map_type>& rowMap,
1286  Teuchos::RCP<const map_type>& colMap,
1287  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1288  const bool tolerant,
1289  const bool debug)
1290  {
1291  using Teuchos::MatrixMarket::Banner;
1292  using Teuchos::RCP;
1293  using Teuchos::ptr;
1294  using Teuchos::Tuple;
1295  using std::cerr;
1296  using std::endl;
1297 
1298  const int myRank = pComm->getRank ();
1299  const int rootRank = 0;
1300 
1301  // Current line number in the input stream. Various calls
1302  // will modify this depending on the number of lines that are
1303  // read from the input stream. Only Rank 0 modifies this.
1304  size_t lineNumber = 1;
1305 
1306  if (debug && myRank == rootRank) {
1307  cerr << "Matrix Market reader: readGraph:" << endl
1308  << "-- Reading banner line" << endl;
1309  }
1310 
1311  // The "Banner" tells you whether the input stream represents
1312  // a sparse matrix, the symmetry type of the matrix, and the
1313  // type of the data it contains.
1314  //
1315  // pBanner will only be nonnull on MPI Rank 0. It will be
1316  // null on all other MPI processes.
1317  RCP<const Banner> pBanner;
1318  {
1319  // We read and validate the Banner on Proc 0, but broadcast
1320  // the validation result to all processes.
1321  // Teuchos::broadcast doesn't currently work with bool, so
1322  // we use int (true -> 1, false -> 0).
1323  int bannerIsCorrect = 1;
1324  std::ostringstream errMsg;
1325 
1326  if (myRank == rootRank) {
1327  // Read the Banner line from the input stream.
1328  try {
1329  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1330  }
1331  catch (std::exception& e) {
1332  errMsg << "Attempt to read the Matrix Market file's Banner line "
1333  "threw an exception: " << e.what();
1334  bannerIsCorrect = 0;
1335  }
1336 
1337  if (bannerIsCorrect) {
1338  // Validate the Banner for the case of a sparse graph.
1339  // We validate on Proc 0, since it reads the Banner.
1340 
1341  // In intolerant mode, the matrix type must be "coordinate".
1342  if (! tolerant && pBanner->matrixType() != "coordinate") {
1343  bannerIsCorrect = 0;
1344  errMsg << "The Matrix Market input file must contain a "
1345  "\"coordinate\"-format sparse graph in order to create a "
1346  "Tpetra::CrsGraph object from it, but the file's matrix "
1347  "type is \"" << pBanner->matrixType() << "\" instead.";
1348  }
1349  // In tolerant mode, we allow the matrix type to be
1350  // anything other than "array" (which would mean that
1351  // the file contains a dense matrix).
1352  if (tolerant && pBanner->matrixType() == "array") {
1353  bannerIsCorrect = 0;
1354  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1355  "format sparse graph in order to create a Tpetra::CrsGraph "
1356  "object from it, but the file's matrix type is \"array\" "
1357  "instead. That probably means the file contains dense matrix "
1358  "data.";
1359  }
1360  }
1361  } // Proc 0: Done reading the Banner, hopefully successfully.
1362 
1363  // Broadcast from Proc 0 whether the Banner was read correctly.
1364  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1365 
1366  // If the Banner is invalid, all processes throw an
1367  // exception. Only Proc 0 gets the exception message, but
1368  // that's OK, since the main point is to "stop the world"
1369  // (rather than throw an exception on one process and leave
1370  // the others hanging).
1371  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1372  std::invalid_argument, errMsg.str ());
1373  } // Done reading the Banner line and broadcasting success.
1374  if (debug && myRank == rootRank) {
1375  cerr << "-- Reading dimensions line" << endl;
1376  }
1377 
1378  // Read the graph dimensions from the Matrix Market metadata.
1379  // dims = (numRows, numCols, numEntries). Proc 0 does the
1380  // reading, but it broadcasts the results to all MPI
1381  // processes. Thus, readCoordDims() is a collective
1382  // operation. It does a collective check for correctness too.
1383  Tuple<global_ordinal_type, 3> dims =
1384  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1385 
1386  if (debug && myRank == rootRank) {
1387  cerr << "-- Making Adder for collecting graph data" << endl;
1388  }
1389 
1390  // "Adder" object for collecting all the sparse graph entries
1391  // from the input stream. This is only nonnull on Proc 0.
1392  // The Adder internally converts the one-based indices (native
1393  // Matrix Market format) into zero-based indices.
1394  RCP<graph_adder_type> pAdder =
1395  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1396 
1397  if (debug && myRank == rootRank) {
1398  cerr << "-- Reading graph data" << endl;
1399  }
1400  //
1401  // Read the graph entries from the input stream on Proc 0.
1402  //
1403  {
1404  // We use readSuccess to broadcast the results of the read
1405  // (succeeded or not) to all MPI processes. Since
1406  // Teuchos::broadcast doesn't currently know how to send
1407  // bools, we convert to int (true -> 1, false -> 0).
1408  int readSuccess = 1;
1409  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1410  if (myRank == rootRank) {
1411  try {
1412  // Reader for "coordinate" format sparse graph data.
1413  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1414  global_ordinal_type> reader_type;
1415  reader_type reader (pAdder);
1416 
1417  // Read the sparse graph entries.
1418  std::pair<bool, std::vector<size_t> > results =
1419  reader.read (in, lineNumber, tolerant, debug);
1420  readSuccess = results.first ? 1 : 0;
1421  }
1422  catch (std::exception& e) {
1423  readSuccess = 0;
1424  errMsg << e.what();
1425  }
1426  }
1427  broadcast (*pComm, rootRank, ptr (&readSuccess));
1428 
1429  // It would be nice to add a "verbose" flag, so that in
1430  // tolerant mode, we could log any bad line number(s) on
1431  // Proc 0. For now, we just throw if the read fails to
1432  // succeed.
1433  //
1434  // Question: If we're in tolerant mode, and if the read did
1435  // not succeed, should we attempt to call fillComplete()?
1436  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1437  "Failed to read the Matrix Market sparse graph file: "
1438  << errMsg.str());
1439  } // Done reading the graph entries (stored on Proc 0 for now)
1440 
1441  if (debug && myRank == rootRank) {
1442  cerr << "-- Successfully read the Matrix Market data" << endl;
1443  }
1444 
1445  // In tolerant mode, we need to rebroadcast the graph
1446  // dimensions, since they may be different after reading the
1447  // actual graph data. We only need to broadcast the number
1448  // of rows and columns. Only Rank 0 needs to know the actual
1449  // global number of entries, since (a) we need to merge
1450  // duplicates on Rank 0 first anyway, and (b) when we
1451  // distribute the entries, each rank other than Rank 0 will
1452  // only need to know how many entries it owns, not the total
1453  // number of entries.
1454  if (tolerant) {
1455  if (debug && myRank == rootRank) {
1456  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1457  << endl
1458  << "----- Dimensions before: "
1459  << dims[0] << " x " << dims[1]
1460  << endl;
1461  }
1462  // Packed coordinate graph dimensions (numRows, numCols).
1463  Tuple<global_ordinal_type, 2> updatedDims;
1464  if (myRank == rootRank) {
1465  // If one or more bottom rows of the graph contain no
1466  // entries, then the Adder will report that the number
1467  // of rows is less than that specified in the
1468  // metadata. We allow this case, and favor the
1469  // metadata so that the zero row(s) will be included.
1470  updatedDims[0] =
1471  std::max (dims[0], pAdder->getAdder()->numRows());
1472  updatedDims[1] = pAdder->getAdder()->numCols();
1473  }
1474  broadcast (*pComm, rootRank, updatedDims);
1475  dims[0] = updatedDims[0];
1476  dims[1] = updatedDims[1];
1477  if (debug && myRank == rootRank) {
1478  cerr << "----- Dimensions after: " << dims[0] << " x "
1479  << dims[1] << endl;
1480  }
1481  }
1482  else {
1483  // In strict mode, we require that the graph's metadata and
1484  // its actual data agree, at least somewhat. In particular,
1485  // the number of rows must agree, since otherwise we cannot
1486  // distribute the graph correctly.
1487 
1488  // Teuchos::broadcast() doesn't know how to broadcast bools,
1489  // so we use an int with the standard 1 == true, 0 == false
1490  // encoding.
1491  int dimsMatch = 1;
1492  if (myRank == rootRank) {
1493  // If one or more bottom rows of the graph contain no
1494  // entries, then the Adder will report that the number of
1495  // rows is less than that specified in the metadata. We
1496  // allow this case, and favor the metadata, but do not
1497  // allow the Adder to think there are more rows in the
1498  // graph than the metadata says.
1499  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1500  dimsMatch = 0;
1501  }
1502  }
1503  broadcast (*pComm, 0, ptr (&dimsMatch));
1504  if (dimsMatch == 0) {
1505  // We're in an error state anyway, so we might as well
1506  // work a little harder to print an informative error
1507  // message.
1508  //
1509  // Broadcast the Adder's idea of the graph dimensions
1510  // from Proc 0 to all processes.
1511  Tuple<global_ordinal_type, 2> addersDims;
1512  if (myRank == rootRank) {
1513  addersDims[0] = pAdder->getAdder()->numRows();
1514  addersDims[1] = pAdder->getAdder()->numCols();
1515  }
1516  broadcast (*pComm, 0, addersDims);
1517  TEUCHOS_TEST_FOR_EXCEPTION(
1518  dimsMatch == 0, std::runtime_error,
1519  "The graph metadata says that the graph is " << dims[0] << " x "
1520  << dims[1] << ", but the actual data says that the graph is "
1521  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1522  "data includes more rows than reported in the metadata. This "
1523  "is not allowed when parsing in strict mode. Parse the graph in "
1524  "tolerant mode to ignore the metadata when it disagrees with the "
1525  "data.");
1526  }
1527  } // Matrix dimensions (# rows, # cols, # entries) agree.
1528 
1529  // Create a map describing a distribution where the root owns EVERYTHING
1530  RCP<map_type> proc0Map;
1531  global_ordinal_type indexBase;
1532  if(Teuchos::is_null(rowMap)) {
1533  indexBase = 0;
1534  }
1535  else {
1536  indexBase = rowMap->getIndexBase();
1537  }
1538  if(myRank == rootRank) {
1539  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1540  }
1541  else {
1542  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1543  }
1544 
1545  // Create the graph where the root owns EVERYTHING
1546  std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1547  if (myRank == rootRank) {
1548  const auto& entries = pAdder()->getAdder()->getEntries();
1549  // This will count duplicates, but it's better than dense.
1550  // An even better approach would use a classic algorithm,
1551  // likely in Saad's old textbook, for converting COO (entries)
1552  // to CSR (the local part of the sparse matrix data structure).
1553  for (const auto& entry : entries) {
1554  const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1555  ++numEntriesPerRow_map[gblRow];
1556  }
1557  }
1558 
1559  Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getLocalNumElements ());
1560  for (const auto& ent : numEntriesPerRow_map) {
1561  const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1562  numEntriesPerRow[lclRow] = ent.second;
1563  }
1564  // Free anything we don't need before allocating the graph.
1565  // Swapping with an empty data structure is the standard idiom
1566  // for freeing memory used by Standard Library containers.
1567  // (Just resizing to 0 doesn't promise to free memory.)
1568  {
1569  std::map<global_ordinal_type, size_t> empty_map;
1570  std::swap (numEntriesPerRow_map, empty_map);
1571  }
1572 
1573  RCP<sparse_graph_type> proc0Graph =
1574  rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1575  constructorParams));
1576  if(myRank == rootRank) {
1577  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1578 
1579  // Get the entries
1580  const std::vector<element_type>& entries =
1581  pAdder->getAdder()->getEntries();
1582 
1583  // Insert them one at a time
1584  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1585  const element_type& curEntry = entries[curPos];
1586  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1587  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1588  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1589  proc0Graph->insertGlobalIndices(curRow,colView);
1590  }
1591  }
1592  proc0Graph->fillComplete();
1593 
1594  RCP<sparse_graph_type> distGraph;
1595  if(Teuchos::is_null(rowMap))
1596  {
1597  // Create a map describing the distribution we actually want
1598  RCP<map_type> distMap =
1599  rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1600 
1601  // Create the graph with that distribution too
1602  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,constructorParams));
1603 
1604  // Create an importer/exporter/vandelay to redistribute the graph
1605  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1606  import_type importer (proc0Map, distMap);
1607 
1608  // Import the data
1609  distGraph->doImport(*proc0Graph,importer,INSERT);
1610  }
1611  else {
1612  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,constructorParams));
1613 
1614  // Create an importer/exporter/vandelay to redistribute the graph
1615  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1616  import_type importer (proc0Map, rowMap);
1617 
1618  // Import the data
1619  distGraph->doImport(*proc0Graph,importer,INSERT);
1620  }
1621 
1622  return distGraph;
1623  }
1624 
1625  public:
1649  static Teuchos::RCP<sparse_graph_type>
1650  readSparseGraphFile (const std::string& filename,
1651  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1652  const bool callFillComplete=true,
1653  const bool tolerant=false,
1654  const bool debug=false)
1655  {
1656  using Teuchos::broadcast;
1657  using Teuchos::outArg;
1658 
1659  // Only open the file on Process 0. Test carefully to make
1660  // sure that the file opened successfully (and broadcast that
1661  // result to all processes to prevent a hang on exception
1662  // throw), since it's a common mistake to misspell a filename.
1663  std::ifstream in;
1664  int opened = 0;
1665  if (comm->getRank () == 0) {
1666  try {
1667  in.open (filename.c_str ());
1668  opened = in.is_open();
1669  }
1670  catch (...) {
1671  opened = 0;
1672  }
1673  }
1674  broadcast<int, int> (*comm, 0, outArg (opened));
1675  TEUCHOS_TEST_FOR_EXCEPTION
1676  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1677  "Failed to open file \"" << filename << "\" on Process 0.");
1678  return readSparseGraph (in, comm,
1679  callFillComplete,
1680  tolerant, debug);
1681  // We can rely on the destructor of the input stream to close
1682  // the file on scope exit, even if readSparseGraph() throws an
1683  // exception.
1684  }
1685 
1686 
1715  static Teuchos::RCP<sparse_graph_type>
1716  readSparseGraphFile (const std::string& filename,
1717  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1718  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1719  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1720  const bool tolerant=false,
1721  const bool debug=false)
1722  {
1723  using Teuchos::broadcast;
1724  using Teuchos::outArg;
1725 
1726  // Only open the file on Process 0. Test carefully to make
1727  // sure that the file opened successfully (and broadcast that
1728  // result to all processes to prevent a hang on exception
1729  // throw), since it's a common mistake to misspell a filename.
1730  std::ifstream in;
1731  int opened = 0;
1732  if (pComm->getRank () == 0) {
1733  try {
1734  in.open (filename.c_str ());
1735  opened = in.is_open();
1736  }
1737  catch (...) {
1738  opened = 0;
1739  }
1740  }
1741  broadcast<int, int> (*pComm, 0, outArg (opened));
1742  TEUCHOS_TEST_FOR_EXCEPTION
1743  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1744  "Failed to open file \"" << filename << "\" on Process 0.");
1745  if (pComm->getRank () == 0) { // only open the input file on Process 0
1746  in.open (filename.c_str ());
1747  }
1748  return readSparseGraph (in, pComm,
1749  constructorParams,
1750  fillCompleteParams, tolerant, debug);
1751  // We can rely on the destructor of the input stream to close
1752  // the file on scope exit, even if readSparseGraph() throws an
1753  // exception.
1754  }
1755 
1756 
1794  static Teuchos::RCP<sparse_graph_type>
1795  readSparseGraphFile (const std::string& filename,
1796  const Teuchos::RCP<const map_type>& rowMap,
1797  Teuchos::RCP<const map_type>& colMap,
1798  const Teuchos::RCP<const map_type>& domainMap,
1799  const Teuchos::RCP<const map_type>& rangeMap,
1800  const bool callFillComplete=true,
1801  const bool tolerant=false,
1802  const bool debug=false)
1803  {
1804  using Teuchos::broadcast;
1805  using Teuchos::Comm;
1806  using Teuchos::outArg;
1807  using Teuchos::RCP;
1808 
1809  TEUCHOS_TEST_FOR_EXCEPTION
1810  (rowMap.is_null (), std::invalid_argument,
1811  "Input rowMap must be nonnull.");
1812  RCP<const Comm<int> > comm = rowMap->getComm ();
1813  if (comm.is_null ()) {
1814  // If the input communicator is null on some process, then
1815  // that process does not participate in the collective.
1816  return Teuchos::null;
1817  }
1818 
1819  // Only open the file on Process 0. Test carefully to make
1820  // sure that the file opened successfully (and broadcast that
1821  // result to all processes to prevent a hang on exception
1822  // throw), since it's a common mistake to misspell a filename.
1823  std::ifstream in;
1824  int opened = 0;
1825  if (comm->getRank () == 0) {
1826  try {
1827  in.open (filename.c_str ());
1828  opened = in.is_open();
1829  }
1830  catch (...) {
1831  opened = 0;
1832  }
1833  }
1834  broadcast<int, int> (*comm, 0, outArg (opened));
1835  TEUCHOS_TEST_FOR_EXCEPTION
1836  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1837  "Failed to open file \"" << filename << "\" on Process 0.");
1838  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1839  callFillComplete, tolerant, debug);
1840  }
1841 
1867  static Teuchos::RCP<sparse_graph_type>
1868  readSparseGraph (std::istream& in,
1869  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1870  const bool callFillComplete=true,
1871  const bool tolerant=false,
1872  const bool debug=false)
1873  {
1874  Teuchos::RCP<const map_type> fakeRowMap;
1875  Teuchos::RCP<const map_type> fakeColMap;
1876  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1877 
1878  Teuchos::RCP<sparse_graph_type> graph =
1879  readSparseGraphHelper (in, pComm,
1880  fakeRowMap, fakeColMap,
1881  fakeCtorParams, tolerant, debug);
1882  if (callFillComplete) {
1883  graph->fillComplete ();
1884  }
1885  return graph;
1886  }
1887 
1888 
1918  static Teuchos::RCP<sparse_graph_type>
1919  readSparseGraph (std::istream& in,
1920  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1921  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1922  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1923  const bool tolerant=false,
1924  const bool debug=false)
1925  {
1926  Teuchos::RCP<const map_type> fakeRowMap;
1927  Teuchos::RCP<const map_type> fakeColMap;
1928  Teuchos::RCP<sparse_graph_type> graph =
1929  readSparseGraphHelper (in, pComm,
1930  fakeRowMap, fakeColMap,
1931  constructorParams, tolerant, debug);
1932  graph->fillComplete (fillCompleteParams);
1933  return graph;
1934  }
1935 
1936 
1977  static Teuchos::RCP<sparse_graph_type>
1978  readSparseGraph (std::istream& in,
1979  const Teuchos::RCP<const map_type>& rowMap,
1980  Teuchos::RCP<const map_type>& colMap,
1981  const Teuchos::RCP<const map_type>& domainMap,
1982  const Teuchos::RCP<const map_type>& rangeMap,
1983  const bool callFillComplete=true,
1984  const bool tolerant=false,
1985  const bool debug=false)
1986  {
1987  Teuchos::RCP<sparse_graph_type> graph =
1988  readSparseGraphHelper (in, rowMap->getComm (),
1989  rowMap, colMap, Teuchos::null, tolerant,
1990  debug);
1991  if (callFillComplete) {
1992  graph->fillComplete (domainMap, rangeMap);
1993  }
1994  return graph;
1995  }
1996 
1997 #include "MatrixMarket_TpetraNew.hpp"
1998 
2022  static Teuchos::RCP<sparse_matrix_type>
2023  readSparseFile (const std::string& filename,
2024  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2025  const bool callFillComplete=true,
2026  const bool tolerant=false,
2027  const bool debug=false)
2028  {
2029  const int myRank = pComm->getRank ();
2030  std::ifstream in;
2031 
2032  // Only open the file on Rank 0.
2033  if (myRank == 0) {
2034  in.open (filename.c_str ());
2035  }
2036  // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2037  // opening the file succeeded, before continuing. That will
2038  // avoid hangs if the read doesn't work. On the other hand,
2039  // readSparse could do that too, by checking the status of the
2040  // std::ostream.
2041 
2042  return readSparse (in, pComm, callFillComplete, tolerant, debug);
2043  // We can rely on the destructor of the input stream to close
2044  // the file on scope exit, even if readSparse() throws an
2045  // exception.
2046  }
2047 
2048 
2077  static Teuchos::RCP<sparse_matrix_type>
2078  readSparseFile (const std::string& filename,
2079  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2080  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2081  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2082  const bool tolerant=false,
2083  const bool debug=false)
2084  {
2085  std::ifstream in;
2086  if (pComm->getRank () == 0) { // only open on Process 0
2087  in.open (filename.c_str ());
2088  }
2089  return readSparse (in, pComm, constructorParams,
2090  fillCompleteParams, tolerant, debug);
2091  }
2092 
2093 
2131  static Teuchos::RCP<sparse_matrix_type>
2132  readSparseFile (const std::string& filename,
2133  const Teuchos::RCP<const map_type>& rowMap,
2134  Teuchos::RCP<const map_type>& colMap,
2135  const Teuchos::RCP<const map_type>& domainMap,
2136  const Teuchos::RCP<const map_type>& rangeMap,
2137  const bool callFillComplete=true,
2138  const bool tolerant=false,
2139  const bool debug=false)
2140  {
2141  using Teuchos::broadcast;
2142  using Teuchos::Comm;
2143  using Teuchos::outArg;
2144  using Teuchos::RCP;
2145 
2146  TEUCHOS_TEST_FOR_EXCEPTION(
2147  rowMap.is_null (), std::invalid_argument,
2148  "Row Map must be nonnull.");
2149 
2150  RCP<const Comm<int> > comm = rowMap->getComm ();
2151  const int myRank = comm->getRank ();
2152 
2153  // Only open the file on Process 0. Test carefully to make
2154  // sure that the file opened successfully (and broadcast that
2155  // result to all processes to prevent a hang on exception
2156  // throw), since it's a common mistake to misspell a filename.
2157  std::ifstream in;
2158  int opened = 0;
2159  if (myRank == 0) {
2160  try {
2161  in.open (filename.c_str ());
2162  opened = in.is_open();
2163  }
2164  catch (...) {
2165  opened = 0;
2166  }
2167  }
2168  broadcast<int, int> (*comm, 0, outArg (opened));
2169  TEUCHOS_TEST_FOR_EXCEPTION(
2170  opened == 0, std::runtime_error,
2171  "readSparseFile: Failed to open file \"" << filename << "\" on "
2172  "Process 0.");
2173  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2174  callFillComplete, tolerant, debug);
2175  }
2176 
2202  static Teuchos::RCP<sparse_matrix_type>
2203  readSparse (std::istream& in,
2204  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2205  const bool callFillComplete=true,
2206  const bool tolerant=false,
2207  const bool debug=false)
2208  {
2209  using Teuchos::MatrixMarket::Banner;
2210  using Teuchos::arcp;
2211  using Teuchos::ArrayRCP;
2212  using Teuchos::broadcast;
2213  using Teuchos::null;
2214  using Teuchos::ptr;
2215  using Teuchos::RCP;
2216  using Teuchos::REDUCE_MAX;
2217  using Teuchos::reduceAll;
2218  using Teuchos::Tuple;
2219  using std::cerr;
2220  using std::endl;
2221  typedef Teuchos::ScalarTraits<scalar_type> STS;
2222 
2223  const bool extraDebug = false;
2224  const int myRank = pComm->getRank ();
2225  const int rootRank = 0;
2226 
2227  // Current line number in the input stream. Various calls
2228  // will modify this depending on the number of lines that are
2229  // read from the input stream. Only Rank 0 modifies this.
2230  size_t lineNumber = 1;
2231 
2232  if (debug && myRank == rootRank) {
2233  cerr << "Matrix Market reader: readSparse:" << endl
2234  << "-- Reading banner line" << endl;
2235  }
2236 
2237  // The "Banner" tells you whether the input stream represents
2238  // a sparse matrix, the symmetry type of the matrix, and the
2239  // type of the data it contains.
2240  //
2241  // pBanner will only be nonnull on MPI Rank 0. It will be
2242  // null on all other MPI processes.
2243  RCP<const Banner> pBanner;
2244  {
2245  // We read and validate the Banner on Proc 0, but broadcast
2246  // the validation result to all processes.
2247  // Teuchos::broadcast doesn't currently work with bool, so
2248  // we use int (true -> 1, false -> 0).
2249  int bannerIsCorrect = 1;
2250  std::ostringstream errMsg;
2251 
2252  if (myRank == rootRank) {
2253  // Read the Banner line from the input stream.
2254  try {
2255  pBanner = readBanner (in, lineNumber, tolerant, debug);
2256  }
2257  catch (std::exception& e) {
2258  errMsg << "Attempt to read the Matrix Market file's Banner line "
2259  "threw an exception: " << e.what();
2260  bannerIsCorrect = 0;
2261  }
2262 
2263  if (bannerIsCorrect) {
2264  // Validate the Banner for the case of a sparse matrix.
2265  // We validate on Proc 0, since it reads the Banner.
2266 
2267  // In intolerant mode, the matrix type must be "coordinate".
2268  if (! tolerant && pBanner->matrixType() != "coordinate") {
2269  bannerIsCorrect = 0;
2270  errMsg << "The Matrix Market input file must contain a "
2271  "\"coordinate\"-format sparse matrix in order to create a "
2272  "Tpetra::CrsMatrix object from it, but the file's matrix "
2273  "type is \"" << pBanner->matrixType() << "\" instead.";
2274  }
2275  // In tolerant mode, we allow the matrix type to be
2276  // anything other than "array" (which would mean that
2277  // the file contains a dense matrix).
2278  if (tolerant && pBanner->matrixType() == "array") {
2279  bannerIsCorrect = 0;
2280  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2281  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2282  "object from it, but the file's matrix type is \"array\" "
2283  "instead. That probably means the file contains dense matrix "
2284  "data.";
2285  }
2286  }
2287  } // Proc 0: Done reading the Banner, hopefully successfully.
2288 
2289  // Broadcast from Proc 0 whether the Banner was read correctly.
2290  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2291 
2292  // If the Banner is invalid, all processes throw an
2293  // exception. Only Proc 0 gets the exception message, but
2294  // that's OK, since the main point is to "stop the world"
2295  // (rather than throw an exception on one process and leave
2296  // the others hanging).
2297  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2298  std::invalid_argument, errMsg.str ());
2299  } // Done reading the Banner line and broadcasting success.
2300  if (debug && myRank == rootRank) {
2301  cerr << "-- Reading dimensions line" << endl;
2302  }
2303 
2304  // Read the matrix dimensions from the Matrix Market metadata.
2305  // dims = (numRows, numCols, numEntries). Proc 0 does the
2306  // reading, but it broadcasts the results to all MPI
2307  // processes. Thus, readCoordDims() is a collective
2308  // operation. It does a collective check for correctness too.
2309  Tuple<global_ordinal_type, 3> dims =
2310  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2311 
2312  if (debug && myRank == rootRank) {
2313  cerr << "-- Making Adder for collecting matrix data" << endl;
2314  }
2315 
2316  // "Adder" object for collecting all the sparse matrix entries
2317  // from the input stream. This is only nonnull on Proc 0.
2318  RCP<adder_type> pAdder =
2319  makeAdder (pComm, pBanner, dims, tolerant, debug);
2320 
2321  if (debug && myRank == rootRank) {
2322  cerr << "-- Reading matrix data" << endl;
2323  }
2324  //
2325  // Read the matrix entries from the input stream on Proc 0.
2326  //
2327  {
2328  // We use readSuccess to broadcast the results of the read
2329  // (succeeded or not) to all MPI processes. Since
2330  // Teuchos::broadcast doesn't currently know how to send
2331  // bools, we convert to int (true -> 1, false -> 0).
2332  int readSuccess = 1;
2333  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2334  if (myRank == rootRank) {
2335  try {
2336  // Reader for "coordinate" format sparse matrix data.
2337  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2338  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2339  reader_type reader (pAdder);
2340 
2341  // Read the sparse matrix entries.
2342  std::pair<bool, std::vector<size_t> > results =
2343  reader.read (in, lineNumber, tolerant, debug);
2344  readSuccess = results.first ? 1 : 0;
2345  }
2346  catch (std::exception& e) {
2347  readSuccess = 0;
2348  errMsg << e.what();
2349  }
2350  }
2351  broadcast (*pComm, rootRank, ptr (&readSuccess));
2352 
2353  // It would be nice to add a "verbose" flag, so that in
2354  // tolerant mode, we could log any bad line number(s) on
2355  // Proc 0. For now, we just throw if the read fails to
2356  // succeed.
2357  //
2358  // Question: If we're in tolerant mode, and if the read did
2359  // not succeed, should we attempt to call fillComplete()?
2360  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2361  "Failed to read the Matrix Market sparse matrix file: "
2362  << errMsg.str());
2363  } // Done reading the matrix entries (stored on Proc 0 for now)
2364 
2365  if (debug && myRank == rootRank) {
2366  cerr << "-- Successfully read the Matrix Market data" << endl;
2367  }
2368 
2369  // In tolerant mode, we need to rebroadcast the matrix
2370  // dimensions, since they may be different after reading the
2371  // actual matrix data. We only need to broadcast the number
2372  // of rows and columns. Only Rank 0 needs to know the actual
2373  // global number of entries, since (a) we need to merge
2374  // duplicates on Rank 0 first anyway, and (b) when we
2375  // distribute the entries, each rank other than Rank 0 will
2376  // only need to know how many entries it owns, not the total
2377  // number of entries.
2378  if (tolerant) {
2379  if (debug && myRank == rootRank) {
2380  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2381  << endl
2382  << "----- Dimensions before: "
2383  << dims[0] << " x " << dims[1]
2384  << endl;
2385  }
2386  // Packed coordinate matrix dimensions (numRows, numCols).
2387  Tuple<global_ordinal_type, 2> updatedDims;
2388  if (myRank == rootRank) {
2389  // If one or more bottom rows of the matrix contain no
2390  // entries, then the Adder will report that the number
2391  // of rows is less than that specified in the
2392  // metadata. We allow this case, and favor the
2393  // metadata so that the zero row(s) will be included.
2394  updatedDims[0] =
2395  std::max (dims[0], pAdder->getAdder()->numRows());
2396  updatedDims[1] = pAdder->getAdder()->numCols();
2397  }
2398  broadcast (*pComm, rootRank, updatedDims);
2399  dims[0] = updatedDims[0];
2400  dims[1] = updatedDims[1];
2401  if (debug && myRank == rootRank) {
2402  cerr << "----- Dimensions after: " << dims[0] << " x "
2403  << dims[1] << endl;
2404  }
2405  }
2406  else {
2407  // In strict mode, we require that the matrix's metadata and
2408  // its actual data agree, at least somewhat. In particular,
2409  // the number of rows must agree, since otherwise we cannot
2410  // distribute the matrix correctly.
2411 
2412  // Teuchos::broadcast() doesn't know how to broadcast bools,
2413  // so we use an int with the standard 1 == true, 0 == false
2414  // encoding.
2415  int dimsMatch = 1;
2416  if (myRank == rootRank) {
2417  // If one or more bottom rows of the matrix contain no
2418  // entries, then the Adder will report that the number of
2419  // rows is less than that specified in the metadata. We
2420  // allow this case, and favor the metadata, but do not
2421  // allow the Adder to think there are more rows in the
2422  // matrix than the metadata says.
2423  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2424  dimsMatch = 0;
2425  }
2426  }
2427  broadcast (*pComm, 0, ptr (&dimsMatch));
2428  if (dimsMatch == 0) {
2429  // We're in an error state anyway, so we might as well
2430  // work a little harder to print an informative error
2431  // message.
2432  //
2433  // Broadcast the Adder's idea of the matrix dimensions
2434  // from Proc 0 to all processes.
2435  Tuple<global_ordinal_type, 2> addersDims;
2436  if (myRank == rootRank) {
2437  addersDims[0] = pAdder->getAdder()->numRows();
2438  addersDims[1] = pAdder->getAdder()->numCols();
2439  }
2440  broadcast (*pComm, 0, addersDims);
2441  TEUCHOS_TEST_FOR_EXCEPTION(
2442  dimsMatch == 0, std::runtime_error,
2443  "The matrix metadata says that the matrix is " << dims[0] << " x "
2444  << dims[1] << ", but the actual data says that the matrix is "
2445  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2446  "data includes more rows than reported in the metadata. This "
2447  "is not allowed when parsing in strict mode. Parse the matrix in "
2448  "tolerant mode to ignore the metadata when it disagrees with the "
2449  "data.");
2450  }
2451  } // Matrix dimensions (# rows, # cols, # entries) agree.
2452 
2453  if (debug && myRank == rootRank) {
2454  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2455  }
2456 
2457  // Now that we've read in all the matrix entries from the
2458  // input stream into the adder on Proc 0, post-process them
2459  // into CSR format (still on Proc 0). This will facilitate
2460  // distributing them to all the processors.
2461  //
2462  // These arrays represent the global matrix data as a CSR
2463  // matrix (with numEntriesPerRow as redundant but convenient
2464  // metadata, since it's computable from rowPtr and vice
2465  // versa). They are valid only on Proc 0.
2466  ArrayRCP<size_t> numEntriesPerRow;
2467  ArrayRCP<size_t> rowPtr;
2468  ArrayRCP<global_ordinal_type> colInd;
2469  ArrayRCP<scalar_type> values;
2470 
2471  // Proc 0 first merges duplicate entries, and then converts
2472  // the coordinate-format matrix data to CSR.
2473  {
2474  int mergeAndConvertSucceeded = 1;
2475  std::ostringstream errMsg;
2476 
2477  if (myRank == rootRank) {
2478  try {
2479  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2480  global_ordinal_type> element_type;
2481 
2482  // Number of rows in the matrix. If we are in tolerant
2483  // mode, we've already synchronized dims with the actual
2484  // matrix data. If in strict mode, we should use dims
2485  // (as read from the file's metadata) rather than the
2486  // matrix data to determine the dimensions. (The matrix
2487  // data will claim fewer rows than the metadata, if one
2488  // or more rows have no entries stored in the file.)
2489  const size_type numRows = dims[0];
2490 
2491  // Additively merge duplicate matrix entries.
2492  pAdder->getAdder()->merge ();
2493 
2494  // Get a temporary const view of the merged matrix entries.
2495  const std::vector<element_type>& entries =
2496  pAdder->getAdder()->getEntries();
2497 
2498  // Number of matrix entries (after merging).
2499  const size_t numEntries = (size_t)entries.size();
2500 
2501  if (debug) {
2502  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2503  << " rows and numEntries=" << numEntries
2504  << " entries." << endl;
2505  }
2506 
2507  // Make space for the CSR matrix data. Converting to
2508  // CSR is easier if we fill numEntriesPerRow with zeros
2509  // at first.
2510  numEntriesPerRow = arcp<size_t> (numRows);
2511  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2512  rowPtr = arcp<size_t> (numRows+1);
2513  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2514  colInd = arcp<global_ordinal_type> (numEntries);
2515  values = arcp<scalar_type> (numEntries);
2516 
2517  // Convert from array-of-structs coordinate format to CSR
2518  // (compressed sparse row) format.
2519  global_ordinal_type prvRow = 0;
2520  size_t curPos = 0;
2521  rowPtr[0] = 0;
2522  for (curPos = 0; curPos < numEntries; ++curPos) {
2523  const element_type& curEntry = entries[curPos];
2524  const global_ordinal_type curRow = curEntry.rowIndex();
2525  TEUCHOS_TEST_FOR_EXCEPTION(
2526  curRow < prvRow, std::logic_error,
2527  "Row indices are out of order, even though they are supposed "
2528  "to be sorted. curRow = " << curRow << ", prvRow = "
2529  << prvRow << ", at curPos = " << curPos << ". Please report "
2530  "this bug to the Tpetra developers.");
2531  if (curRow > prvRow) {
2532  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2533  rowPtr[r] = curPos;
2534  }
2535  prvRow = curRow;
2536  }
2537  numEntriesPerRow[curRow]++;
2538  colInd[curPos] = curEntry.colIndex();
2539  values[curPos] = curEntry.value();
2540  }
2541  // rowPtr has one more entry than numEntriesPerRow. The
2542  // last entry of rowPtr is the number of entries in
2543  // colInd and values.
2544  rowPtr[numRows] = numEntries;
2545  } // Finished conversion to CSR format
2546  catch (std::exception& e) {
2547  mergeAndConvertSucceeded = 0;
2548  errMsg << "Failed to merge sparse matrix entries and convert to "
2549  "CSR format: " << e.what();
2550  }
2551 
2552  if (debug && mergeAndConvertSucceeded) {
2553  // Number of rows in the matrix.
2554  const size_type numRows = dims[0];
2555  const size_type maxToDisplay = 100;
2556 
2557  cerr << "----- Proc 0: numEntriesPerRow[0.."
2558  << (numEntriesPerRow.size()-1) << "] ";
2559  if (numRows > maxToDisplay) {
2560  cerr << "(only showing first and last few entries) ";
2561  }
2562  cerr << "= [";
2563  if (numRows > 0) {
2564  if (numRows > maxToDisplay) {
2565  for (size_type k = 0; k < 2; ++k) {
2566  cerr << numEntriesPerRow[k] << " ";
2567  }
2568  cerr << "... ";
2569  for (size_type k = numRows-2; k < numRows-1; ++k) {
2570  cerr << numEntriesPerRow[k] << " ";
2571  }
2572  }
2573  else {
2574  for (size_type k = 0; k < numRows-1; ++k) {
2575  cerr << numEntriesPerRow[k] << " ";
2576  }
2577  }
2578  cerr << numEntriesPerRow[numRows-1];
2579  } // numRows > 0
2580  cerr << "]" << endl;
2581 
2582  cerr << "----- Proc 0: rowPtr ";
2583  if (numRows > maxToDisplay) {
2584  cerr << "(only showing first and last few entries) ";
2585  }
2586  cerr << "= [";
2587  if (numRows > maxToDisplay) {
2588  for (size_type k = 0; k < 2; ++k) {
2589  cerr << rowPtr[k] << " ";
2590  }
2591  cerr << "... ";
2592  for (size_type k = numRows-2; k < numRows; ++k) {
2593  cerr << rowPtr[k] << " ";
2594  }
2595  }
2596  else {
2597  for (size_type k = 0; k < numRows; ++k) {
2598  cerr << rowPtr[k] << " ";
2599  }
2600  }
2601  cerr << rowPtr[numRows] << "]" << endl;
2602  }
2603  } // if myRank == rootRank
2604  } // Done converting sparse matrix data to CSR format
2605 
2606  // Now we're done with the Adder, so we can release the
2607  // reference ("free" it) to save space. This only actually
2608  // does anything on Rank 0, since pAdder is null on all the
2609  // other MPI processes.
2610  pAdder = null;
2611 
2612  if (debug && myRank == rootRank) {
2613  cerr << "-- Making range, domain, and row maps" << endl;
2614  }
2615 
2616  // Make the maps that describe the matrix's range and domain,
2617  // and the distribution of its rows. Creating a Map is a
2618  // collective operation, so we don't have to do a broadcast of
2619  // a success Boolean.
2620  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2621  RCP<const map_type> pDomainMap =
2622  makeDomainMap (pRangeMap, dims[0], dims[1]);
2623  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2624 
2625  if (debug && myRank == rootRank) {
2626  cerr << "-- Distributing the matrix data" << endl;
2627  }
2628 
2629  // Distribute the matrix data. Each processor has to add the
2630  // rows that it owns. If you try to make Proc 0 call
2631  // insertGlobalValues() for _all_ the rows, not just those it
2632  // owns, then fillComplete() will compute the number of
2633  // columns incorrectly. That's why Proc 0 has to distribute
2634  // the matrix data and why we make all the processors (not
2635  // just Proc 0) call insertGlobalValues() on their own data.
2636  //
2637  // These arrays represent each processor's part of the matrix
2638  // data, in "CSR" format (sort of, since the row indices might
2639  // not be contiguous).
2640  ArrayRCP<size_t> myNumEntriesPerRow;
2641  ArrayRCP<size_t> myRowPtr;
2642  ArrayRCP<global_ordinal_type> myColInd;
2643  ArrayRCP<scalar_type> myValues;
2644  // Distribute the matrix data. This is a collective operation.
2645  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2646  numEntriesPerRow, rowPtr, colInd, values, debug);
2647 
2648  if (debug && myRank == rootRank) {
2649  cerr << "-- Inserting matrix entries on each processor";
2650  if (callFillComplete) {
2651  cerr << " and calling fillComplete()";
2652  }
2653  cerr << endl;
2654  }
2655  // Each processor inserts its part of the matrix data, and
2656  // then they all call fillComplete(). This method invalidates
2657  // the my* distributed matrix data before calling
2658  // fillComplete(), in order to save space. In general, we
2659  // never store more than two copies of the matrix's entries in
2660  // memory at once, which is no worse than what Tpetra
2661  // promises.
2662  RCP<sparse_matrix_type> pMatrix =
2663  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2664  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2665  // Only use a reduce-all in debug mode to check if pMatrix is
2666  // null. Otherwise, just throw an exception. We never expect
2667  // a null pointer here, so we can save a communication.
2668  if (debug) {
2669  int localIsNull = pMatrix.is_null () ? 1 : 0;
2670  int globalIsNull = 0;
2671  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2672  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2673  "Reader::makeMatrix() returned a null pointer on at least one "
2674  "process. Please report this bug to the Tpetra developers.");
2675  }
2676  else {
2677  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2678  "Reader::makeMatrix() returned a null pointer. "
2679  "Please report this bug to the Tpetra developers.");
2680  }
2681 
2682  // We can't get the dimensions of the matrix until after
2683  // fillComplete() is called. Thus, we can't do the sanity
2684  // check (dimensions read from the Matrix Market data,
2685  // vs. dimensions reported by the CrsMatrix) unless the user
2686  // asked makeMatrix() to call fillComplete().
2687  //
2688  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2689  // what one might think it does, so you have to ask the range
2690  // resp. domain map for the number of rows resp. columns.
2691  if (callFillComplete) {
2692  const int numProcs = pComm->getSize ();
2693 
2694  if (extraDebug && debug) {
2695  const global_size_t globalNumRows =
2696  pRangeMap->getGlobalNumElements ();
2697  const global_size_t globalNumCols =
2698  pDomainMap->getGlobalNumElements ();
2699  if (myRank == rootRank) {
2700  cerr << "-- Matrix is "
2701  << globalNumRows << " x " << globalNumCols
2702  << " with " << pMatrix->getGlobalNumEntries()
2703  << " entries, and index base "
2704  << pMatrix->getIndexBase() << "." << endl;
2705  }
2706  pComm->barrier ();
2707  for (int p = 0; p < numProcs; ++p) {
2708  if (myRank == p) {
2709  cerr << "-- Proc " << p << " owns "
2710  << pMatrix->getLocalNumCols() << " columns, and "
2711  << pMatrix->getLocalNumEntries() << " entries." << endl;
2712  }
2713  pComm->barrier ();
2714  }
2715  } // if (extraDebug && debug)
2716  } // if (callFillComplete)
2717 
2718  if (debug && myRank == rootRank) {
2719  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2720  << endl;
2721  }
2722  return pMatrix;
2723  }
2724 
2725 
2754  static Teuchos::RCP<sparse_matrix_type>
2755  readSparse (std::istream& in,
2756  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2757  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2758  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2759  const bool tolerant=false,
2760  const bool debug=false)
2761  {
2762  using Teuchos::MatrixMarket::Banner;
2763  using Teuchos::arcp;
2764  using Teuchos::ArrayRCP;
2765  using Teuchos::broadcast;
2766  using Teuchos::null;
2767  using Teuchos::ptr;
2768  using Teuchos::RCP;
2769  using Teuchos::reduceAll;
2770  using Teuchos::Tuple;
2771  using std::cerr;
2772  using std::endl;
2773  typedef Teuchos::ScalarTraits<scalar_type> STS;
2774 
2775  const bool extraDebug = false;
2776  const int myRank = pComm->getRank ();
2777  const int rootRank = 0;
2778 
2779  // Current line number in the input stream. Various calls
2780  // will modify this depending on the number of lines that are
2781  // read from the input stream. Only Rank 0 modifies this.
2782  size_t lineNumber = 1;
2783 
2784  if (debug && myRank == rootRank) {
2785  cerr << "Matrix Market reader: readSparse:" << endl
2786  << "-- Reading banner line" << endl;
2787  }
2788 
2789  // The "Banner" tells you whether the input stream represents
2790  // a sparse matrix, the symmetry type of the matrix, and the
2791  // type of the data it contains.
2792  //
2793  // pBanner will only be nonnull on MPI Rank 0. It will be
2794  // null on all other MPI processes.
2795  RCP<const Banner> pBanner;
2796  {
2797  // We read and validate the Banner on Proc 0, but broadcast
2798  // the validation result to all processes.
2799  // Teuchos::broadcast doesn't currently work with bool, so
2800  // we use int (true -> 1, false -> 0).
2801  int bannerIsCorrect = 1;
2802  std::ostringstream errMsg;
2803 
2804  if (myRank == rootRank) {
2805  // Read the Banner line from the input stream.
2806  try {
2807  pBanner = readBanner (in, lineNumber, tolerant, debug);
2808  }
2809  catch (std::exception& e) {
2810  errMsg << "Attempt to read the Matrix Market file's Banner line "
2811  "threw an exception: " << e.what();
2812  bannerIsCorrect = 0;
2813  }
2814 
2815  if (bannerIsCorrect) {
2816  // Validate the Banner for the case of a sparse matrix.
2817  // We validate on Proc 0, since it reads the Banner.
2818 
2819  // In intolerant mode, the matrix type must be "coordinate".
2820  if (! tolerant && pBanner->matrixType() != "coordinate") {
2821  bannerIsCorrect = 0;
2822  errMsg << "The Matrix Market input file must contain a "
2823  "\"coordinate\"-format sparse matrix in order to create a "
2824  "Tpetra::CrsMatrix object from it, but the file's matrix "
2825  "type is \"" << pBanner->matrixType() << "\" instead.";
2826  }
2827  // In tolerant mode, we allow the matrix type to be
2828  // anything other than "array" (which would mean that
2829  // the file contains a dense matrix).
2830  if (tolerant && pBanner->matrixType() == "array") {
2831  bannerIsCorrect = 0;
2832  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2833  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2834  "object from it, but the file's matrix type is \"array\" "
2835  "instead. That probably means the file contains dense matrix "
2836  "data.";
2837  }
2838  }
2839  } // Proc 0: Done reading the Banner, hopefully successfully.
2840 
2841  // Broadcast from Proc 0 whether the Banner was read correctly.
2842  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2843 
2844  // If the Banner is invalid, all processes throw an
2845  // exception. Only Proc 0 gets the exception message, but
2846  // that's OK, since the main point is to "stop the world"
2847  // (rather than throw an exception on one process and leave
2848  // the others hanging).
2849  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2850  std::invalid_argument, errMsg.str ());
2851  } // Done reading the Banner line and broadcasting success.
2852  if (debug && myRank == rootRank) {
2853  cerr << "-- Reading dimensions line" << endl;
2854  }
2855 
2856  // Read the matrix dimensions from the Matrix Market metadata.
2857  // dims = (numRows, numCols, numEntries). Proc 0 does the
2858  // reading, but it broadcasts the results to all MPI
2859  // processes. Thus, readCoordDims() is a collective
2860  // operation. It does a collective check for correctness too.
2861  Tuple<global_ordinal_type, 3> dims =
2862  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2863 
2864  if (debug && myRank == rootRank) {
2865  cerr << "-- Making Adder for collecting matrix data" << endl;
2866  }
2867 
2868  // "Adder" object for collecting all the sparse matrix entries
2869  // from the input stream. This is only nonnull on Proc 0.
2870  RCP<adder_type> pAdder =
2871  makeAdder (pComm, pBanner, dims, tolerant, debug);
2872 
2873  if (debug && myRank == rootRank) {
2874  cerr << "-- Reading matrix data" << endl;
2875  }
2876  //
2877  // Read the matrix entries from the input stream on Proc 0.
2878  //
2879  {
2880  // We use readSuccess to broadcast the results of the read
2881  // (succeeded or not) to all MPI processes. Since
2882  // Teuchos::broadcast doesn't currently know how to send
2883  // bools, we convert to int (true -> 1, false -> 0).
2884  int readSuccess = 1;
2885  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2886  if (myRank == rootRank) {
2887  try {
2888  // Reader for "coordinate" format sparse matrix data.
2889  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2890  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2891  reader_type reader (pAdder);
2892 
2893  // Read the sparse matrix entries.
2894  std::pair<bool, std::vector<size_t> > results =
2895  reader.read (in, lineNumber, tolerant, debug);
2896  readSuccess = results.first ? 1 : 0;
2897  }
2898  catch (std::exception& e) {
2899  readSuccess = 0;
2900  errMsg << e.what();
2901  }
2902  }
2903  broadcast (*pComm, rootRank, ptr (&readSuccess));
2904 
2905  // It would be nice to add a "verbose" flag, so that in
2906  // tolerant mode, we could log any bad line number(s) on
2907  // Proc 0. For now, we just throw if the read fails to
2908  // succeed.
2909  //
2910  // Question: If we're in tolerant mode, and if the read did
2911  // not succeed, should we attempt to call fillComplete()?
2912  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2913  "Failed to read the Matrix Market sparse matrix file: "
2914  << errMsg.str());
2915  } // Done reading the matrix entries (stored on Proc 0 for now)
2916 
2917  if (debug && myRank == rootRank) {
2918  cerr << "-- Successfully read the Matrix Market data" << endl;
2919  }
2920 
2921  // In tolerant mode, we need to rebroadcast the matrix
2922  // dimensions, since they may be different after reading the
2923  // actual matrix data. We only need to broadcast the number
2924  // of rows and columns. Only Rank 0 needs to know the actual
2925  // global number of entries, since (a) we need to merge
2926  // duplicates on Rank 0 first anyway, and (b) when we
2927  // distribute the entries, each rank other than Rank 0 will
2928  // only need to know how many entries it owns, not the total
2929  // number of entries.
2930  if (tolerant) {
2931  if (debug && myRank == rootRank) {
2932  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2933  << endl
2934  << "----- Dimensions before: "
2935  << dims[0] << " x " << dims[1]
2936  << endl;
2937  }
2938  // Packed coordinate matrix dimensions (numRows, numCols).
2939  Tuple<global_ordinal_type, 2> updatedDims;
2940  if (myRank == rootRank) {
2941  // If one or more bottom rows of the matrix contain no
2942  // entries, then the Adder will report that the number
2943  // of rows is less than that specified in the
2944  // metadata. We allow this case, and favor the
2945  // metadata so that the zero row(s) will be included.
2946  updatedDims[0] =
2947  std::max (dims[0], pAdder->getAdder()->numRows());
2948  updatedDims[1] = pAdder->getAdder()->numCols();
2949  }
2950  broadcast (*pComm, rootRank, updatedDims);
2951  dims[0] = updatedDims[0];
2952  dims[1] = updatedDims[1];
2953  if (debug && myRank == rootRank) {
2954  cerr << "----- Dimensions after: " << dims[0] << " x "
2955  << dims[1] << endl;
2956  }
2957  }
2958  else {
2959  // In strict mode, we require that the matrix's metadata and
2960  // its actual data agree, at least somewhat. In particular,
2961  // the number of rows must agree, since otherwise we cannot
2962  // distribute the matrix correctly.
2963 
2964  // Teuchos::broadcast() doesn't know how to broadcast bools,
2965  // so we use an int with the standard 1 == true, 0 == false
2966  // encoding.
2967  int dimsMatch = 1;
2968  if (myRank == rootRank) {
2969  // If one or more bottom rows of the matrix contain no
2970  // entries, then the Adder will report that the number of
2971  // rows is less than that specified in the metadata. We
2972  // allow this case, and favor the metadata, but do not
2973  // allow the Adder to think there are more rows in the
2974  // matrix than the metadata says.
2975  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2976  dimsMatch = 0;
2977  }
2978  }
2979  broadcast (*pComm, 0, ptr (&dimsMatch));
2980  if (dimsMatch == 0) {
2981  // We're in an error state anyway, so we might as well
2982  // work a little harder to print an informative error
2983  // message.
2984  //
2985  // Broadcast the Adder's idea of the matrix dimensions
2986  // from Proc 0 to all processes.
2987  Tuple<global_ordinal_type, 2> addersDims;
2988  if (myRank == rootRank) {
2989  addersDims[0] = pAdder->getAdder()->numRows();
2990  addersDims[1] = pAdder->getAdder()->numCols();
2991  }
2992  broadcast (*pComm, 0, addersDims);
2993  TEUCHOS_TEST_FOR_EXCEPTION(
2994  dimsMatch == 0, std::runtime_error,
2995  "The matrix metadata says that the matrix is " << dims[0] << " x "
2996  << dims[1] << ", but the actual data says that the matrix is "
2997  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2998  "data includes more rows than reported in the metadata. This "
2999  "is not allowed when parsing in strict mode. Parse the matrix in "
3000  "tolerant mode to ignore the metadata when it disagrees with the "
3001  "data.");
3002  }
3003  } // Matrix dimensions (# rows, # cols, # entries) agree.
3004 
3005  if (debug && myRank == rootRank) {
3006  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3007  }
3008 
3009  // Now that we've read in all the matrix entries from the
3010  // input stream into the adder on Proc 0, post-process them
3011  // into CSR format (still on Proc 0). This will facilitate
3012  // distributing them to all the processors.
3013  //
3014  // These arrays represent the global matrix data as a CSR
3015  // matrix (with numEntriesPerRow as redundant but convenient
3016  // metadata, since it's computable from rowPtr and vice
3017  // versa). They are valid only on Proc 0.
3018  ArrayRCP<size_t> numEntriesPerRow;
3019  ArrayRCP<size_t> rowPtr;
3020  ArrayRCP<global_ordinal_type> colInd;
3021  ArrayRCP<scalar_type> values;
3022 
3023  // Proc 0 first merges duplicate entries, and then converts
3024  // the coordinate-format matrix data to CSR.
3025  {
3026  int mergeAndConvertSucceeded = 1;
3027  std::ostringstream errMsg;
3028 
3029  if (myRank == rootRank) {
3030  try {
3031  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3032  global_ordinal_type> element_type;
3033 
3034  // Number of rows in the matrix. If we are in tolerant
3035  // mode, we've already synchronized dims with the actual
3036  // matrix data. If in strict mode, we should use dims
3037  // (as read from the file's metadata) rather than the
3038  // matrix data to determine the dimensions. (The matrix
3039  // data will claim fewer rows than the metadata, if one
3040  // or more rows have no entries stored in the file.)
3041  const size_type numRows = dims[0];
3042 
3043  // Additively merge duplicate matrix entries.
3044  pAdder->getAdder()->merge ();
3045 
3046  // Get a temporary const view of the merged matrix entries.
3047  const std::vector<element_type>& entries =
3048  pAdder->getAdder()->getEntries();
3049 
3050  // Number of matrix entries (after merging).
3051  const size_t numEntries = (size_t)entries.size();
3052 
3053  if (debug) {
3054  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3055  << " rows and numEntries=" << numEntries
3056  << " entries." << endl;
3057  }
3058 
3059  // Make space for the CSR matrix data. Converting to
3060  // CSR is easier if we fill numEntriesPerRow with zeros
3061  // at first.
3062  numEntriesPerRow = arcp<size_t> (numRows);
3063  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3064  rowPtr = arcp<size_t> (numRows+1);
3065  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3066  colInd = arcp<global_ordinal_type> (numEntries);
3067  values = arcp<scalar_type> (numEntries);
3068 
3069  // Convert from array-of-structs coordinate format to CSR
3070  // (compressed sparse row) format.
3071  global_ordinal_type prvRow = 0;
3072  size_t curPos = 0;
3073  rowPtr[0] = 0;
3074  for (curPos = 0; curPos < numEntries; ++curPos) {
3075  const element_type& curEntry = entries[curPos];
3076  const global_ordinal_type curRow = curEntry.rowIndex();
3077  TEUCHOS_TEST_FOR_EXCEPTION(
3078  curRow < prvRow, std::logic_error,
3079  "Row indices are out of order, even though they are supposed "
3080  "to be sorted. curRow = " << curRow << ", prvRow = "
3081  << prvRow << ", at curPos = " << curPos << ". Please report "
3082  "this bug to the Tpetra developers.");
3083  if (curRow > prvRow) {
3084  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3085  rowPtr[r] = curPos;
3086  }
3087  prvRow = curRow;
3088  }
3089  numEntriesPerRow[curRow]++;
3090  colInd[curPos] = curEntry.colIndex();
3091  values[curPos] = curEntry.value();
3092  }
3093  // rowPtr has one more entry than numEntriesPerRow. The
3094  // last entry of rowPtr is the number of entries in
3095  // colInd and values.
3096  rowPtr[numRows] = numEntries;
3097  } // Finished conversion to CSR format
3098  catch (std::exception& e) {
3099  mergeAndConvertSucceeded = 0;
3100  errMsg << "Failed to merge sparse matrix entries and convert to "
3101  "CSR format: " << e.what();
3102  }
3103 
3104  if (debug && mergeAndConvertSucceeded) {
3105  // Number of rows in the matrix.
3106  const size_type numRows = dims[0];
3107  const size_type maxToDisplay = 100;
3108 
3109  cerr << "----- Proc 0: numEntriesPerRow[0.."
3110  << (numEntriesPerRow.size()-1) << "] ";
3111  if (numRows > maxToDisplay) {
3112  cerr << "(only showing first and last few entries) ";
3113  }
3114  cerr << "= [";
3115  if (numRows > 0) {
3116  if (numRows > maxToDisplay) {
3117  for (size_type k = 0; k < 2; ++k) {
3118  cerr << numEntriesPerRow[k] << " ";
3119  }
3120  cerr << "... ";
3121  for (size_type k = numRows-2; k < numRows-1; ++k) {
3122  cerr << numEntriesPerRow[k] << " ";
3123  }
3124  }
3125  else {
3126  for (size_type k = 0; k < numRows-1; ++k) {
3127  cerr << numEntriesPerRow[k] << " ";
3128  }
3129  }
3130  cerr << numEntriesPerRow[numRows-1];
3131  } // numRows > 0
3132  cerr << "]" << endl;
3133 
3134  cerr << "----- Proc 0: rowPtr ";
3135  if (numRows > maxToDisplay) {
3136  cerr << "(only showing first and last few entries) ";
3137  }
3138  cerr << "= [";
3139  if (numRows > maxToDisplay) {
3140  for (size_type k = 0; k < 2; ++k) {
3141  cerr << rowPtr[k] << " ";
3142  }
3143  cerr << "... ";
3144  for (size_type k = numRows-2; k < numRows; ++k) {
3145  cerr << rowPtr[k] << " ";
3146  }
3147  }
3148  else {
3149  for (size_type k = 0; k < numRows; ++k) {
3150  cerr << rowPtr[k] << " ";
3151  }
3152  }
3153  cerr << rowPtr[numRows] << "]" << endl;
3154  }
3155  } // if myRank == rootRank
3156  } // Done converting sparse matrix data to CSR format
3157 
3158  // Now we're done with the Adder, so we can release the
3159  // reference ("free" it) to save space. This only actually
3160  // does anything on Rank 0, since pAdder is null on all the
3161  // other MPI processes.
3162  pAdder = null;
3163 
3164  if (debug && myRank == rootRank) {
3165  cerr << "-- Making range, domain, and row maps" << endl;
3166  }
3167 
3168  // Make the maps that describe the matrix's range and domain,
3169  // and the distribution of its rows. Creating a Map is a
3170  // collective operation, so we don't have to do a broadcast of
3171  // a success Boolean.
3172  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3173  RCP<const map_type> pDomainMap =
3174  makeDomainMap (pRangeMap, dims[0], dims[1]);
3175  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3176 
3177  if (debug && myRank == rootRank) {
3178  cerr << "-- Distributing the matrix data" << endl;
3179  }
3180 
3181  // Distribute the matrix data. Each processor has to add the
3182  // rows that it owns. If you try to make Proc 0 call
3183  // insertGlobalValues() for _all_ the rows, not just those it
3184  // owns, then fillComplete() will compute the number of
3185  // columns incorrectly. That's why Proc 0 has to distribute
3186  // the matrix data and why we make all the processors (not
3187  // just Proc 0) call insertGlobalValues() on their own data.
3188  //
3189  // These arrays represent each processor's part of the matrix
3190  // data, in "CSR" format (sort of, since the row indices might
3191  // not be contiguous).
3192  ArrayRCP<size_t> myNumEntriesPerRow;
3193  ArrayRCP<size_t> myRowPtr;
3194  ArrayRCP<global_ordinal_type> myColInd;
3195  ArrayRCP<scalar_type> myValues;
3196  // Distribute the matrix data. This is a collective operation.
3197  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3198  numEntriesPerRow, rowPtr, colInd, values, debug);
3199 
3200  if (debug && myRank == rootRank) {
3201  cerr << "-- Inserting matrix entries on each process "
3202  "and calling fillComplete()" << endl;
3203  }
3204  // Each processor inserts its part of the matrix data, and
3205  // then they all call fillComplete(). This method invalidates
3206  // the my* distributed matrix data before calling
3207  // fillComplete(), in order to save space. In general, we
3208  // never store more than two copies of the matrix's entries in
3209  // memory at once, which is no worse than what Tpetra
3210  // promises.
3211  Teuchos::RCP<sparse_matrix_type> pMatrix =
3212  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3213  pRowMap, pRangeMap, pDomainMap, constructorParams,
3214  fillCompleteParams);
3215  // Only use a reduce-all in debug mode to check if pMatrix is
3216  // null. Otherwise, just throw an exception. We never expect
3217  // a null pointer here, so we can save a communication.
3218  if (debug) {
3219  int localIsNull = pMatrix.is_null () ? 1 : 0;
3220  int globalIsNull = 0;
3221  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3222  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3223  "Reader::makeMatrix() returned a null pointer on at least one "
3224  "process. Please report this bug to the Tpetra developers.");
3225  }
3226  else {
3227  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3228  "Reader::makeMatrix() returned a null pointer. "
3229  "Please report this bug to the Tpetra developers.");
3230  }
3231 
3232  // Sanity check for dimensions (read from the Matrix Market
3233  // data, vs. dimensions reported by the CrsMatrix).
3234  //
3235  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3236  // what one might think it does, so you have to ask the range
3237  // resp. domain map for the number of rows resp. columns.
3238  if (extraDebug && debug) {
3239  const int numProcs = pComm->getSize ();
3240  const global_size_t globalNumRows =
3241  pRangeMap->getGlobalNumElements();
3242  const global_size_t globalNumCols =
3243  pDomainMap->getGlobalNumElements();
3244  if (myRank == rootRank) {
3245  cerr << "-- Matrix is "
3246  << globalNumRows << " x " << globalNumCols
3247  << " with " << pMatrix->getGlobalNumEntries()
3248  << " entries, and index base "
3249  << pMatrix->getIndexBase() << "." << endl;
3250  }
3251  pComm->barrier ();
3252  for (int p = 0; p < numProcs; ++p) {
3253  if (myRank == p) {
3254  cerr << "-- Proc " << p << " owns "
3255  << pMatrix->getLocalNumCols() << " columns, and "
3256  << pMatrix->getLocalNumEntries() << " entries." << endl;
3257  }
3258  pComm->barrier ();
3259  }
3260  } // if (extraDebug && debug)
3261 
3262  if (debug && myRank == rootRank) {
3263  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3264  << endl;
3265  }
3266  return pMatrix;
3267  }
3268 
3269 
3310  static Teuchos::RCP<sparse_matrix_type>
3311  readSparse (std::istream& in,
3312  const Teuchos::RCP<const map_type>& rowMap,
3313  Teuchos::RCP<const map_type>& colMap,
3314  const Teuchos::RCP<const map_type>& domainMap,
3315  const Teuchos::RCP<const map_type>& rangeMap,
3316  const bool callFillComplete=true,
3317  const bool tolerant=false,
3318  const bool debug=false)
3319  {
3320  using Teuchos::MatrixMarket::Banner;
3321  using Teuchos::arcp;
3322  using Teuchos::ArrayRCP;
3323  using Teuchos::ArrayView;
3324  using Teuchos::as;
3325  using Teuchos::broadcast;
3326  using Teuchos::Comm;
3327  using Teuchos::null;
3328  using Teuchos::ptr;
3329  using Teuchos::RCP;
3330  using Teuchos::reduceAll;
3331  using Teuchos::Tuple;
3332  using std::cerr;
3333  using std::endl;
3334  typedef Teuchos::ScalarTraits<scalar_type> STS;
3335 
3336  RCP<const Comm<int> > pComm = rowMap->getComm ();
3337  const int myRank = pComm->getRank ();
3338  const int rootRank = 0;
3339  const bool extraDebug = false;
3340 
3341  // Fast checks for invalid input. We can't check other
3342  // attributes of the Maps until we've read in the matrix
3343  // dimensions.
3344  TEUCHOS_TEST_FOR_EXCEPTION(
3345  rowMap.is_null (), std::invalid_argument,
3346  "Row Map must be nonnull.");
3347  TEUCHOS_TEST_FOR_EXCEPTION(
3348  rangeMap.is_null (), std::invalid_argument,
3349  "Range Map must be nonnull.");
3350  TEUCHOS_TEST_FOR_EXCEPTION(
3351  domainMap.is_null (), std::invalid_argument,
3352  "Domain Map must be nonnull.");
3353  TEUCHOS_TEST_FOR_EXCEPTION(
3354  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3355  std::invalid_argument,
3356  "The specified row Map's communicator (rowMap->getComm())"
3357  "differs from the given separately supplied communicator pComm.");
3358  TEUCHOS_TEST_FOR_EXCEPTION(
3359  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3360  std::invalid_argument,
3361  "The specified domain Map's communicator (domainMap->getComm())"
3362  "differs from the given separately supplied communicator pComm.");
3363  TEUCHOS_TEST_FOR_EXCEPTION(
3364  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3365  std::invalid_argument,
3366  "The specified range Map's communicator (rangeMap->getComm())"
3367  "differs from the given separately supplied communicator pComm.");
3368 
3369  // Current line number in the input stream. Various calls
3370  // will modify this depending on the number of lines that are
3371  // read from the input stream. Only Rank 0 modifies this.
3372  size_t lineNumber = 1;
3373 
3374  if (debug && myRank == rootRank) {
3375  cerr << "Matrix Market reader: readSparse:" << endl
3376  << "-- Reading banner line" << endl;
3377  }
3378 
3379  // The "Banner" tells you whether the input stream represents
3380  // a sparse matrix, the symmetry type of the matrix, and the
3381  // type of the data it contains.
3382  //
3383  // pBanner will only be nonnull on MPI Rank 0. It will be
3384  // null on all other MPI processes.
3385  RCP<const Banner> pBanner;
3386  {
3387  // We read and validate the Banner on Proc 0, but broadcast
3388  // the validation result to all processes.
3389  // Teuchos::broadcast doesn't currently work with bool, so
3390  // we use int (true -> 1, false -> 0).
3391  int bannerIsCorrect = 1;
3392  std::ostringstream errMsg;
3393 
3394  if (myRank == rootRank) {
3395  // Read the Banner line from the input stream.
3396  try {
3397  pBanner = readBanner (in, lineNumber, tolerant, debug);
3398  }
3399  catch (std::exception& e) {
3400  errMsg << "Attempt to read the Matrix Market file's Banner line "
3401  "threw an exception: " << e.what();
3402  bannerIsCorrect = 0;
3403  }
3404 
3405  if (bannerIsCorrect) {
3406  // Validate the Banner for the case of a sparse matrix.
3407  // We validate on Proc 0, since it reads the Banner.
3408 
3409  // In intolerant mode, the matrix type must be "coordinate".
3410  if (! tolerant && pBanner->matrixType() != "coordinate") {
3411  bannerIsCorrect = 0;
3412  errMsg << "The Matrix Market input file must contain a "
3413  "\"coordinate\"-format sparse matrix in order to create a "
3414  "Tpetra::CrsMatrix object from it, but the file's matrix "
3415  "type is \"" << pBanner->matrixType() << "\" instead.";
3416  }
3417  // In tolerant mode, we allow the matrix type to be
3418  // anything other than "array" (which would mean that
3419  // the file contains a dense matrix).
3420  if (tolerant && pBanner->matrixType() == "array") {
3421  bannerIsCorrect = 0;
3422  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3423  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3424  "object from it, but the file's matrix type is \"array\" "
3425  "instead. That probably means the file contains dense matrix "
3426  "data.";
3427  }
3428  }
3429  } // Proc 0: Done reading the Banner, hopefully successfully.
3430 
3431  // Broadcast from Proc 0 whether the Banner was read correctly.
3432  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3433 
3434  // If the Banner is invalid, all processes throw an
3435  // exception. Only Proc 0 gets the exception message, but
3436  // that's OK, since the main point is to "stop the world"
3437  // (rather than throw an exception on one process and leave
3438  // the others hanging).
3439  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3440  std::invalid_argument, errMsg.str ());
3441  } // Done reading the Banner line and broadcasting success.
3442  if (debug && myRank == rootRank) {
3443  cerr << "-- Reading dimensions line" << endl;
3444  }
3445 
3446  // Read the matrix dimensions from the Matrix Market metadata.
3447  // dims = (numRows, numCols, numEntries). Proc 0 does the
3448  // reading, but it broadcasts the results to all MPI
3449  // processes. Thus, readCoordDims() is a collective
3450  // operation. It does a collective check for correctness too.
3451  Tuple<global_ordinal_type, 3> dims =
3452  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3453 
3454  if (debug && myRank == rootRank) {
3455  cerr << "-- Making Adder for collecting matrix data" << endl;
3456  }
3457 
3458  // "Adder" object for collecting all the sparse matrix entries
3459  // from the input stream. This is only nonnull on Proc 0.
3460  // The Adder internally converts the one-based indices (native
3461  // Matrix Market format) into zero-based indices.
3462  RCP<adder_type> pAdder =
3463  makeAdder (pComm, pBanner, dims, tolerant, debug);
3464 
3465  if (debug && myRank == rootRank) {
3466  cerr << "-- Reading matrix data" << endl;
3467  }
3468  //
3469  // Read the matrix entries from the input stream on Proc 0.
3470  //
3471  {
3472  // We use readSuccess to broadcast the results of the read
3473  // (succeeded or not) to all MPI processes. Since
3474  // Teuchos::broadcast doesn't currently know how to send
3475  // bools, we convert to int (true -> 1, false -> 0).
3476  int readSuccess = 1;
3477  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3478  if (myRank == rootRank) {
3479  try {
3480  // Reader for "coordinate" format sparse matrix data.
3481  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3482  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3483  reader_type reader (pAdder);
3484 
3485  // Read the sparse matrix entries.
3486  std::pair<bool, std::vector<size_t> > results =
3487  reader.read (in, lineNumber, tolerant, debug);
3488  readSuccess = results.first ? 1 : 0;
3489  }
3490  catch (std::exception& e) {
3491  readSuccess = 0;
3492  errMsg << e.what();
3493  }
3494  }
3495  broadcast (*pComm, rootRank, ptr (&readSuccess));
3496 
3497  // It would be nice to add a "verbose" flag, so that in
3498  // tolerant mode, we could log any bad line number(s) on
3499  // Proc 0. For now, we just throw if the read fails to
3500  // succeed.
3501  //
3502  // Question: If we're in tolerant mode, and if the read did
3503  // not succeed, should we attempt to call fillComplete()?
3504  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3505  "Failed to read the Matrix Market sparse matrix file: "
3506  << errMsg.str());
3507  } // Done reading the matrix entries (stored on Proc 0 for now)
3508 
3509  if (debug && myRank == rootRank) {
3510  cerr << "-- Successfully read the Matrix Market data" << endl;
3511  }
3512 
3513  // In tolerant mode, we need to rebroadcast the matrix
3514  // dimensions, since they may be different after reading the
3515  // actual matrix data. We only need to broadcast the number
3516  // of rows and columns. Only Rank 0 needs to know the actual
3517  // global number of entries, since (a) we need to merge
3518  // duplicates on Rank 0 first anyway, and (b) when we
3519  // distribute the entries, each rank other than Rank 0 will
3520  // only need to know how many entries it owns, not the total
3521  // number of entries.
3522  if (tolerant) {
3523  if (debug && myRank == rootRank) {
3524  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3525  << endl
3526  << "----- Dimensions before: "
3527  << dims[0] << " x " << dims[1]
3528  << endl;
3529  }
3530  // Packed coordinate matrix dimensions (numRows, numCols).
3531  Tuple<global_ordinal_type, 2> updatedDims;
3532  if (myRank == rootRank) {
3533  // If one or more bottom rows of the matrix contain no
3534  // entries, then the Adder will report that the number
3535  // of rows is less than that specified in the
3536  // metadata. We allow this case, and favor the
3537  // metadata so that the zero row(s) will be included.
3538  updatedDims[0] =
3539  std::max (dims[0], pAdder->getAdder()->numRows());
3540  updatedDims[1] = pAdder->getAdder()->numCols();
3541  }
3542  broadcast (*pComm, rootRank, updatedDims);
3543  dims[0] = updatedDims[0];
3544  dims[1] = updatedDims[1];
3545  if (debug && myRank == rootRank) {
3546  cerr << "----- Dimensions after: " << dims[0] << " x "
3547  << dims[1] << endl;
3548  }
3549  }
3550  else {
3551  // In strict mode, we require that the matrix's metadata and
3552  // its actual data agree, at least somewhat. In particular,
3553  // the number of rows must agree, since otherwise we cannot
3554  // distribute the matrix correctly.
3555 
3556  // Teuchos::broadcast() doesn't know how to broadcast bools,
3557  // so we use an int with the standard 1 == true, 0 == false
3558  // encoding.
3559  int dimsMatch = 1;
3560  if (myRank == rootRank) {
3561  // If one or more bottom rows of the matrix contain no
3562  // entries, then the Adder will report that the number of
3563  // rows is less than that specified in the metadata. We
3564  // allow this case, and favor the metadata, but do not
3565  // allow the Adder to think there are more rows in the
3566  // matrix than the metadata says.
3567  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3568  dimsMatch = 0;
3569  }
3570  }
3571  broadcast (*pComm, 0, ptr (&dimsMatch));
3572  if (dimsMatch == 0) {
3573  // We're in an error state anyway, so we might as well
3574  // work a little harder to print an informative error
3575  // message.
3576  //
3577  // Broadcast the Adder's idea of the matrix dimensions
3578  // from Proc 0 to all processes.
3579  Tuple<global_ordinal_type, 2> addersDims;
3580  if (myRank == rootRank) {
3581  addersDims[0] = pAdder->getAdder()->numRows();
3582  addersDims[1] = pAdder->getAdder()->numCols();
3583  }
3584  broadcast (*pComm, 0, addersDims);
3585  TEUCHOS_TEST_FOR_EXCEPTION(
3586  dimsMatch == 0, std::runtime_error,
3587  "The matrix metadata says that the matrix is " << dims[0] << " x "
3588  << dims[1] << ", but the actual data says that the matrix is "
3589  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3590  "data includes more rows than reported in the metadata. This "
3591  "is not allowed when parsing in strict mode. Parse the matrix in "
3592  "tolerant mode to ignore the metadata when it disagrees with the "
3593  "data.");
3594  }
3595  } // Matrix dimensions (# rows, # cols, # entries) agree.
3596 
3597  if (debug && myRank == rootRank) {
3598  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3599  }
3600 
3601  // Now that we've read in all the matrix entries from the
3602  // input stream into the adder on Proc 0, post-process them
3603  // into CSR format (still on Proc 0). This will facilitate
3604  // distributing them to all the processors.
3605  //
3606  // These arrays represent the global matrix data as a CSR
3607  // matrix (with numEntriesPerRow as redundant but convenient
3608  // metadata, since it's computable from rowPtr and vice
3609  // versa). They are valid only on Proc 0.
3610  ArrayRCP<size_t> numEntriesPerRow;
3611  ArrayRCP<size_t> rowPtr;
3612  ArrayRCP<global_ordinal_type> colInd;
3613  ArrayRCP<scalar_type> values;
3614 
3615  // Proc 0 first merges duplicate entries, and then converts
3616  // the coordinate-format matrix data to CSR.
3617  {
3618  int mergeAndConvertSucceeded = 1;
3619  std::ostringstream errMsg;
3620 
3621  if (myRank == rootRank) {
3622  try {
3623  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3624  global_ordinal_type> element_type;
3625 
3626  // Number of rows in the matrix. If we are in tolerant
3627  // mode, we've already synchronized dims with the actual
3628  // matrix data. If in strict mode, we should use dims
3629  // (as read from the file's metadata) rather than the
3630  // matrix data to determine the dimensions. (The matrix
3631  // data will claim fewer rows than the metadata, if one
3632  // or more rows have no entries stored in the file.)
3633  const size_type numRows = dims[0];
3634 
3635  // Additively merge duplicate matrix entries.
3636  pAdder->getAdder()->merge ();
3637 
3638  // Get a temporary const view of the merged matrix entries.
3639  const std::vector<element_type>& entries =
3640  pAdder->getAdder()->getEntries();
3641 
3642  // Number of matrix entries (after merging).
3643  const size_t numEntries = (size_t)entries.size();
3644 
3645  if (debug) {
3646  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3647  << " rows and numEntries=" << numEntries
3648  << " entries." << endl;
3649  }
3650 
3651  // Make space for the CSR matrix data. Converting to
3652  // CSR is easier if we fill numEntriesPerRow with zeros
3653  // at first.
3654  numEntriesPerRow = arcp<size_t> (numRows);
3655  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3656  rowPtr = arcp<size_t> (numRows+1);
3657  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3658  colInd = arcp<global_ordinal_type> (numEntries);
3659  values = arcp<scalar_type> (numEntries);
3660 
3661  // Convert from array-of-structs coordinate format to CSR
3662  // (compressed sparse row) format.
3663  global_ordinal_type prvRow = 0;
3664  size_t curPos = 0;
3665  rowPtr[0] = 0;
3666  for (curPos = 0; curPos < numEntries; ++curPos) {
3667  const element_type& curEntry = entries[curPos];
3668  const global_ordinal_type curRow = curEntry.rowIndex();
3669  TEUCHOS_TEST_FOR_EXCEPTION(
3670  curRow < prvRow, std::logic_error,
3671  "Row indices are out of order, even though they are supposed "
3672  "to be sorted. curRow = " << curRow << ", prvRow = "
3673  << prvRow << ", at curPos = " << curPos << ". Please report "
3674  "this bug to the Tpetra developers.");
3675  if (curRow > prvRow) {
3676  prvRow = curRow;
3677  }
3678  numEntriesPerRow[curRow]++;
3679  colInd[curPos] = curEntry.colIndex();
3680  values[curPos] = curEntry.value();
3681  }
3682 
3683  rowPtr[0] = 0;
3684  for (global_ordinal_type row = 1; row <= numRows; ++row) {
3685  rowPtr[row] = numEntriesPerRow[row-1] + rowPtr[row-1];
3686  }
3687  } // Finished conversion to CSR format
3688  catch (std::exception& e) {
3689  mergeAndConvertSucceeded = 0;
3690  errMsg << "Failed to merge sparse matrix entries and convert to "
3691  "CSR format: " << e.what();
3692  }
3693 
3694  if (debug && mergeAndConvertSucceeded) {
3695  // Number of rows in the matrix.
3696  const size_type numRows = dims[0];
3697  const size_type maxToDisplay = 100;
3698 
3699  cerr << "----- Proc 0: numEntriesPerRow[0.."
3700  << (numEntriesPerRow.size()-1) << "] ";
3701  if (numRows > maxToDisplay) {
3702  cerr << "(only showing first and last few entries) ";
3703  }
3704  cerr << "= [";
3705  if (numRows > 0) {
3706  if (numRows > maxToDisplay) {
3707  for (size_type k = 0; k < 2; ++k) {
3708  cerr << numEntriesPerRow[k] << " ";
3709  }
3710  cerr << "... ";
3711  for (size_type k = numRows-2; k < numRows-1; ++k) {
3712  cerr << numEntriesPerRow[k] << " ";
3713  }
3714  }
3715  else {
3716  for (size_type k = 0; k < numRows-1; ++k) {
3717  cerr << numEntriesPerRow[k] << " ";
3718  }
3719  }
3720  cerr << numEntriesPerRow[numRows-1];
3721  } // numRows > 0
3722  cerr << "]" << endl;
3723 
3724  cerr << "----- Proc 0: rowPtr ";
3725  if (numRows > maxToDisplay) {
3726  cerr << "(only showing first and last few entries) ";
3727  }
3728  cerr << "= [";
3729  if (numRows > maxToDisplay) {
3730  for (size_type k = 0; k < 2; ++k) {
3731  cerr << rowPtr[k] << " ";
3732  }
3733  cerr << "... ";
3734  for (size_type k = numRows-2; k < numRows; ++k) {
3735  cerr << rowPtr[k] << " ";
3736  }
3737  }
3738  else {
3739  for (size_type k = 0; k < numRows; ++k) {
3740  cerr << rowPtr[k] << " ";
3741  }
3742  }
3743  cerr << rowPtr[numRows] << "]" << endl;
3744 
3745  cerr << "----- Proc 0: colInd = [";
3746  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3747  cerr << colInd[k] << " ";
3748  }
3749  cerr << "]" << endl;
3750  }
3751  } // if myRank == rootRank
3752  } // Done converting sparse matrix data to CSR format
3753 
3754  // Now we're done with the Adder, so we can release the
3755  // reference ("free" it) to save space. This only actually
3756  // does anything on Rank 0, since pAdder is null on all the
3757  // other MPI processes.
3758  pAdder = null;
3759 
3760  // Verify details of the Maps. Don't count the global number
3761  // of entries in the row Map, since that number doesn't
3762  // correctly count overlap.
3763  if (debug && myRank == rootRank) {
3764  cerr << "-- Verifying Maps" << endl;
3765  }
3766  TEUCHOS_TEST_FOR_EXCEPTION(
3767  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3768  std::invalid_argument,
3769  "The range Map has " << rangeMap->getGlobalNumElements ()
3770  << " entries, but the matrix has a global number of rows " << dims[0]
3771  << ".");
3772  TEUCHOS_TEST_FOR_EXCEPTION(
3773  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3774  std::invalid_argument,
3775  "The domain Map has " << domainMap->getGlobalNumElements ()
3776  << " entries, but the matrix has a global number of columns "
3777  << dims[1] << ".");
3778 
3779  // Create a row Map which is entirely owned on Proc 0.
3780  RCP<Teuchos::FancyOStream> err = debug ?
3781  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3782 
3783  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3784  ArrayView<const global_ordinal_type> myRows =
3785  gatherRowMap->getLocalElementList ();
3786  const size_type myNumRows = myRows.size ();
3787  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3788 
3789  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3790  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3791  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3792  }
3793 
3794  // Create a matrix using this Map, and fill in on Proc 0. We
3795  // know how many entries there are in each row, so we can use
3796  // static profile.
3797  RCP<sparse_matrix_type> A_proc0 =
3798  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow()));
3799  if (myRank == rootRank) {
3800  if (debug) {
3801  cerr << "-- Proc 0: Filling gather matrix" << endl;
3802  }
3803  if (debug) {
3804  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3805  }
3806 
3807  // Add Proc 0's matrix entries to the CrsMatrix.
3808  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3809  size_type i = myRows[i_] - indexBase;
3810 
3811  const size_type curPos = as<size_type> (rowPtr[i]);
3812  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3813  ArrayView<global_ordinal_type> curColInd =
3814  colInd.view (curPos, curNumEntries);
3815  ArrayView<scalar_type> curValues =
3816  values.view (curPos, curNumEntries);
3817 
3818  // Modify the column indices in place to have the right index base.
3819  for (size_type k = 0; k < curNumEntries; ++k) {
3820  curColInd[k] += indexBase;
3821  }
3822  if (debug) {
3823  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3824  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3825  }
3826  // Avoid constructing empty views of ArrayRCP objects.
3827  if (curNumEntries > 0) {
3828  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3829  }
3830  }
3831  // Now we can save space by deallocating numEntriesPerRow,
3832  // rowPtr, colInd, and values, since we've already put those
3833  // data in the matrix.
3834  numEntriesPerRow = null;
3835  rowPtr = null;
3836  colInd = null;
3837  values = null;
3838  } // if myRank == rootRank
3839 
3840  RCP<sparse_matrix_type> A;
3842  export_type exp (gatherRowMap, rowMap);
3843 
3844  // Communicate the precise number of nonzeros per row, which was already
3845  // calculated above.
3846  typedef local_ordinal_type LO;
3847  typedef global_ordinal_type GO;
3848  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
3849  mv_type_go target_nnzPerRow(rowMap,1);
3850  mv_type_go source_nnzPerRow(gatherRowMap,1);
3851  Teuchos::ArrayRCP<GO> srcData = source_nnzPerRow.getDataNonConst(0);
3852  for (int i=0; i<myNumRows; i++)
3853  srcData[i] = gatherNumEntriesPerRow[i];
3854  srcData = Teuchos::null;
3855  target_nnzPerRow.doExport(source_nnzPerRow,exp,Tpetra::INSERT);
3856  Teuchos::ArrayRCP<GO> targetData = target_nnzPerRow.getDataNonConst(0);
3857  ArrayRCP<size_t> targetData_size_t = arcp<size_t>(targetData.size());
3858  for (int i=0; i<targetData.size(); i++)
3859  targetData_size_t[i] = targetData[i];
3860 
3861  if (colMap.is_null ()) {
3862  A = rcp (new sparse_matrix_type (rowMap, targetData_size_t()));
3863  } else {
3864  A = rcp (new sparse_matrix_type (rowMap, colMap, targetData_size_t()));
3865  }
3866  A->doExport (*A_proc0, exp, INSERT);
3867  if (callFillComplete) {
3868  A->fillComplete (domainMap, rangeMap);
3869  }
3870 
3871  // We can't get the dimensions of the matrix until after
3872  // fillComplete() is called. Thus, we can't do the sanity
3873  // check (dimensions read from the Matrix Market data,
3874  // vs. dimensions reported by the CrsMatrix) unless the user
3875  // asked us to call fillComplete().
3876  //
3877  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3878  // what one might think it does, so you have to ask the range
3879  // resp. domain map for the number of rows resp. columns.
3880  if (callFillComplete) {
3881  const int numProcs = pComm->getSize ();
3882 
3883  if (extraDebug && debug) {
3884  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3885  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3886  if (myRank == rootRank) {
3887  cerr << "-- Matrix is "
3888  << globalNumRows << " x " << globalNumCols
3889  << " with " << A->getGlobalNumEntries()
3890  << " entries, and index base "
3891  << A->getIndexBase() << "." << endl;
3892  }
3893  pComm->barrier ();
3894  for (int p = 0; p < numProcs; ++p) {
3895  if (myRank == p) {
3896  cerr << "-- Proc " << p << " owns "
3897  << A->getLocalNumCols() << " columns, and "
3898  << A->getLocalNumEntries() << " entries." << endl;
3899  }
3900  pComm->barrier ();
3901  }
3902  } // if (extraDebug && debug)
3903  } // if (callFillComplete)
3904 
3905  if (debug && myRank == rootRank) {
3906  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3907  << endl;
3908  }
3909  return A;
3910  }
3911 
3941  static Teuchos::RCP<multivector_type>
3942  readDenseFile (const std::string& filename,
3943  const Teuchos::RCP<const comm_type>& comm,
3944  Teuchos::RCP<const map_type>& map,
3945  const bool tolerant=false,
3946  const bool debug=false,
3947  const bool binary=false)
3948  {
3949  using Teuchos::broadcast;
3950  using Teuchos::outArg;
3951 
3952  std::ifstream in;
3953  int opened = 0;
3954  if (comm->getRank() == 0) {
3955  try {
3956  if (!binary)
3957  in.open (filename.c_str ());
3958  else
3959  in.open (filename.c_str (), std::ios::binary);
3960  opened = in.is_open();
3961  }
3962  catch (...) {
3963  opened = 0;
3964  }
3965  }
3966  broadcast<int, int> (*comm, 0, outArg (opened));
3967  TEUCHOS_TEST_FOR_EXCEPTION(
3968  opened == 0, std::runtime_error,
3969  "readDenseFile: Failed to open file \"" << filename << "\" on "
3970  "Process 0.");
3971  return readDense (in, comm, map, tolerant, debug, binary);
3972  }
3973 
3974 
4004  static Teuchos::RCP<vector_type>
4005  readVectorFile (const std::string& filename,
4006  const Teuchos::RCP<const comm_type>& comm,
4007  Teuchos::RCP<const map_type>& map,
4008  const bool tolerant=false,
4009  const bool debug=false)
4010  {
4011  using Teuchos::broadcast;
4012  using Teuchos::outArg;
4013 
4014  std::ifstream in;
4015  int opened = 0;
4016  if (comm->getRank() == 0) {
4017  try {
4018  in.open (filename.c_str ());
4019  opened = in.is_open();
4020  }
4021  catch (...) {
4022  opened = 0;
4023  }
4024  }
4025  broadcast<int, int> (*comm, 0, outArg (opened));
4026  TEUCHOS_TEST_FOR_EXCEPTION(
4027  opened == 0, std::runtime_error,
4028  "readVectorFile: Failed to open file \"" << filename << "\" on "
4029  "Process 0.");
4030  return readVector (in, comm, map, tolerant, debug);
4031  }
4032 
4033 
4101 
4102  static Teuchos::RCP<multivector_type>
4103  readDense (std::istream& in,
4104  const Teuchos::RCP<const comm_type>& comm,
4105  Teuchos::RCP<const map_type>& map,
4106  const bool tolerant=false,
4107  const bool debug=false,
4108  const bool binary=false)
4109  {
4110  Teuchos::RCP<Teuchos::FancyOStream> err =
4111  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4112  return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug, binary);
4113  }
4114 
4115 
4117  static Teuchos::RCP<vector_type>
4118  readVector (std::istream& in,
4119  const Teuchos::RCP<const comm_type>& comm,
4120  Teuchos::RCP<const map_type>& map,
4121  const bool tolerant=false,
4122  const bool debug=false)
4123  {
4124  Teuchos::RCP<Teuchos::FancyOStream> err =
4125  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4126  return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4127  }
4128 
4129 
4151  static Teuchos::RCP<const map_type>
4152  readMapFile (const std::string& filename,
4153  const Teuchos::RCP<const comm_type>& comm,
4154  const bool tolerant=false,
4155  const bool debug=false,
4156  const bool binary=false)
4157  {
4158  using Teuchos::inOutArg;
4159  using Teuchos::broadcast;
4160  std::ifstream in;
4161 
4162  int success = 1;
4163  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4164  if (binary)
4165  in.open (filename.c_str (), std::ios::binary);
4166  else
4167  in.open (filename.c_str ()); // Destructor closes safely
4168  if (! in) {
4169  success = 0;
4170  }
4171  }
4172  broadcast<int, int> (*comm, 0, inOutArg (success));
4173  TEUCHOS_TEST_FOR_EXCEPTION(
4174  success == 0, std::runtime_error,
4175  "Tpetra::MatrixMarket::Reader::readMapFile: "
4176  "Failed to read file \"" << filename << "\" on Process 0.");
4177  return readMap (in, comm, tolerant, debug, binary);
4178  }
4179 
4180 
4181  private:
4182  template<class MultiVectorScalarType>
4183  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4186  node_type> >
4187  readDenseImpl (std::istream& in,
4188  const Teuchos::RCP<const comm_type>& comm,
4189  Teuchos::RCP<const map_type>& map,
4190  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4191  const bool tolerant=false,
4192  const bool debug=false,
4193  const bool binary=false)
4194  {
4195  using Teuchos::MatrixMarket::Banner;
4196  using Teuchos::MatrixMarket::checkCommentLine;
4197  using Teuchos::ArrayRCP;
4198  using Teuchos::as;
4199  using Teuchos::broadcast;
4200  using Teuchos::outArg;
4201  using Teuchos::RCP;
4202  using Teuchos::Tuple;
4203  using std::endl;
4204  typedef MultiVectorScalarType ST;
4205  typedef local_ordinal_type LO;
4206  typedef global_ordinal_type GO;
4207  typedef node_type NT;
4208  typedef Teuchos::ScalarTraits<ST> STS;
4209  typedef typename STS::magnitudeType MT;
4210  typedef Teuchos::ScalarTraits<MT> STM;
4212 
4213  // Rank 0 is the only (MPI) process allowed to read from the
4214  // input stream.
4215  const int myRank = comm->getRank ();
4216 
4217  if (! err.is_null ()) {
4218  err->pushTab ();
4219  }
4220  if (debug) {
4221  *err << myRank << ": readDenseImpl" << endl;
4222  }
4223  if (! err.is_null ()) {
4224  err->pushTab ();
4225  }
4226 
4227  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4228  // instances be identical and that the Node instances be
4229  // identical. The essential condition is more complicated to
4230  // test and isn't the same for all Node types. Thus, we just
4231  // leave it up to the user.
4232 
4233  // // If map is nonnull, check the precondition that its
4234  // // communicator resp. node equal comm resp. node. Checking
4235  // // now avoids doing a lot of file reading before we detect the
4236  // // violated precondition.
4237  // TEUCHOS_TEST_FOR_EXCEPTION(
4238  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4239  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4240  // "communicator and node must equal the supplied communicator resp. "
4241  // "node.");
4242 
4243  // Process 0 will read in the matrix dimensions from the file,
4244  // and broadcast them to all ranks in the given communicator.
4245  // There are only 2 dimensions in the matrix, but we use the
4246  // third element of the Tuple to encode the banner's reported
4247  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4248  // (same as "real"). We don't allow pattern matrices (i.e.,
4249  // graphs) since they only make sense for sparse data.
4250  Tuple<GO, 3> dims;
4251  dims[0] = 0;
4252  dims[1] = 0;
4253  dims[2] = 0;
4254 
4255  // Current line number in the input stream. Only valid on
4256  // Proc 0. Various calls will modify this depending on the
4257  // number of lines that are read from the input stream.
4258  size_t lineNumber = 1;
4259 
4260  // Capture errors and their messages on Proc 0.
4261  std::ostringstream exMsg;
4262  int localBannerReadSuccess = 1;
4263  int localDimsReadSuccess = 1;
4264 
4265  // Only Proc 0 gets to read matrix data from the input stream.
4266  if (myRank == 0) {
4267  if (! binary) {
4268  if (debug) {
4269  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4270  }
4271 
4272  // The "Banner" tells you whether the input stream
4273  // represents a dense matrix, the symmetry type of the
4274  // matrix, and the type of the data it contains.
4275  RCP<const Banner> pBanner;
4276  try {
4277  pBanner = readBanner (in, lineNumber, tolerant, debug);
4278  } catch (std::exception& e) {
4279  exMsg << e.what ();
4280  localBannerReadSuccess = 0;
4281  }
4282  // Make sure the input stream is the right kind of data.
4283  if (localBannerReadSuccess) {
4284  if (pBanner->matrixType () != "array") {
4285  exMsg << "The Matrix Market file does not contain dense matrix "
4286  "data. Its banner (first) line says that its matrix type is \""
4287  << pBanner->matrixType () << "\", rather that the required "
4288  "\"array\".";
4289  localBannerReadSuccess = 0;
4290  } else if (pBanner->dataType() == "pattern") {
4291  exMsg << "The Matrix Market file's banner (first) "
4292  "line claims that the matrix's data type is \"pattern\". This does "
4293  "not make sense for a dense matrix, yet the file reports the matrix "
4294  "as dense. The only valid data types for a dense matrix are "
4295  "\"real\", \"complex\", and \"integer\".";
4296  localBannerReadSuccess = 0;
4297  } else {
4298  // Encode the data type reported by the Banner as the
4299  // third element of the dimensions Tuple.
4300  dims[2] = encodeDataType (pBanner->dataType ());
4301  }
4302  } // if we successfully read the banner line
4303 
4304  // At this point, we've successfully read the banner line.
4305  // Now read the dimensions line.
4306  if (localBannerReadSuccess) {
4307  if (debug) {
4308  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4309  }
4310  // Keep reading lines from the input stream until we find
4311  // a non-comment line, or until we run out of lines. The
4312  // latter is an error, since every "array" format Matrix
4313  // Market file must have a dimensions line after the
4314  // banner (even if the matrix has zero rows or columns, or
4315  // zero entries).
4316  std::string line;
4317  bool commentLine = true;
4318 
4319  while (commentLine) {
4320  // Test whether it is even valid to read from the input
4321  // stream wrapping the line.
4322  if (in.eof () || in.fail ()) {
4323  exMsg << "Unable to get array dimensions line (at all) from line "
4324  << lineNumber << " of input stream. The input stream "
4325  << "claims that it is "
4326  << (in.eof() ? "at end-of-file." : "in a failed state.");
4327  localDimsReadSuccess = 0;
4328  } else {
4329  // Try to get the next line from the input stream.
4330  if (getline (in, line)) {
4331  ++lineNumber; // We did actually read a line.
4332  }
4333  // Is the current line a comment line? Ignore start
4334  // and size; they are only useful for reading the
4335  // actual matrix entries. (We could use them here as
4336  // an optimization, but we've chosen not to.)
4337  size_t start = 0, size = 0;
4338  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4339  } // whether we failed to read the line at all
4340  } // while the line we just read is a comment line
4341 
4342  //
4343  // Get <numRows> <numCols> from the line we just read.
4344  //
4345  std::istringstream istr (line);
4346 
4347  // Test whether it is even valid to read from the input
4348  // stream wrapping the line.
4349  if (istr.eof () || istr.fail ()) {
4350  exMsg << "Unable to read any data from line " << lineNumber
4351  << " of input; the line should contain the matrix dimensions "
4352  << "\"<numRows> <numCols>\".";
4353  localDimsReadSuccess = 0;
4354  } else { // It's valid to read from the line.
4355  GO theNumRows = 0;
4356  istr >> theNumRows; // Read in the number of rows.
4357  if (istr.fail ()) {
4358  exMsg << "Failed to get number of rows from line "
4359  << lineNumber << " of input; the line should contains the "
4360  << "matrix dimensions \"<numRows> <numCols>\".";
4361  localDimsReadSuccess = 0;
4362  } else { // We successfully read the number of rows
4363  dims[0] = theNumRows; // Save the number of rows
4364  if (istr.eof ()) { // Do we still have data to read?
4365  exMsg << "No more data after number of rows on line "
4366  << lineNumber << " of input; the line should contain the "
4367  << "matrix dimensions \"<numRows> <numCols>\".";
4368  localDimsReadSuccess = 0;
4369  } else { // Still data left to read; read in number of columns.
4370  GO theNumCols = 0;
4371  istr >> theNumCols; // Read in the number of columns
4372  if (istr.fail ()) {
4373  exMsg << "Failed to get number of columns from line "
4374  << lineNumber << " of input; the line should contain "
4375  << "the matrix dimensions \"<numRows> <numCols>\".";
4376  localDimsReadSuccess = 0;
4377  } else { // We successfully read the number of columns
4378  dims[1] = theNumCols; // Save the number of columns
4379  } // if istr.fail ()
4380  } // if istr.eof ()
4381  } // if we read the number of rows
4382  } // if the input stream wrapping the dims line was (in)valid
4383  } // if we successfully read the banner line
4384  } // not in binary format
4385  else { // in binary format
4386  global_size_t numRows, numCols;
4387  in.read(reinterpret_cast<char*>(&numRows), sizeof(numRows));
4388  in.read(reinterpret_cast<char*>(&numCols), sizeof(numCols));
4389  dims[0] = Teuchos::as<GO>(numRows);
4390  dims[1] = Teuchos::as<GO>(numCols);
4391  if ((typeid(ST) == typeid(double)) || Teuchos::ScalarTraits<ST>::isOrdinal) {
4392  dims[2] = 0;
4393  } else if (Teuchos::ScalarTraits<ST>::isComplex) {
4394  dims[2] = 1;
4395  } else {
4396  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
4397  "Unrecognized Matrix Market data type. "
4398  "We should never get here. "
4399  "Please report this bug to the Tpetra developers.");
4400  }
4401  localDimsReadSuccess = true;
4402  localDimsReadSuccess = true;
4403  } // in binary format
4404  } // if (myRank == 0)
4405 
4406  // Broadcast the matrix dimensions, the encoded data type, and
4407  // whether or not Proc 0 succeeded in reading the banner and
4408  // dimensions.
4409  Tuple<GO, 5> bannerDimsReadResult;
4410  if (myRank == 0) {
4411  bannerDimsReadResult[0] = dims[0]; // numRows
4412  bannerDimsReadResult[1] = dims[1]; // numCols
4413  bannerDimsReadResult[2] = dims[2]; // encoded data type
4414  bannerDimsReadResult[3] = localBannerReadSuccess;
4415  bannerDimsReadResult[4] = localDimsReadSuccess;
4416  }
4417  // Broadcast matrix dimensions and the encoded data type from
4418  // Proc 0 to all the MPI processes.
4419  broadcast (*comm, 0, bannerDimsReadResult);
4420 
4421  TEUCHOS_TEST_FOR_EXCEPTION(
4422  bannerDimsReadResult[3] == 0, std::runtime_error,
4423  "Failed to read banner line: " << exMsg.str ());
4424  TEUCHOS_TEST_FOR_EXCEPTION(
4425  bannerDimsReadResult[4] == 0, std::runtime_error,
4426  "Failed to read matrix dimensions line: " << exMsg.str ());
4427  if (myRank != 0) {
4428  dims[0] = bannerDimsReadResult[0];
4429  dims[1] = bannerDimsReadResult[1];
4430  dims[2] = bannerDimsReadResult[2];
4431  }
4432 
4433  // Tpetra objects want the matrix dimensions in these types.
4434  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4435  const size_t numCols = static_cast<size_t> (dims[1]);
4436 
4437  // Make a "Proc 0 owns everything" Map that we will use to
4438  // read in the multivector entries in the correct order on
4439  // Proc 0. This must be a collective
4440  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4441  if (map.is_null ()) {
4442  // The user didn't supply a Map. Make a contiguous
4443  // distributed Map for them, using the read-in multivector
4444  // dimensions.
4445  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4446  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4447  // At this point, map exists and has a nonnull node.
4448  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4449  comm);
4450  }
4451  else { // The user supplied a Map.
4452  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4453  }
4454 
4455  // Make a multivector X owned entirely by Proc 0.
4456  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4457 
4458  //
4459  // On Proc 0, read the Matrix Market data from the input
4460  // stream into the multivector X.
4461  //
4462  int localReadDataSuccess = 1;
4463  if (myRank == 0) {
4464  if (! binary) {
4465  try {
4466  if (debug) {
4467  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4468  << endl;
4469  }
4470 
4471  // Make sure that we can get a 1-D view of X.
4472  TEUCHOS_TEST_FOR_EXCEPTION(
4473  ! X->isConstantStride (), std::logic_error,
4474  "Can't get a 1-D view of the entries of the MultiVector X on "
4475  "Process 0, because the stride between the columns of X is not "
4476  "constant. This shouldn't happen because we just created X and "
4477  "haven't filled it in yet. Please report this bug to the Tpetra "
4478  "developers.");
4479 
4480  // Get a writeable 1-D view of the entries of X. Rank 0
4481  // owns all of them. The view will expire at the end of
4482  // scope, so (if necessary) it will be written back to X
4483  // at this time.
4484  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4485  TEUCHOS_TEST_FOR_EXCEPTION(
4486  as<global_size_t> (X_view.size ()) < numRows * numCols,
4487  std::logic_error,
4488  "The view of X has size " << X_view.size() << " which is not enough to "
4489  "accommodate the expected number of entries numRows*numCols = "
4490  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4491  "Please report this bug to the Tpetra developers.");
4492  const size_t stride = X->getStride ();
4493 
4494  // The third element of the dimensions Tuple encodes the data
4495  // type reported by the Banner: "real" == 0, "complex" == 1,
4496  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4497  // allow dense matrices to be pattern matrices, so dims[2] ==
4498  // 0 or 1. We've already checked for this above.
4499  const bool isComplex = (dims[2] == 1);
4500  size_type count = 0, curRow = 0, curCol = 0;
4501 
4502  std::string line;
4503  while (getline (in, line)) {
4504  ++lineNumber;
4505  // Is the current line a comment line? If it's not,
4506  // line.substr(start,size) contains the data.
4507  size_t start = 0, size = 0;
4508  const bool commentLine =
4509  checkCommentLine (line, start, size, lineNumber, tolerant);
4510  if (! commentLine) {
4511  // Make sure we have room in which to put the new matrix
4512  // entry. We check this only after checking for a
4513  // comment line, because there may be one or more
4514  // comment lines at the end of the file. In tolerant
4515  // mode, we simply ignore any extra data.
4516  if (count >= X_view.size()) {
4517  if (tolerant) {
4518  break;
4519  }
4520  else {
4521  TEUCHOS_TEST_FOR_EXCEPTION(
4522  count >= X_view.size(),
4523  std::runtime_error,
4524  "The Matrix Market input stream has more data in it than "
4525  "its metadata reported. Current line number is "
4526  << lineNumber << ".");
4527  }
4528  }
4529 
4530  // mfh 19 Dec 2012: Ignore everything up to the initial
4531  // colon. writeDense() has the option to print out the
4532  // global row index in front of each entry, followed by
4533  // a colon and space.
4534  {
4535  const size_t pos = line.substr (start, size).find (':');
4536  if (pos != std::string::npos) {
4537  start = pos+1;
4538  }
4539  }
4540  std::istringstream istr (line.substr (start, size));
4541  // Does the line contain anything at all? Can we
4542  // safely read from the input stream wrapping the
4543  // line?
4544  if (istr.eof() || istr.fail()) {
4545  // In tolerant mode, simply ignore the line.
4546  if (tolerant) {
4547  break;
4548  }
4549  // We repeat the full test here so the exception
4550  // message is more informative.
4551  TEUCHOS_TEST_FOR_EXCEPTION(
4552  ! tolerant && (istr.eof() || istr.fail()),
4553  std::runtime_error,
4554  "Line " << lineNumber << " of the Matrix Market file is "
4555  "empty, or we cannot read from it for some other reason.");
4556  }
4557  // Current matrix entry to read in.
4558  ST val = STS::zero();
4559  // Real and imaginary parts of the current matrix entry.
4560  // The imaginary part is zero if the matrix is real-valued.
4561  MT real = STM::zero(), imag = STM::zero();
4562 
4563  // isComplex refers to the input stream's data, not to
4564  // the scalar type S. It's OK to read real-valued
4565  // data into a matrix storing complex-valued data; in
4566  // that case, all entries' imaginary parts are zero.
4567  if (isComplex) {
4568  // STS::real() and STS::imag() return a copy of
4569  // their respective components, not a writeable
4570  // reference. Otherwise we could just assign to
4571  // them using the istream extraction operator (>>).
4572  // That's why we have separate magnitude type "real"
4573  // and "imag" variables.
4574 
4575  // Attempt to read the real part of the current entry.
4576  istr >> real;
4577  if (istr.fail()) {
4578  TEUCHOS_TEST_FOR_EXCEPTION(
4579  ! tolerant && istr.eof(), std::runtime_error,
4580  "Failed to get the real part of a complex-valued matrix "
4581  "entry from line " << lineNumber << " of the Matrix Market "
4582  "file.");
4583  // In tolerant mode, just skip bad lines.
4584  if (tolerant) {
4585  break;
4586  }
4587  } else if (istr.eof()) {
4588  TEUCHOS_TEST_FOR_EXCEPTION(
4589  ! tolerant && istr.eof(), std::runtime_error,
4590  "Missing imaginary part of a complex-valued matrix entry "
4591  "on line " << lineNumber << " of the Matrix Market file.");
4592  // In tolerant mode, let any missing imaginary part be 0.
4593  } else {
4594  // Attempt to read the imaginary part of the current
4595  // matrix entry.
4596  istr >> imag;
4597  TEUCHOS_TEST_FOR_EXCEPTION(
4598  ! tolerant && istr.fail(), std::runtime_error,
4599  "Failed to get the imaginary part of a complex-valued "
4600  "matrix entry from line " << lineNumber << " of the "
4601  "Matrix Market file.");
4602  // In tolerant mode, let any missing or corrupted
4603  // imaginary part be 0.
4604  }
4605  } else { // Matrix Market file contains real-valued data.
4606  // Attempt to read the current matrix entry.
4607  istr >> real;
4608  TEUCHOS_TEST_FOR_EXCEPTION(
4609  ! tolerant && istr.fail(), std::runtime_error,
4610  "Failed to get a real-valued matrix entry from line "
4611  << lineNumber << " of the Matrix Market file.");
4612  // In tolerant mode, simply ignore the line if
4613  // we failed to read a matrix entry.
4614  if (istr.fail() && tolerant) {
4615  break;
4616  }
4617  }
4618  // In tolerant mode, we simply let pass through whatever
4619  // data we got.
4620  TEUCHOS_TEST_FOR_EXCEPTION(
4621  ! tolerant && istr.fail(), std::runtime_error,
4622  "Failed to read matrix data from line " << lineNumber
4623  << " of the Matrix Market file.");
4624 
4625  // Assign val = ST(real, imag).
4626  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4627 
4628  curRow = count % numRows;
4629  curCol = count / numRows;
4630  X_view[curRow + curCol*stride] = val;
4631  ++count;
4632  } // if not a comment line
4633  } // while there are still lines in the file, get the next one
4634 
4635  TEUCHOS_TEST_FOR_EXCEPTION(
4636  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4637  std::runtime_error,
4638  "The Matrix Market metadata reports that the dense matrix is "
4639  << numRows << " x " << numCols << ", and thus has "
4640  << numRows*numCols << " total entries, but we only found " << count
4641  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4642  } catch (std::exception& e) {
4643  exMsg << e.what ();
4644  localReadDataSuccess = 0;
4645  }
4646  } // not binary file
4647  else {
4648  if (debug) {
4649  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4650  << endl;
4651  }
4652 
4653  // Make sure that we can get a 1-D view of X.
4654  TEUCHOS_TEST_FOR_EXCEPTION(
4655  ! X->isConstantStride (), std::logic_error,
4656  "Can't get a 1-D view of the entries of the MultiVector X on "
4657  "Process 0, because the stride between the columns of X is not "
4658  "constant. This shouldn't happen because we just created X and "
4659  "haven't filled it in yet. Please report this bug to the Tpetra "
4660  "developers.");
4661 
4662  // Get a writeable 1-D view of the entries of X. Rank 0
4663  // owns all of them. The view will expire at the end of
4664  // scope, so (if necessary) it will be written back to X
4665  // at this time.
4666  auto X_view = X->getLocalViewHost (Access::OverwriteAll);
4667 
4668  TEUCHOS_TEST_FOR_EXCEPTION(
4669  as<global_size_t> (X_view.extent(0)) < numRows,
4670  std::logic_error,
4671  "The view of X has " << X_view.extent(0) << " rows which is not enough to "
4672  "accommodate the expected number of entries numRows = "
4673  << numRows << ". "
4674  "Please report this bug to the Tpetra developers.");
4675  TEUCHOS_TEST_FOR_EXCEPTION(
4676  as<global_size_t> (X_view.extent(1)) < numCols,
4677  std::logic_error,
4678  "The view of X has " << X_view.extent(1) << " colums which is not enough to "
4679  "accommodate the expected number of entries numRows = "
4680  << numCols << ". "
4681  "Please report this bug to the Tpetra developers.");
4682 
4683  for (size_t curRow = 0; curRow < numRows; ++curRow) {
4684  for (size_t curCol = 0; curCol < numCols; ++curCol) {
4685  if (Teuchos::ScalarTraits<ST>::isOrdinal){
4686  global_size_t val;
4687  in.read(reinterpret_cast<char*>(&val), sizeof(val));
4688  X_view(curRow, curCol) = val;
4689  } else {
4690  double val;
4691  in.read(reinterpret_cast<char*>(&val), sizeof(val));
4692  X_view(curRow, curCol) = val;
4693  }
4694  }
4695  }
4696  } // binary
4697  } // if (myRank == 0)
4698 
4699  if (debug) {
4700  *err << myRank << ": readDenseImpl: done reading data" << endl;
4701  }
4702 
4703  // Synchronize on whether Proc 0 successfully read the data.
4704  int globalReadDataSuccess = localReadDataSuccess;
4705  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4706  TEUCHOS_TEST_FOR_EXCEPTION(
4707  globalReadDataSuccess == 0, std::runtime_error,
4708  "Failed to read the multivector's data: " << exMsg.str ());
4709 
4710  // If there's only one MPI process and the user didn't supply
4711  // a Map (i.e., pMap is null), we're done. Set pMap to the
4712  // Map used to distribute X, and return X.
4713  if (comm->getSize () == 1 && map.is_null ()) {
4714  map = proc0Map;
4715  if (! err.is_null ()) {
4716  err->popTab ();
4717  }
4718  if (debug) {
4719  *err << myRank << ": readDenseImpl: done" << endl;
4720  }
4721  if (! err.is_null ()) {
4722  err->popTab ();
4723  }
4724  return X;
4725  }
4726 
4727  if (debug) {
4728  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4729  }
4730 
4731  // Make a multivector Y with the distributed map pMap.
4732  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4733 
4734  if (debug) {
4735  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4736  }
4737 
4738  // Make an Export object that will export X to Y. First
4739  // argument is the source map, second argument is the target
4740  // map.
4741  Export<LO, GO, NT> exporter (proc0Map, map, err);
4742 
4743  if (debug) {
4744  *err << myRank << ": readDenseImpl: Exporting" << endl;
4745  }
4746  // Export X into Y.
4747  Y->doExport (*X, exporter, INSERT);
4748 
4749  if (! err.is_null ()) {
4750  err->popTab ();
4751  }
4752  if (debug) {
4753  *err << myRank << ": readDenseImpl: done" << endl;
4754  }
4755  if (! err.is_null ()) {
4756  err->popTab ();
4757  }
4758 
4759  // Y is distributed over all process(es) in the communicator.
4760  return Y;
4761  }
4762 
4763 
4764  template<class VectorScalarType>
4765  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4768  node_type> >
4769  readVectorImpl (std::istream& in,
4770  const Teuchos::RCP<const comm_type>& comm,
4771  Teuchos::RCP<const map_type>& map,
4772  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4773  const bool tolerant=false,
4774  const bool debug=false)
4775  {
4776  using Teuchos::MatrixMarket::Banner;
4777  using Teuchos::MatrixMarket::checkCommentLine;
4778  using Teuchos::as;
4779  using Teuchos::broadcast;
4780  using Teuchos::outArg;
4781  using Teuchos::RCP;
4782  using Teuchos::Tuple;
4783  using std::endl;
4784  typedef VectorScalarType ST;
4785  typedef local_ordinal_type LO;
4786  typedef global_ordinal_type GO;
4787  typedef node_type NT;
4788  typedef Teuchos::ScalarTraits<ST> STS;
4789  typedef typename STS::magnitudeType MT;
4790  typedef Teuchos::ScalarTraits<MT> STM;
4791  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4792 
4793  // Rank 0 is the only (MPI) process allowed to read from the
4794  // input stream.
4795  const int myRank = comm->getRank ();
4796 
4797  if (! err.is_null ()) {
4798  err->pushTab ();
4799  }
4800  if (debug) {
4801  *err << myRank << ": readVectorImpl" << endl;
4802  }
4803  if (! err.is_null ()) {
4804  err->pushTab ();
4805  }
4806 
4807  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4808  // instances be identical and that the Node instances be
4809  // identical. The essential condition is more complicated to
4810  // test and isn't the same for all Node types. Thus, we just
4811  // leave it up to the user.
4812 
4813  // // If map is nonnull, check the precondition that its
4814  // // communicator resp. node equal comm resp. node. Checking
4815  // // now avoids doing a lot of file reading before we detect the
4816  // // violated precondition.
4817  // TEUCHOS_TEST_FOR_EXCEPTION(
4818  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4819  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4820  // "communicator and node must equal the supplied communicator resp. "
4821  // "node.");
4822 
4823  // Process 0 will read in the matrix dimensions from the file,
4824  // and broadcast them to all ranks in the given communicator.
4825  // There are only 2 dimensions in the matrix, but we use the
4826  // third element of the Tuple to encode the banner's reported
4827  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4828  // (same as "real"). We don't allow pattern matrices (i.e.,
4829  // graphs) since they only make sense for sparse data.
4830  Tuple<GO, 3> dims;
4831  dims[0] = 0;
4832  dims[1] = 0;
4833 
4834  // Current line number in the input stream. Only valid on
4835  // Proc 0. Various calls will modify this depending on the
4836  // number of lines that are read from the input stream.
4837  size_t lineNumber = 1;
4838 
4839  // Capture errors and their messages on Proc 0.
4840  std::ostringstream exMsg;
4841  int localBannerReadSuccess = 1;
4842  int localDimsReadSuccess = 1;
4843 
4844  // Only Proc 0 gets to read matrix data from the input stream.
4845  if (myRank == 0) {
4846  if (debug) {
4847  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4848  }
4849 
4850  // The "Banner" tells you whether the input stream
4851  // represents a dense matrix, the symmetry type of the
4852  // matrix, and the type of the data it contains.
4853  RCP<const Banner> pBanner;
4854  try {
4855  pBanner = readBanner (in, lineNumber, tolerant, debug);
4856  } catch (std::exception& e) {
4857  exMsg << e.what ();
4858  localBannerReadSuccess = 0;
4859  }
4860  // Make sure the input stream is the right kind of data.
4861  if (localBannerReadSuccess) {
4862  if (pBanner->matrixType () != "array") {
4863  exMsg << "The Matrix Market file does not contain dense matrix "
4864  "data. Its banner (first) line says that its matrix type is \""
4865  << pBanner->matrixType () << "\", rather that the required "
4866  "\"array\".";
4867  localBannerReadSuccess = 0;
4868  } else if (pBanner->dataType() == "pattern") {
4869  exMsg << "The Matrix Market file's banner (first) "
4870  "line claims that the matrix's data type is \"pattern\". This does "
4871  "not make sense for a dense matrix, yet the file reports the matrix "
4872  "as dense. The only valid data types for a dense matrix are "
4873  "\"real\", \"complex\", and \"integer\".";
4874  localBannerReadSuccess = 0;
4875  } else {
4876  // Encode the data type reported by the Banner as the
4877  // third element of the dimensions Tuple.
4878  dims[2] = encodeDataType (pBanner->dataType ());
4879  }
4880  } // if we successfully read the banner line
4881 
4882  // At this point, we've successfully read the banner line.
4883  // Now read the dimensions line.
4884  if (localBannerReadSuccess) {
4885  if (debug) {
4886  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4887  }
4888  // Keep reading lines from the input stream until we find
4889  // a non-comment line, or until we run out of lines. The
4890  // latter is an error, since every "array" format Matrix
4891  // Market file must have a dimensions line after the
4892  // banner (even if the matrix has zero rows or columns, or
4893  // zero entries).
4894  std::string line;
4895  bool commentLine = true;
4896 
4897  while (commentLine) {
4898  // Test whether it is even valid to read from the input
4899  // stream wrapping the line.
4900  if (in.eof () || in.fail ()) {
4901  exMsg << "Unable to get array dimensions line (at all) from line "
4902  << lineNumber << " of input stream. The input stream "
4903  << "claims that it is "
4904  << (in.eof() ? "at end-of-file." : "in a failed state.");
4905  localDimsReadSuccess = 0;
4906  } else {
4907  // Try to get the next line from the input stream.
4908  if (getline (in, line)) {
4909  ++lineNumber; // We did actually read a line.
4910  }
4911  // Is the current line a comment line? Ignore start
4912  // and size; they are only useful for reading the
4913  // actual matrix entries. (We could use them here as
4914  // an optimization, but we've chosen not to.)
4915  size_t start = 0, size = 0;
4916  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4917  } // whether we failed to read the line at all
4918  } // while the line we just read is a comment line
4919 
4920  //
4921  // Get <numRows> <numCols> from the line we just read.
4922  //
4923  std::istringstream istr (line);
4924 
4925  // Test whether it is even valid to read from the input
4926  // stream wrapping the line.
4927  if (istr.eof () || istr.fail ()) {
4928  exMsg << "Unable to read any data from line " << lineNumber
4929  << " of input; the line should contain the matrix dimensions "
4930  << "\"<numRows> <numCols>\".";
4931  localDimsReadSuccess = 0;
4932  } else { // It's valid to read from the line.
4933  GO theNumRows = 0;
4934  istr >> theNumRows; // Read in the number of rows.
4935  if (istr.fail ()) {
4936  exMsg << "Failed to get number of rows from line "
4937  << lineNumber << " of input; the line should contains the "
4938  << "matrix dimensions \"<numRows> <numCols>\".";
4939  localDimsReadSuccess = 0;
4940  } else { // We successfully read the number of rows
4941  dims[0] = theNumRows; // Save the number of rows
4942  if (istr.eof ()) { // Do we still have data to read?
4943  exMsg << "No more data after number of rows on line "
4944  << lineNumber << " of input; the line should contain the "
4945  << "matrix dimensions \"<numRows> <numCols>\".";
4946  localDimsReadSuccess = 0;
4947  } else { // Still data left to read; read in number of columns.
4948  GO theNumCols = 0;
4949  istr >> theNumCols; // Read in the number of columns
4950  if (istr.fail ()) {
4951  exMsg << "Failed to get number of columns from line "
4952  << lineNumber << " of input; the line should contain "
4953  << "the matrix dimensions \"<numRows> <numCols>\".";
4954  localDimsReadSuccess = 0;
4955  } else { // We successfully read the number of columns
4956  dims[1] = theNumCols; // Save the number of columns
4957  } // if istr.fail ()
4958  } // if istr.eof ()
4959  } // if we read the number of rows
4960  } // if the input stream wrapping the dims line was (in)valid
4961  } // if we successfully read the banner line
4962  } // if (myRank == 0)
4963 
4964  // Check if file has a Vector
4965  if (dims[1]!=1) {
4966  exMsg << "File does not contain a 1D Vector";
4967  localDimsReadSuccess = 0;
4968  }
4969 
4970  // Broadcast the matrix dimensions, the encoded data type, and
4971  // whether or not Proc 0 succeeded in reading the banner and
4972  // dimensions.
4973  Tuple<GO, 5> bannerDimsReadResult;
4974  if (myRank == 0) {
4975  bannerDimsReadResult[0] = dims[0]; // numRows
4976  bannerDimsReadResult[1] = dims[1]; // numCols
4977  bannerDimsReadResult[2] = dims[2]; // encoded data type
4978  bannerDimsReadResult[3] = localBannerReadSuccess;
4979  bannerDimsReadResult[4] = localDimsReadSuccess;
4980  }
4981 
4982  // Broadcast matrix dimensions and the encoded data type from
4983  // Proc 0 to all the MPI processes.
4984  broadcast (*comm, 0, bannerDimsReadResult);
4985 
4986  TEUCHOS_TEST_FOR_EXCEPTION(
4987  bannerDimsReadResult[3] == 0, std::runtime_error,
4988  "Failed to read banner line: " << exMsg.str ());
4989  TEUCHOS_TEST_FOR_EXCEPTION(
4990  bannerDimsReadResult[4] == 0, std::runtime_error,
4991  "Failed to read matrix dimensions line: " << exMsg.str ());
4992  if (myRank != 0) {
4993  dims[0] = bannerDimsReadResult[0];
4994  dims[1] = bannerDimsReadResult[1];
4995  dims[2] = bannerDimsReadResult[2];
4996  }
4997 
4998  // Tpetra objects want the matrix dimensions in these types.
4999  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
5000  const size_t numCols = static_cast<size_t> (dims[1]);
5001 
5002  // Make a "Proc 0 owns everything" Map that we will use to
5003  // read in the multivector entries in the correct order on
5004  // Proc 0. This must be a collective
5005  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
5006  if (map.is_null ()) {
5007  // The user didn't supply a Map. Make a contiguous
5008  // distributed Map for them, using the read-in multivector
5009  // dimensions.
5010  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
5011  const size_t localNumRows = (myRank == 0) ? numRows : 0;
5012  // At this point, map exists and has a nonnull node.
5013  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
5014  comm);
5015  }
5016  else { // The user supplied a Map.
5017  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
5018  }
5019 
5020  // Make a multivector X owned entirely by Proc 0.
5021  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
5022 
5023  //
5024  // On Proc 0, read the Matrix Market data from the input
5025  // stream into the multivector X.
5026  //
5027  int localReadDataSuccess = 1;
5028  if (myRank == 0) {
5029  try {
5030  if (debug) {
5031  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
5032  << endl;
5033  }
5034 
5035  // Make sure that we can get a 1-D view of X.
5036  TEUCHOS_TEST_FOR_EXCEPTION(
5037  ! X->isConstantStride (), std::logic_error,
5038  "Can't get a 1-D view of the entries of the MultiVector X on "
5039  "Process 0, because the stride between the columns of X is not "
5040  "constant. This shouldn't happen because we just created X and "
5041  "haven't filled it in yet. Please report this bug to the Tpetra "
5042  "developers.");
5043 
5044  // Get a writeable 1-D view of the entries of X. Rank 0
5045  // owns all of them. The view will expire at the end of
5046  // scope, so (if necessary) it will be written back to X
5047  // at this time.
5048  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
5049  TEUCHOS_TEST_FOR_EXCEPTION(
5050  as<global_size_t> (X_view.size ()) < numRows * numCols,
5051  std::logic_error,
5052  "The view of X has size " << X_view << " which is not enough to "
5053  "accommodate the expected number of entries numRows*numCols = "
5054  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
5055  "Please report this bug to the Tpetra developers.");
5056  const size_t stride = X->getStride ();
5057 
5058  // The third element of the dimensions Tuple encodes the data
5059  // type reported by the Banner: "real" == 0, "complex" == 1,
5060  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
5061  // allow dense matrices to be pattern matrices, so dims[2] ==
5062  // 0 or 1. We've already checked for this above.
5063  const bool isComplex = (dims[2] == 1);
5064  size_type count = 0, curRow = 0, curCol = 0;
5065 
5066  std::string line;
5067  while (getline (in, line)) {
5068  ++lineNumber;
5069  // Is the current line a comment line? If it's not,
5070  // line.substr(start,size) contains the data.
5071  size_t start = 0, size = 0;
5072  const bool commentLine =
5073  checkCommentLine (line, start, size, lineNumber, tolerant);
5074  if (! commentLine) {
5075  // Make sure we have room in which to put the new matrix
5076  // entry. We check this only after checking for a
5077  // comment line, because there may be one or more
5078  // comment lines at the end of the file. In tolerant
5079  // mode, we simply ignore any extra data.
5080  if (count >= X_view.size()) {
5081  if (tolerant) {
5082  break;
5083  }
5084  else {
5085  TEUCHOS_TEST_FOR_EXCEPTION(
5086  count >= X_view.size(),
5087  std::runtime_error,
5088  "The Matrix Market input stream has more data in it than "
5089  "its metadata reported. Current line number is "
5090  << lineNumber << ".");
5091  }
5092  }
5093 
5094  // mfh 19 Dec 2012: Ignore everything up to the initial
5095  // colon. writeDense() has the option to print out the
5096  // global row index in front of each entry, followed by
5097  // a colon and space.
5098  {
5099  const size_t pos = line.substr (start, size).find (':');
5100  if (pos != std::string::npos) {
5101  start = pos+1;
5102  }
5103  }
5104  std::istringstream istr (line.substr (start, size));
5105  // Does the line contain anything at all? Can we
5106  // safely read from the input stream wrapping the
5107  // line?
5108  if (istr.eof() || istr.fail()) {
5109  // In tolerant mode, simply ignore the line.
5110  if (tolerant) {
5111  break;
5112  }
5113  // We repeat the full test here so the exception
5114  // message is more informative.
5115  TEUCHOS_TEST_FOR_EXCEPTION(
5116  ! tolerant && (istr.eof() || istr.fail()),
5117  std::runtime_error,
5118  "Line " << lineNumber << " of the Matrix Market file is "
5119  "empty, or we cannot read from it for some other reason.");
5120  }
5121  // Current matrix entry to read in.
5122  ST val = STS::zero();
5123  // Real and imaginary parts of the current matrix entry.
5124  // The imaginary part is zero if the matrix is real-valued.
5125  MT real = STM::zero(), imag = STM::zero();
5126 
5127  // isComplex refers to the input stream's data, not to
5128  // the scalar type S. It's OK to read real-valued
5129  // data into a matrix storing complex-valued data; in
5130  // that case, all entries' imaginary parts are zero.
5131  if (isComplex) {
5132  // STS::real() and STS::imag() return a copy of
5133  // their respective components, not a writeable
5134  // reference. Otherwise we could just assign to
5135  // them using the istream extraction operator (>>).
5136  // That's why we have separate magnitude type "real"
5137  // and "imag" variables.
5138 
5139  // Attempt to read the real part of the current entry.
5140  istr >> real;
5141  if (istr.fail()) {
5142  TEUCHOS_TEST_FOR_EXCEPTION(
5143  ! tolerant && istr.eof(), std::runtime_error,
5144  "Failed to get the real part of a complex-valued matrix "
5145  "entry from line " << lineNumber << " of the Matrix Market "
5146  "file.");
5147  // In tolerant mode, just skip bad lines.
5148  if (tolerant) {
5149  break;
5150  }
5151  } else if (istr.eof()) {
5152  TEUCHOS_TEST_FOR_EXCEPTION(
5153  ! tolerant && istr.eof(), std::runtime_error,
5154  "Missing imaginary part of a complex-valued matrix entry "
5155  "on line " << lineNumber << " of the Matrix Market file.");
5156  // In tolerant mode, let any missing imaginary part be 0.
5157  } else {
5158  // Attempt to read the imaginary part of the current
5159  // matrix entry.
5160  istr >> imag;
5161  TEUCHOS_TEST_FOR_EXCEPTION(
5162  ! tolerant && istr.fail(), std::runtime_error,
5163  "Failed to get the imaginary part of a complex-valued "
5164  "matrix entry from line " << lineNumber << " of the "
5165  "Matrix Market file.");
5166  // In tolerant mode, let any missing or corrupted
5167  // imaginary part be 0.
5168  }
5169  } else { // Matrix Market file contains real-valued data.
5170  // Attempt to read the current matrix entry.
5171  istr >> real;
5172  TEUCHOS_TEST_FOR_EXCEPTION(
5173  ! tolerant && istr.fail(), std::runtime_error,
5174  "Failed to get a real-valued matrix entry from line "
5175  << lineNumber << " of the Matrix Market file.");
5176  // In tolerant mode, simply ignore the line if
5177  // we failed to read a matrix entry.
5178  if (istr.fail() && tolerant) {
5179  break;
5180  }
5181  }
5182  // In tolerant mode, we simply let pass through whatever
5183  // data we got.
5184  TEUCHOS_TEST_FOR_EXCEPTION(
5185  ! tolerant && istr.fail(), std::runtime_error,
5186  "Failed to read matrix data from line " << lineNumber
5187  << " of the Matrix Market file.");
5188 
5189  // Assign val = ST(real, imag).
5190  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5191 
5192  curRow = count % numRows;
5193  curCol = count / numRows;
5194  X_view[curRow + curCol*stride] = val;
5195  ++count;
5196  } // if not a comment line
5197  } // while there are still lines in the file, get the next one
5198 
5199  TEUCHOS_TEST_FOR_EXCEPTION(
5200  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5201  std::runtime_error,
5202  "The Matrix Market metadata reports that the dense matrix is "
5203  << numRows << " x " << numCols << ", and thus has "
5204  << numRows*numCols << " total entries, but we only found " << count
5205  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5206  } catch (std::exception& e) {
5207  exMsg << e.what ();
5208  localReadDataSuccess = 0;
5209  }
5210  } // if (myRank == 0)
5211 
5212  if (debug) {
5213  *err << myRank << ": readVectorImpl: done reading data" << endl;
5214  }
5215 
5216  // Synchronize on whether Proc 0 successfully read the data.
5217  int globalReadDataSuccess = localReadDataSuccess;
5218  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5219  TEUCHOS_TEST_FOR_EXCEPTION(
5220  globalReadDataSuccess == 0, std::runtime_error,
5221  "Failed to read the multivector's data: " << exMsg.str ());
5222 
5223  // If there's only one MPI process and the user didn't supply
5224  // a Map (i.e., pMap is null), we're done. Set pMap to the
5225  // Map used to distribute X, and return X.
5226  if (comm->getSize () == 1 && map.is_null ()) {
5227  map = proc0Map;
5228  if (! err.is_null ()) {
5229  err->popTab ();
5230  }
5231  if (debug) {
5232  *err << myRank << ": readVectorImpl: done" << endl;
5233  }
5234  if (! err.is_null ()) {
5235  err->popTab ();
5236  }
5237  return X;
5238  }
5239 
5240  if (debug) {
5241  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5242  }
5243 
5244  // Make a multivector Y with the distributed map pMap.
5245  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5246 
5247  if (debug) {
5248  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5249  }
5250 
5251  // Make an Export object that will export X to Y. First
5252  // argument is the source map, second argument is the target
5253  // map.
5254  Export<LO, GO, NT> exporter (proc0Map, map, err);
5255 
5256  if (debug) {
5257  *err << myRank << ": readVectorImpl: Exporting" << endl;
5258  }
5259  // Export X into Y.
5260  Y->doExport (*X, exporter, INSERT);
5261 
5262  if (! err.is_null ()) {
5263  err->popTab ();
5264  }
5265  if (debug) {
5266  *err << myRank << ": readVectorImpl: done" << endl;
5267  }
5268  if (! err.is_null ()) {
5269  err->popTab ();
5270  }
5271 
5272  // Y is distributed over all process(es) in the communicator.
5273  return Y;
5274  }
5275 
5276  public:
5297  static Teuchos::RCP<const map_type>
5298  readMap (std::istream& in,
5299  const Teuchos::RCP<const comm_type>& comm,
5300  const bool tolerant=false,
5301  const bool debug=false,
5302  const bool binary=false)
5303  {
5304  Teuchos::RCP<Teuchos::FancyOStream> err =
5305  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5306  return readMap (in, comm, err, tolerant, debug, binary);
5307  }
5308 
5309 
5336  static Teuchos::RCP<const map_type>
5337  readMap (std::istream& in,
5338  const Teuchos::RCP<const comm_type>& comm,
5339  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5340  const bool tolerant=false,
5341  const bool debug=false,
5342  const bool binary=false)
5343  {
5344  using Teuchos::arcp;
5345  using Teuchos::Array;
5346  using Teuchos::ArrayRCP;
5347  using Teuchos::as;
5348  using Teuchos::broadcast;
5349  using Teuchos::Comm;
5350  using Teuchos::CommRequest;
5351  using Teuchos::inOutArg;
5352  using Teuchos::ireceive;
5353  using Teuchos::outArg;
5354  using Teuchos::RCP;
5355  using Teuchos::receive;
5356  using Teuchos::reduceAll;
5357  using Teuchos::REDUCE_MIN;
5358  using Teuchos::isend;
5359  using Teuchos::SerialComm;
5360  using Teuchos::toString;
5361  using Teuchos::wait;
5362  using std::endl;
5363  typedef Tpetra::global_size_t GST;
5364  typedef ptrdiff_t int_type; // Can hold int and GO
5365  typedef local_ordinal_type LO;
5366  typedef global_ordinal_type GO;
5367  typedef node_type NT;
5369 
5370  const int numProcs = comm->getSize ();
5371  const int myRank = comm->getRank ();
5372 
5373  if (err.is_null ()) {
5374  err->pushTab ();
5375  }
5376  if (debug) {
5377  std::ostringstream os;
5378  os << myRank << ": readMap: " << endl;
5379  *err << os.str ();
5380  }
5381  if (err.is_null ()) {
5382  err->pushTab ();
5383  }
5384 
5385  // Tag for receive-size / send-size messages. writeMap used
5386  // tags 1337 and 1338; we count up from there.
5387  const int sizeTag = 1339;
5388  // Tag for receive-data / send-data messages.
5389  const int dataTag = 1340;
5390 
5391  // These are for sends on Process 0, and for receives on all
5392  // other processes. sizeReq is for the {receive,send}-size
5393  // message, and dataReq is for the message containing the
5394  // actual GIDs to belong to the receiving process.
5395  RCP<CommRequest<int> > sizeReq;
5396  RCP<CommRequest<int> > dataReq;
5397 
5398  // Each process will have to receive the number of GIDs to
5399  // expect. Thus, we can post the receives now, and cancel
5400  // them if something should go wrong in the meantime.
5401  ArrayRCP<int_type> numGidsToRecv (1);
5402  numGidsToRecv[0] = 0;
5403  if (myRank != 0) {
5404  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5405  }
5406 
5407  int readSuccess = 1;
5408  std::ostringstream exMsg;
5409  RCP<MV> data; // Will only be valid on Proc 0
5410  if (myRank == 0) {
5411  // If we want to reuse readDenseImpl, we have to make a
5412  // communicator that only contains Proc 0. Otherwise,
5413  // readDenseImpl will redistribute the data to all
5414  // processes. While we eventually want that, neither we nor
5415  // readDenseImpl know the correct Map to use at the moment.
5416  // That depends on the second column of the multivector.
5417  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5418  try {
5419  RCP<const map_type> dataMap;
5420  // This is currently the only place where we use the
5421  // 'tolerant' argument. Later, if we want to be clever,
5422  // we could have tolerant mode allow PIDs out of order.
5423  data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug, binary);
5424  (void) dataMap; // Silence "unused" warnings
5425  if (data.is_null ()) {
5426  readSuccess = 0;
5427  exMsg << "readDenseImpl() returned null." << endl;
5428  }
5429  } catch (std::exception& e) {
5430  readSuccess = 0;
5431  exMsg << e.what () << endl;
5432  }
5433  }
5434 
5435  // Map from PID to all the GIDs for that PID.
5436  // Only populated on Process 0.
5437  std::map<int, Array<GO> > pid2gids;
5438 
5439  // The index base must be the global minimum GID.
5440  // We will compute this on Process 0 and broadcast,
5441  // so that all processes can set up the Map.
5442  int_type globalNumGIDs = 0;
5443 
5444  // The index base must be the global minimum GID.
5445  // We will compute this on Process 0 and broadcast,
5446  // so that all processes can set up the Map.
5447  GO indexBase = 0;
5448 
5449  // Process 0: If the above read of the MultiVector succeeded,
5450  // extract the GIDs and PIDs into pid2gids, and find the
5451  // global min GID.
5452  if (myRank == 0 && readSuccess == 1) {
5453  if (data->getNumVectors () == 2) { // Map format 1.0
5454  ArrayRCP<const GO> GIDs = data->getData (0);
5455  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5456  globalNumGIDs = GIDs.size ();
5457 
5458  // Start computing the global min GID, while collecting
5459  // the GIDs for each PID.
5460  if (globalNumGIDs > 0) {
5461  const int pid = static_cast<int> (PIDs[0]);
5462 
5463  if (pid < 0 || pid >= numProcs) {
5464  readSuccess = 0;
5465  exMsg << "Tpetra::MatrixMarket::readMap: "
5466  << "Encountered invalid PID " << pid << "." << endl;
5467  }
5468  else {
5469  const GO gid = GIDs[0];
5470  pid2gids[pid].push_back (gid);
5471  indexBase = gid; // the current min GID
5472  }
5473  }
5474  if (readSuccess == 1) {
5475  // Collect the rest of the GIDs for each PID, and compute
5476  // the global min GID.
5477  for (size_type k = 1; k < globalNumGIDs; ++k) {
5478  const int pid = static_cast<int> (PIDs[k]);
5479  if (pid < 0 || pid >= numProcs) {
5480  readSuccess = 0;
5481  exMsg << "Tpetra::MatrixMarket::readMap: "
5482  << "Encountered invalid PID " << pid << "." << endl;
5483  }
5484  else {
5485  const int_type gid = GIDs[k];
5486  pid2gids[pid].push_back (gid);
5487  if (gid < indexBase) {
5488  indexBase = gid; // the current min GID
5489  }
5490  }
5491  }
5492  }
5493  }
5494  else if (data->getNumVectors () == 1) { // Map format 2.0
5495  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5496  readSuccess = 0;
5497  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5498  "wrong format (for Map format 2.0). The global number of rows "
5499  "in the MultiVector must be even (divisible by 2)." << endl;
5500  }
5501  else {
5502  ArrayRCP<const GO> theData = data->getData (0);
5503  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5504  static_cast<GO> (2);
5505 
5506  // Start computing the global min GID, while
5507  // collecting the GIDs for each PID.
5508  if (globalNumGIDs > 0) {
5509  const int pid = static_cast<int> (theData[1]);
5510  if (pid < 0 || pid >= numProcs) {
5511  readSuccess = 0;
5512  exMsg << "Tpetra::MatrixMarket::readMap: "
5513  << "Encountered invalid PID " << pid << "." << endl;
5514  }
5515  else {
5516  const GO gid = theData[0];
5517  pid2gids[pid].push_back (gid);
5518  indexBase = gid; // the current min GID
5519  }
5520  }
5521  // Collect the rest of the GIDs for each PID, and
5522  // compute the global min GID.
5523  for (int_type k = 1; k < globalNumGIDs; ++k) {
5524  const int pid = static_cast<int> (theData[2*k + 1]);
5525  if (pid < 0 || pid >= numProcs) {
5526  readSuccess = 0;
5527  exMsg << "Tpetra::MatrixMarket::readMap: "
5528  << "Encountered invalid PID " << pid << "." << endl;
5529  }
5530  else {
5531  const GO gid = theData[2*k];
5532  pid2gids[pid].push_back (gid);
5533  if (gid < indexBase) {
5534  indexBase = gid; // the current min GID
5535  }
5536  }
5537  } // for each GID
5538  } // if the amount of data is correct
5539  }
5540  else {
5541  readSuccess = 0;
5542  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5543  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5544  "the old Map format 1.0).";
5545  }
5546  } // myRank is zero
5547 
5548  // Broadcast the indexBase, the global number of GIDs, and the
5549  // current success status. Use int_type for all of these.
5550  {
5551  int_type readResults[3];
5552  readResults[0] = static_cast<int_type> (indexBase);
5553  readResults[1] = static_cast<int_type> (globalNumGIDs);
5554  readResults[2] = static_cast<int_type> (readSuccess);
5555  broadcast<int, int_type> (*comm, 0, 3, readResults);
5556 
5557  indexBase = static_cast<GO> (readResults[0]);
5558  globalNumGIDs = static_cast<int_type> (readResults[1]);
5559  readSuccess = static_cast<int> (readResults[2]);
5560  }
5561 
5562  // Unwinding the stack will invoke sizeReq's destructor, which
5563  // will cancel the receive-size request on all processes that
5564  // posted it.
5565  TEUCHOS_TEST_FOR_EXCEPTION(
5566  readSuccess != 1, std::runtime_error,
5567  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5568  "following exception message: " << exMsg.str ());
5569 
5570  if (myRank == 0) {
5571  // Proc 0: Send each process' number of GIDs to that process.
5572  for (int p = 1; p < numProcs; ++p) {
5573  ArrayRCP<int_type> numGidsToSend (1);
5574 
5575  auto it = pid2gids.find (p);
5576  if (it == pid2gids.end ()) {
5577  numGidsToSend[0] = 0;
5578  } else {
5579  numGidsToSend[0] = it->second.size ();
5580  }
5581  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5582  wait<int> (*comm, outArg (sizeReq));
5583  }
5584  }
5585  else {
5586  // Wait on the receive-size message to finish.
5587  wait<int> (*comm, outArg (sizeReq));
5588  }
5589 
5590  // Allocate / get the array for my GIDs.
5591  // Only Process 0 will have its actual GIDs at this point.
5592  ArrayRCP<GO> myGids;
5593  int_type myNumGids = 0;
5594  if (myRank == 0) {
5595  GO* myGidsRaw = NULL;
5596 
5597  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5598  if (it != pid2gids.end ()) {
5599  myGidsRaw = it->second.getRawPtr ();
5600  myNumGids = it->second.size ();
5601  // Nonowning ArrayRCP just views the Array.
5602  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5603  }
5604  }
5605  else { // myRank != 0
5606  myNumGids = numGidsToRecv[0];
5607  myGids = arcp<GO> (myNumGids);
5608  }
5609 
5610  if (myRank != 0) {
5611  // Post receive for data, now that we know how much data we
5612  // will receive. Only post receive if my process actually
5613  // has nonzero GIDs.
5614  if (myNumGids > 0) {
5615  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5616  }
5617  }
5618 
5619  for (int p = 1; p < numProcs; ++p) {
5620  if (myRank == 0) {
5621  ArrayRCP<GO> sendGids; // to send to Process p
5622  GO* sendGidsRaw = NULL;
5623  int_type numSendGids = 0;
5624 
5625  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5626  if (it != pid2gids.end ()) {
5627  numSendGids = it->second.size ();
5628  sendGidsRaw = it->second.getRawPtr ();
5629  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5630  }
5631  // Only send if that process actually has nonzero GIDs.
5632  if (numSendGids > 0) {
5633  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5634  }
5635  wait<int> (*comm, outArg (dataReq));
5636  }
5637  else if (myRank == p) {
5638  // Wait on my receive of GIDs to finish.
5639  wait<int> (*comm, outArg (dataReq));
5640  }
5641  } // for each process rank p in 1, 2, ..., numProcs-1
5642 
5643  if (debug) {
5644  std::ostringstream os;
5645  os << myRank << ": readMap: creating Map" << endl;
5646  *err << os.str ();
5647  }
5648  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5649  RCP<const map_type> newMap;
5650 
5651  // Create the Map; test whether the constructor threw. This
5652  // avoids deadlock and makes error reporting more readable.
5653 
5654  int lclSuccess = 1;
5655  int gblSuccess = 0; // output argument
5656  std::ostringstream errStrm;
5657  try {
5658  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5659  }
5660  catch (std::exception& e) {
5661  lclSuccess = 0;
5662  errStrm << "Process " << comm->getRank () << " threw an exception: "
5663  << e.what () << std::endl;
5664  }
5665  catch (...) {
5666  lclSuccess = 0;
5667  errStrm << "Process " << comm->getRank () << " threw an exception "
5668  "not a subclass of std::exception" << std::endl;
5669  }
5670  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5671  lclSuccess, Teuchos::outArg (gblSuccess));
5672  if (gblSuccess != 1) {
5673  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5674  }
5675  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5676 
5677  if (err.is_null ()) {
5678  err->popTab ();
5679  }
5680  if (debug) {
5681  std::ostringstream os;
5682  os << myRank << ": readMap: done" << endl;
5683  *err << os.str ();
5684  }
5685  if (err.is_null ()) {
5686  err->popTab ();
5687  }
5688  return newMap;
5689  }
5690 
5691 
5692  private:
5693 
5704  static int
5705  encodeDataType (const std::string& dataType)
5706  {
5707  if (dataType == "real" || dataType == "integer") {
5708  return 0;
5709  } else if (dataType == "complex") {
5710  return 1;
5711  } else if (dataType == "pattern") {
5712  return 2;
5713  } else {
5714  // We should never get here, since Banner validates the
5715  // reported data type and ensures it is one of the accepted
5716  // values.
5717  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5718  "Unrecognized Matrix Market data type \"" << dataType
5719  << "\". We should never get here. "
5720  "Please report this bug to the Tpetra developers.");
5721  }
5722  }
5723 
5724  public:
5725 
5755  static Teuchos::RCP<sparse_matrix_type>
5756  readSparsePerRank (const std::string& filename_prefix,
5757  const std::string& filename_suffix,
5758  const Teuchos::RCP<const map_type>& rowMap,
5759  Teuchos::RCP<const map_type>& colMap,
5760  const Teuchos::RCP<const map_type>& domainMap,
5761  const Teuchos::RCP<const map_type>& rangeMap,
5762  const bool callFillComplete=true,
5763  const bool tolerant=false,
5764  const int ranksToReadAtOnce=8,
5765  const bool debug=false)
5766  {
5767  using ST = scalar_type;
5768  using LO = local_ordinal_type;
5769  using GO = global_ordinal_type;
5770  using STS = typename Teuchos::ScalarTraits<ST>;
5771  using Teuchos::RCP;
5772  using Teuchos::ArrayRCP;
5773  using Teuchos::arcp;
5774  using Teuchos::rcp;
5775 
5776  // Sanity Checks
5777  // Fast checks for invalid input. We can't check other
5778  // attributes of the Maps until we've read in the matrix
5779  // dimensions.
5780  TEUCHOS_TEST_FOR_EXCEPTION(
5781  rowMap.is_null (), std::invalid_argument,
5782  "Row Map must be nonnull.");
5783  Teuchos::RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
5784  TEUCHOS_TEST_FOR_EXCEPTION
5785  (comm.is_null (), std::invalid_argument,
5786  "The input row map's communicator (Teuchos::Comm object) is null.");
5787  TEUCHOS_TEST_FOR_EXCEPTION(
5788  rangeMap.is_null (), std::invalid_argument,
5789  "Range Map must be nonnull.");
5790  TEUCHOS_TEST_FOR_EXCEPTION(
5791  domainMap.is_null (), std::invalid_argument,
5792  "Domain Map must be nonnull.");
5793  TEUCHOS_TEST_FOR_EXCEPTION(
5794  domainMap->getComm().getRawPtr() != comm.getRawPtr(),
5795  std::invalid_argument,
5796  "The specified domain Map's communicator (domainMap->getComm())"
5797  "differs from row Map's communicator");
5798  TEUCHOS_TEST_FOR_EXCEPTION(
5799  rangeMap->getComm().getRawPtr() != comm.getRawPtr(),
5800  std::invalid_argument,
5801  "The specified range Map's communicator (rangeMap->getComm())"
5802  "differs from row Map's communicator");
5803 
5804  // Setup
5805  const int myRank = comm->getRank();
5806  const int numProc = comm->getSize();
5807  std::string filename = filename_prefix + std::to_string(myRank) + filename_suffix;
5808 
5809  // Bounds check the writing limits
5810  int rank_limit = std::min(std::max(ranksToReadAtOnce,1),numProc);
5811 
5812  // Data structures for constructor
5813  ArrayRCP<size_t> numEntriesPerRow;
5814  ArrayRCP<size_t> rowPtr;
5815  ArrayRCP<global_ordinal_type> colInd;
5816  ArrayRCP<scalar_type> values;
5817  std::ostringstream errMsg;
5818 
5820  // Start the reading of the banners to get
5821  // local row / nnz counts and then read the
5822  // data. We'll pack everything into big ol'
5823  // rowptr/colind/values ArrayRCPs
5824  bool success = true;
5825  int bannerIsCorrect = 1, readSuccess = 1;
5826  LO numRows, numCols, numNonzeros;
5827  for(int base_rank = 0; base_rank < numProc; base_rank += rank_limit) {
5828  int stop = std::min(base_rank+rank_limit,numProc);
5829 
5830  // Is my rank in this batch?
5831  if(base_rank <= myRank && myRank < stop) {
5832  // My turn to read
5833  std::ifstream in(filename);
5834  using Teuchos::MatrixMarket::Banner;
5835  size_t lineNumber = 1;
5836  RCP<const Banner> pBanner;
5837  try {
5838  pBanner = readBanner (in, lineNumber, tolerant, debug);
5839  }
5840  catch (std::exception& e) {
5841  errMsg << "Attempt to read the Matrix Market file's Banner line "
5842  "threw an exception: " << e.what();
5843  bannerIsCorrect = 0;
5844  }
5845  if (bannerIsCorrect) {
5846  // Validate the Banner for the case of a sparse matrix.
5847  // We validate on Proc 0, since it reads the Banner.
5848 
5849  // In intolerant mode, the matrix type must be "coordinate".
5850  if (! tolerant && pBanner->matrixType() != "coordinate") {
5851  bannerIsCorrect = 0;
5852  errMsg << "The Matrix Market input file must contain a "
5853  "\"coordinate\"-format sparse matrix in order to create a "
5854  "Tpetra::CrsMatrix object from it, but the file's matrix "
5855  "type is \"" << pBanner->matrixType() << "\" instead.";
5856  }
5857  // In tolerant mode, we allow the matrix type to be
5858  // anything other than "array" (which would mean that
5859  // the file contains a dense matrix).
5860  if (tolerant && pBanner->matrixType() == "array") {
5861  bannerIsCorrect = 0;
5862  errMsg << "Matrix Market file must contain a \"coordinate\"-"
5863  "format sparse matrix in order to create a Tpetra::CrsMatrix "
5864  "object from it, but the file's matrix type is \"array\" "
5865  "instead. That probably means the file contains dense matrix "
5866  "data.";
5867  }
5868  }
5869 
5870  // Unpacked coordinate matrix dimensions
5871  using Teuchos::MatrixMarket::readCoordinateDimensions;
5872  success = readCoordinateDimensions (in, numRows, numCols,
5873  numNonzeros, lineNumber,
5874  tolerant);
5875 
5876  // Sanity checking of headers
5877  TEUCHOS_TEST_FOR_EXCEPTION(numRows != (LO)rowMap->getLocalNumElements(), std::invalid_argument,
5878  "# rows in file does not match rowmap.");
5879  TEUCHOS_TEST_FOR_EXCEPTION(!colMap.is_null() && numCols != (LO)colMap->getLocalNumElements(), std::invalid_argument,
5880  "# rows in file does not match colmap.");
5881 
5882 
5883  // Read the data
5884  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,global_ordinal_type> raw_adder_type;
5885  bool tolerant_required = true;
5886  Teuchos::RCP<raw_adder_type> pRaw =
5887  Teuchos::rcp (new raw_adder_type (numRows,numCols,numNonzeros,tolerant_required,debug));
5888  RCP<adder_type> pAdder = Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
5889 
5890  if (debug) {
5891  std::cerr << "-- Reading matrix data" << std::endl;
5892  }
5893 
5894  try {
5895  // Reader for "coordinate" format sparse matrix data.
5896  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
5897  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
5898  reader_type reader (pAdder);
5899 
5900  // Read the sparse matrix entries.
5901  std::pair<bool, std::vector<size_t> > results = reader.read (in, lineNumber, tolerant_required, debug);
5902 
5903 
5904  readSuccess = results.first ? 1 : 0;
5905  }
5906  catch (std::exception& e) {
5907  readSuccess = 0;
5908  errMsg << e.what();
5909  }
5910 
5912  // Create the CSR Arrays
5913  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,global_ordinal_type> element_type;
5914 
5915  // Additively merge duplicate matrix entries.
5916  pAdder->getAdder()->merge ();
5917 
5918  // Get a temporary const view of the merged matrix entries.
5919  const std::vector<element_type>& entries = pAdder->getAdder()->getEntries();
5920 
5921  // Number of matrix entries (after merging).
5922  const size_t numEntries = (size_t)entries.size();
5923 
5924  if (debug) {
5925  std::cerr << "----- Proc "<<myRank<<": Matrix has numRows=" << numRows
5926  << " rows and numEntries=" << numEntries
5927  << " entries." << std::endl;
5928  }
5929 
5930 
5931  // Make space for the CSR matrix data. Converting to
5932  // CSR is easier if we fill numEntriesPerRow with zeros
5933  // at first.
5934  numEntriesPerRow = arcp<size_t> (numRows);
5935  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
5936  rowPtr = arcp<size_t> (numRows+1);
5937  std::fill (rowPtr.begin(), rowPtr.end(), 0);
5938  colInd = arcp<global_ordinal_type> (numEntries);
5939  values = arcp<scalar_type> (numEntries);
5940 
5941  // Convert from array-of-structs coordinate format to CSR
5942  // (compressed sparse row) format.
5943  global_ordinal_type l_prvRow = 0;
5944  size_t curPos = 0;
5945  LO INVALID = Teuchos::OrdinalTraits<LO>::invalid();
5946  rowPtr[0] = 0;
5947  LO indexBase = rowMap->getIndexBase();
5948  for (curPos = 0; curPos < numEntries; ++curPos) {
5949  const element_type& curEntry = entries[curPos];
5950  const global_ordinal_type curRow = curEntry.rowIndex() + indexBase;
5951  LO l_curRow = rowMap->getLocalElement(curRow);
5952 
5953 
5954  TEUCHOS_TEST_FOR_EXCEPTION(l_curRow == INVALID,std::logic_error,
5955  "Current global row "<< curRow << " is invalid.");
5956 
5957  TEUCHOS_TEST_FOR_EXCEPTION(l_curRow < l_prvRow, std::logic_error,
5958  "Row indices are out of order, even though they are supposed "
5959  "to be sorted. curRow = " << l_curRow << ", prvRow = "
5960  << l_prvRow << ", at curPos = " << curPos << ". Please report "
5961  "this bug to the Tpetra developers.");
5962  if (l_curRow > l_prvRow) {
5963  for (LO r = l_prvRow+1; r <= l_curRow; ++r) {
5964  rowPtr[r] = curPos;
5965  }
5966  l_prvRow = l_curRow;
5967  }
5968  numEntriesPerRow[l_curRow]++;
5969  colInd[curPos] = curEntry.colIndex() + indexBase;
5970  values[curPos] = curEntry.value();
5971 
5972  }
5973  // rowPtr has one more entry than numEntriesPerRow. The
5974  // last entry of rowPtr is the number of entries in
5975  // colInd and values.
5976  rowPtr[numRows] = numEntries;
5977 
5978  }// end base_rank <= myRank < stop
5979 
5980  // Barrier between batches to keep the filesystem happy
5981  comm->barrier();
5982 
5983  }//end outer rank loop
5984 
5985 
5986  // Call the matrix constructor and fill. This isn't particularly efficient
5987  RCP<sparse_matrix_type> A;
5988  if(colMap.is_null()) {
5989  A=rcp(new sparse_matrix_type(rowMap,numEntriesPerRow()));
5990  for(size_t i=0; i<rowMap->getLocalNumElements(); i++) {
5991  GO g_row = rowMap->getGlobalElement(i);
5992  size_t start = rowPtr[i];
5993  size_t size = rowPtr[i+1] - rowPtr[i];
5994  if(size>0) {
5995  A->insertGlobalValues(g_row,size,&values[start],&colInd[start]);
5996  }
5997  }
5998  }
5999  else {
6000  throw std::runtime_error("Reading with a column map is not yet implemented");
6001  }
6002  RCP<const map_type> myDomainMap = domainMap.is_null() ? rowMap : domainMap;
6003  RCP<const map_type> myRangeMap = rangeMap.is_null() ? rowMap : rangeMap;
6004 
6005  A->fillComplete(myDomainMap,myRangeMap);
6006 
6007  if(!readSuccess)
6008  success = false;
6009  TEUCHOS_TEST_FOR_EXCEPTION(success == false, std::runtime_error,
6010  "Read failed.");
6011 
6012  return A;
6013  }// end readSparsePerRank
6014 
6015 
6016  }; // class Reader
6017 
6046  template<class SparseMatrixType>
6047  class Writer {
6048  public:
6050  typedef SparseMatrixType sparse_matrix_type;
6051  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
6052 
6054  typedef typename SparseMatrixType::scalar_type scalar_type;
6056  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
6062  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
6064  typedef typename SparseMatrixType::node_type node_type;
6065 
6067  typedef MultiVector<scalar_type,
6075 
6078 
6110  static void
6111  writeSparseFile (const std::string& filename,
6112  const sparse_matrix_type& matrix,
6113  const std::string& matrixName,
6114  const std::string& matrixDescription,
6115  const bool debug=false)
6116  {
6117  Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
6118  TEUCHOS_TEST_FOR_EXCEPTION
6119  (comm.is_null (), std::invalid_argument,
6120  "The input matrix's communicator (Teuchos::Comm object) is null.");
6121  const int myRank = comm->getRank ();
6122  std::ofstream out;
6123 
6124  // Only open the file on Rank 0.
6125  if (myRank == 0) {
6126  out.open (filename.c_str ());
6127  }
6128  writeSparse (out, matrix, matrixName, matrixDescription, debug);
6129  // We can rely on the destructor of the output stream to close
6130  // the file on scope exit, even if writeSparse() throws an
6131  // exception.
6132  }
6133 
6135  static void
6136  writeSparseFile (const std::string& filename,
6137  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6138  const std::string& matrixName,
6139  const std::string& matrixDescription,
6140  const bool debug=false)
6141  {
6142  TEUCHOS_TEST_FOR_EXCEPTION
6143  (pMatrix.is_null (), std::invalid_argument,
6144  "The input matrix is null.");
6145  writeSparseFile (filename, *pMatrix, matrixName,
6146  matrixDescription, debug);
6147  }
6148 
6168  static void
6169  writeSparseFile (const std::string& filename,
6170  const sparse_matrix_type& matrix,
6171  const bool debug=false)
6172  {
6173  writeSparseFile (filename, matrix, "", "", debug);
6174  }
6175 
6177  static void
6178  writeSparseFile (const std::string& filename,
6179  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6180  const bool debug=false)
6181  {
6182  writeSparseFile (filename, *pMatrix, "", "", debug);
6183  }
6184 
6215  static void
6216  writeSparse (std::ostream& out,
6217  const sparse_matrix_type& matrix,
6218  const std::string& matrixName,
6219  const std::string& matrixDescription,
6220  const bool debug=false)
6221  {
6222  using Teuchos::ArrayView;
6223  using Teuchos::Comm;
6224  using Teuchos::FancyOStream;
6225  using Teuchos::getFancyOStream;
6226  using Teuchos::null;
6227  using Teuchos::RCP;
6228  using Teuchos::rcpFromRef;
6229  using std::cerr;
6230  using std::endl;
6231  using ST = scalar_type;
6232  using LO = local_ordinal_type;
6233  using GO = global_ordinal_type;
6234  using STS = typename Teuchos::ScalarTraits<ST>;
6235 
6236  // Make the output stream write floating-point numbers in
6237  // scientific notation. It will politely put the output
6238  // stream back to its state on input, when this scope
6239  // terminates.
6240  Teuchos::SetScientific<ST> sci (out);
6241 
6242  // Get the matrix's communicator.
6243  RCP<const Comm<int> > comm = matrix.getComm ();
6244  TEUCHOS_TEST_FOR_EXCEPTION(
6245  comm.is_null (), std::invalid_argument,
6246  "The input matrix's communicator (Teuchos::Comm object) is null.");
6247  const int myRank = comm->getRank ();
6248 
6249  // Optionally, make a stream for debugging output.
6250  RCP<FancyOStream> err =
6251  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6252  if (debug) {
6253  std::ostringstream os;
6254  os << myRank << ": writeSparse" << endl;
6255  *err << os.str ();
6256  comm->barrier ();
6257  os << "-- " << myRank << ": past barrier" << endl;
6258  *err << os.str ();
6259  }
6260 
6261  // Whether to print debugging output to stderr.
6262  const bool debugPrint = debug && myRank == 0;
6263 
6264  RCP<const map_type> rowMap = matrix.getRowMap ();
6265  RCP<const map_type> colMap = matrix.getColMap ();
6266  RCP<const map_type> domainMap = matrix.getDomainMap ();
6267  RCP<const map_type> rangeMap = matrix.getRangeMap ();
6268 
6269  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6270  const global_size_t numCols = domainMap->getGlobalNumElements ();
6271 
6272  if (debug && myRank == 0) {
6273  std::ostringstream os;
6274  os << "-- Input sparse matrix is:"
6275  << "---- " << numRows << " x " << numCols << endl
6276  << "---- "
6277  << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
6278  << " indexed." << endl
6279  << "---- Its row map has " << rowMap->getGlobalNumElements ()
6280  << " elements." << endl
6281  << "---- Its col map has " << colMap->getGlobalNumElements ()
6282  << " elements." << endl;
6283  *err << os.str ();
6284  }
6285  // Make the "gather" row map, where Proc 0 owns all rows and
6286  // the other procs own no rows.
6287  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6288  if (debug) {
6289  std::ostringstream os;
6290  os << "-- " << myRank << ": making gatherRowMap" << endl;
6291  *err << os.str ();
6292  }
6293  RCP<const map_type> gatherRowMap =
6294  Details::computeGatherMap (rowMap, err, debug);
6295 
6296  // Since the matrix may in general be non-square, we need to
6297  // make a column map as well. In this case, the column map
6298  // contains all the columns of the original matrix, because we
6299  // are gathering the whole matrix onto Proc 0. We call
6300  // computeGatherMap to preserve the original order of column
6301  // indices over all the processes.
6302  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6303  RCP<const map_type> gatherColMap =
6304  Details::computeGatherMap (colMap, err, debug);
6305 
6306  // Current map is the source map, gather map is the target map.
6307  typedef Import<LO, GO, node_type> import_type;
6308  import_type importer (rowMap, gatherRowMap);
6309 
6310  // Create a new CrsMatrix to hold the result of the import.
6311  // The constructor needs a column map as well as a row map,
6312  // for the case that the matrix is not square.
6313  RCP<sparse_matrix_type> newMatrix =
6314  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
6315  static_cast<size_t> (0)));
6316  // Import the sparse matrix onto Proc 0.
6317  newMatrix->doImport (matrix, importer, INSERT);
6318 
6319  // fillComplete() needs the domain and range maps for the case
6320  // that the matrix is not square.
6321  {
6322  RCP<const map_type> gatherDomainMap =
6323  rcp (new map_type (numCols, localNumCols,
6324  domainMap->getIndexBase (),
6325  comm));
6326  RCP<const map_type> gatherRangeMap =
6327  rcp (new map_type (numRows, localNumRows,
6328  rangeMap->getIndexBase (),
6329  comm));
6330  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
6331  }
6332 
6333  if (debugPrint) {
6334  cerr << "-- Output sparse matrix is:"
6335  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
6336  << " x "
6337  << newMatrix->getDomainMap ()->getGlobalNumElements ()
6338  << " with "
6339  << newMatrix->getGlobalNumEntries () << " entries;" << endl
6340  << "---- "
6341  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
6342  << " indexed." << endl
6343  << "---- Its row map has "
6344  << newMatrix->getRowMap ()->getGlobalNumElements ()
6345  << " elements, with index base "
6346  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
6347  << "---- Its col map has "
6348  << newMatrix->getColMap ()->getGlobalNumElements ()
6349  << " elements, with index base "
6350  << newMatrix->getColMap ()->getIndexBase () << "." << endl
6351  << "---- Element count of output matrix's column Map may differ "
6352  << "from that of the input matrix's column Map, if some columns "
6353  << "of the matrix contain no entries." << endl;
6354  }
6355 
6356  //
6357  // Print the metadata and the matrix entries on Rank 0.
6358  //
6359  if (myRank == 0) {
6360  // Print the Matrix Market banner line. CrsMatrix stores
6361  // data nonsymmetrically ("general"). This implies that
6362  // readSparse() on a symmetrically stored input file,
6363  // followed by writeSparse() on the resulting sparse matrix,
6364  // will result in an output file with a different banner
6365  // line than the original input file.
6366  out << "%%MatrixMarket matrix coordinate "
6367  << (STS::isComplex ? "complex" : "real")
6368  << " general" << endl;
6369 
6370  // Print comments (the matrix name and / or description).
6371  if (matrixName != "") {
6372  printAsComment (out, matrixName);
6373  }
6374  if (matrixDescription != "") {
6375  printAsComment (out, matrixDescription);
6376  }
6377 
6378  // Print the Matrix Market header (# rows, # columns, #
6379  // nonzeros). Use the range resp. domain map for the number
6380  // of rows resp. columns, since Tpetra::CrsMatrix uses the
6381  // column map for the number of columns. That only
6382  // corresponds to the "linear-algebraic" number of columns
6383  // when the column map is uniquely owned (a.k.a. one-to-one),
6384  // which only happens if the matrix is (block) diagonal.
6385  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
6386  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
6387  << newMatrix->getGlobalNumEntries () << endl;
6388 
6389  // The Matrix Market format expects one-based row and column
6390  // indices. We'll convert the indices on output from
6391  // whatever index base they use to one-based indices.
6392  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6393  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
6394  //
6395  // Print the entries of the matrix.
6396  //
6397  // newMatrix can never be globally indexed, since we called
6398  // fillComplete() on it. We include code for both cases
6399  // (globally or locally indexed) just in case that ever
6400  // changes.
6401  if (newMatrix->isGloballyIndexed()) {
6402  // We know that the "gather" row Map is contiguous, so we
6403  // don't need to get the list of GIDs.
6404  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6405  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6406  for (GO globalRowIndex = minAllGlobalIndex;
6407  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6408  ++globalRowIndex) {
6409  typename sparse_matrix_type::global_inds_host_view_type ind;
6410  typename sparse_matrix_type::values_host_view_type val;
6411  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6412  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6413  const GO globalColIndex = ind(ii);
6414  // Convert row and column indices to 1-based.
6415  // This works because the global index type is signed.
6416  out << (globalRowIndex + 1 - rowIndexBase) << " "
6417  << (globalColIndex + 1 - colIndexBase) << " ";
6418  if (STS::isComplex) {
6419  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6420  } else {
6421  out << val(ii);
6422  }
6423  out << endl;
6424  } // For each entry in the current row
6425  } // For each row of the "gather" matrix
6426  }
6427  else { // newMatrix is locally indexed
6428  using OTG = Teuchos::OrdinalTraits<GO>;
6429  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6430  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6431  ++localRowIndex) {
6432  // Convert from local to global row index.
6433  const GO globalRowIndex =
6434  gatherRowMap->getGlobalElement (localRowIndex);
6435  TEUCHOS_TEST_FOR_EXCEPTION(
6436  globalRowIndex == OTG::invalid(), std::logic_error,
6437  "Failed to convert the supposed local row index "
6438  << localRowIndex << " into a global row index. "
6439  "Please report this bug to the Tpetra developers.");
6440  typename sparse_matrix_type::local_inds_host_view_type ind;
6441  typename sparse_matrix_type::values_host_view_type val;
6442  newMatrix->getLocalRowView (localRowIndex, ind, val);
6443  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6444  // Convert the column index from local to global.
6445  const GO globalColIndex =
6446  newMatrix->getColMap()->getGlobalElement (ind(ii));
6447  TEUCHOS_TEST_FOR_EXCEPTION(
6448  globalColIndex == OTG::invalid(), std::logic_error,
6449  "On local row " << localRowIndex << " of the sparse matrix: "
6450  "Failed to convert the supposed local column index "
6451  << ind(ii) << " into a global column index. Please report "
6452  "this bug to the Tpetra developers.");
6453  // Convert row and column indices to 1-based.
6454  // This works because the global index type is signed.
6455  out << (globalRowIndex + 1 - rowIndexBase) << " "
6456  << (globalColIndex + 1 - colIndexBase) << " ";
6457  if (STS::isComplex) {
6458  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6459  } else {
6460  out << val(ii);
6461  }
6462  out << endl;
6463  } // For each entry in the current row
6464  } // For each row of the "gather" matrix
6465  } // Whether the "gather" matrix is locally or globally indexed
6466  } // If my process' rank is 0
6467  }
6468 
6470  static void
6471  writeSparse (std::ostream& out,
6472  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6473  const std::string& matrixName,
6474  const std::string& matrixDescription,
6475  const bool debug=false)
6476  {
6477  TEUCHOS_TEST_FOR_EXCEPTION
6478  (pMatrix.is_null (), std::invalid_argument,
6479  "The input matrix is null.");
6480  writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6481  }
6482 
6513  static void
6514  writeSparseGraph (std::ostream& out,
6515  const crs_graph_type& graph,
6516  const std::string& graphName,
6517  const std::string& graphDescription,
6518  const bool debug=false)
6519  {
6520  using Teuchos::ArrayView;
6521  using Teuchos::Comm;
6522  using Teuchos::FancyOStream;
6523  using Teuchos::getFancyOStream;
6524  using Teuchos::null;
6525  using Teuchos::RCP;
6526  using Teuchos::rcpFromRef;
6527  using std::cerr;
6528  using std::endl;
6529  typedef local_ordinal_type LO;
6530  typedef global_ordinal_type GO;
6531 
6532  // Get the graph's communicator. Processes on which the
6533  // graph's Map or communicator is null don't participate in
6534  // this operation. This function shouldn't even be called on
6535  // those processes.
6536  auto rowMap = graph.getRowMap ();
6537  if (rowMap.is_null ()) {
6538  return;
6539  }
6540  auto comm = rowMap->getComm ();
6541  if (comm.is_null ()) {
6542  return;
6543  }
6544  const int myRank = comm->getRank ();
6545 
6546  // Optionally, make a stream for debugging output.
6547  RCP<FancyOStream> err =
6548  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6549  if (debug) {
6550  std::ostringstream os;
6551  os << myRank << ": writeSparseGraph" << endl;
6552  *err << os.str ();
6553  comm->barrier ();
6554  os << "-- " << myRank << ": past barrier" << endl;
6555  *err << os.str ();
6556  }
6557 
6558  // Whether to print debugging output to stderr.
6559  const bool debugPrint = debug && myRank == 0;
6560 
6561  // We've already gotten the rowMap above.
6562  auto colMap = graph.getColMap ();
6563  auto domainMap = graph.getDomainMap ();
6564  auto rangeMap = graph.getRangeMap ();
6565 
6566  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6567  const global_size_t numCols = domainMap->getGlobalNumElements ();
6568 
6569  if (debug && myRank == 0) {
6570  std::ostringstream os;
6571  os << "-- Input sparse graph is:"
6572  << "---- " << numRows << " x " << numCols << " with "
6573  << graph.getGlobalNumEntries () << " entries;" << endl
6574  << "---- "
6575  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6576  << " indexed." << endl
6577  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6578  << " elements." << endl
6579  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6580  << " elements." << endl;
6581  *err << os.str ();
6582  }
6583  // Make the "gather" row map, where Proc 0 owns all rows and
6584  // the other procs own no rows.
6585  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6586  if (debug) {
6587  std::ostringstream os;
6588  os << "-- " << myRank << ": making gatherRowMap" << endl;
6589  *err << os.str ();
6590  }
6591  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6592 
6593  // Since the graph may in general be non-square, we need to
6594  // make a column map as well. In this case, the column map
6595  // contains all the columns of the original graph, because we
6596  // are gathering the whole graph onto Proc 0. We call
6597  // computeGatherMap to preserve the original order of column
6598  // indices over all the processes.
6599  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6600  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6601 
6602  // Current map is the source map, gather map is the target map.
6603  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6604 
6605  // Create a new CrsGraph to hold the result of the import.
6606  // The constructor needs a column map as well as a row map,
6607  // for the case that the graph is not square.
6608  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6609  static_cast<size_t> (0));
6610  // Import the sparse graph onto Proc 0.
6611  newGraph.doImport (graph, importer, INSERT);
6612 
6613  // fillComplete() needs the domain and range maps for the case
6614  // that the graph is not square.
6615  {
6616  RCP<const map_type> gatherDomainMap =
6617  rcp (new map_type (numCols, localNumCols,
6618  domainMap->getIndexBase (),
6619  comm));
6620  RCP<const map_type> gatherRangeMap =
6621  rcp (new map_type (numRows, localNumRows,
6622  rangeMap->getIndexBase (),
6623  comm));
6624  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6625  }
6626 
6627  if (debugPrint) {
6628  cerr << "-- Output sparse graph is:"
6629  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6630  << " x "
6631  << newGraph.getDomainMap ()->getGlobalNumElements ()
6632  << " with "
6633  << newGraph.getGlobalNumEntries () << " entries;" << endl
6634  << "---- "
6635  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6636  << " indexed." << endl
6637  << "---- Its row map has "
6638  << newGraph.getRowMap ()->getGlobalNumElements ()
6639  << " elements, with index base "
6640  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6641  << "---- Its col map has "
6642  << newGraph.getColMap ()->getGlobalNumElements ()
6643  << " elements, with index base "
6644  << newGraph.getColMap ()->getIndexBase () << "." << endl
6645  << "---- Element count of output graph's column Map may differ "
6646  << "from that of the input matrix's column Map, if some columns "
6647  << "of the matrix contain no entries." << endl;
6648  }
6649 
6650  //
6651  // Print the metadata and the graph entries on Process 0 of
6652  // the graph's communicator.
6653  //
6654  if (myRank == 0) {
6655  // Print the Matrix Market banner line. CrsGraph stores
6656  // data nonsymmetrically ("general"). This implies that
6657  // readSparseGraph() on a symmetrically stored input file,
6658  // followed by writeSparseGraph() on the resulting sparse
6659  // graph, will result in an output file with a different
6660  // banner line than the original input file.
6661  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6662 
6663  // Print comments (the graph name and / or description).
6664  if (graphName != "") {
6665  printAsComment (out, graphName);
6666  }
6667  if (graphDescription != "") {
6668  printAsComment (out, graphDescription);
6669  }
6670 
6671  // Print the Matrix Market header (# rows, # columns, #
6672  // stored entries). Use the range resp. domain map for the
6673  // number of rows resp. columns, since Tpetra::CrsGraph uses
6674  // the column map for the number of columns. That only
6675  // corresponds to the "linear-algebraic" number of columns
6676  // when the column map is uniquely owned
6677  // (a.k.a. one-to-one), which only happens if the graph is
6678  // block diagonal (one block per process).
6679  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6680  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6681  << newGraph.getGlobalNumEntries () << endl;
6682 
6683  // The Matrix Market format expects one-based row and column
6684  // indices. We'll convert the indices on output from
6685  // whatever index base they use to one-based indices.
6686  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6687  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6688  //
6689  // Print the entries of the graph.
6690  //
6691  // newGraph can never be globally indexed, since we called
6692  // fillComplete() on it. We include code for both cases
6693  // (globally or locally indexed) just in case that ever
6694  // changes.
6695  if (newGraph.isGloballyIndexed ()) {
6696  // We know that the "gather" row Map is contiguous, so we
6697  // don't need to get the list of GIDs.
6698  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6699  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6700  for (GO globalRowIndex = minAllGlobalIndex;
6701  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6702  ++globalRowIndex) {
6703  typename crs_graph_type::global_inds_host_view_type ind;
6704  newGraph.getGlobalRowView (globalRowIndex, ind);
6705  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6706  const GO globalColIndex = ind(ii);
6707  // Convert row and column indices to 1-based.
6708  // This works because the global index type is signed.
6709  out << (globalRowIndex + 1 - rowIndexBase) << " "
6710  << (globalColIndex + 1 - colIndexBase) << " ";
6711  out << endl;
6712  } // For each entry in the current row
6713  } // For each row of the "gather" graph
6714  }
6715  else { // newGraph is locally indexed
6716  typedef Teuchos::OrdinalTraits<GO> OTG;
6717  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6718  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6719  ++localRowIndex) {
6720  // Convert from local to global row index.
6721  const GO globalRowIndex =
6722  gatherRowMap->getGlobalElement (localRowIndex);
6723  TEUCHOS_TEST_FOR_EXCEPTION
6724  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6725  "to convert the supposed local row index " << localRowIndex <<
6726  " into a global row index. Please report this bug to the "
6727  "Tpetra developers.");
6728  typename crs_graph_type::local_inds_host_view_type ind;
6729  newGraph.getLocalRowView (localRowIndex, ind);
6730  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6731  // Convert the column index from local to global.
6732  const GO globalColIndex =
6733  newGraph.getColMap ()->getGlobalElement (ind(ii));
6734  TEUCHOS_TEST_FOR_EXCEPTION(
6735  globalColIndex == OTG::invalid(), std::logic_error,
6736  "On local row " << localRowIndex << " of the sparse graph: "
6737  "Failed to convert the supposed local column index "
6738  << ind(ii) << " into a global column index. Please report "
6739  "this bug to the Tpetra developers.");
6740  // Convert row and column indices to 1-based.
6741  // This works because the global index type is signed.
6742  out << (globalRowIndex + 1 - rowIndexBase) << " "
6743  << (globalColIndex + 1 - colIndexBase) << " ";
6744  out << endl;
6745  } // For each entry in the current row
6746  } // For each row of the "gather" graph
6747  } // Whether the "gather" graph is locally or globally indexed
6748  } // If my process' rank is 0
6749  }
6750 
6756  static void
6757  writeSparseGraph (std::ostream& out,
6758  const crs_graph_type& graph,
6759  const bool debug=false)
6760  {
6761  writeSparseGraph (out, graph, "", "", debug);
6762  }
6763 
6798  static void
6799  writeSparseGraphFile (const std::string& filename,
6800  const crs_graph_type& graph,
6801  const std::string& graphName,
6802  const std::string& graphDescription,
6803  const bool debug=false)
6804  {
6805  auto comm = graph.getComm ();
6806  if (comm.is_null ()) {
6807  // Processes on which the communicator is null shouldn't
6808  // even call this function. The convention is that
6809  // processes on which the object's communicator is null do
6810  // not participate in collective operations involving the
6811  // object.
6812  return;
6813  }
6814  const int myRank = comm->getRank ();
6815  std::ofstream out;
6816 
6817  // Only open the file on Process 0.
6818  if (myRank == 0) {
6819  out.open (filename.c_str ());
6820  }
6821  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6822  // We can rely on the destructor of the output stream to close
6823  // the file on scope exit, even if writeSparseGraph() throws
6824  // an exception.
6825  }
6826 
6831  static void
6832  writeSparseGraphFile (const std::string& filename,
6833  const crs_graph_type& graph,
6834  const bool debug=false)
6835  {
6836  writeSparseGraphFile (filename, graph, "", "", debug);
6837  }
6838 
6847  static void
6848  writeSparseGraphFile (const std::string& filename,
6849  const Teuchos::RCP<const crs_graph_type>& pGraph,
6850  const std::string& graphName,
6851  const std::string& graphDescription,
6852  const bool debug=false)
6853  {
6854  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6855  }
6856 
6866  static void
6867  writeSparseGraphFile (const std::string& filename,
6868  const Teuchos::RCP<const crs_graph_type>& pGraph,
6869  const bool debug=false)
6870  {
6871  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6872  }
6873 
6896  static void
6897  writeSparse (std::ostream& out,
6898  const sparse_matrix_type& matrix,
6899  const bool debug=false)
6900  {
6901  writeSparse (out, matrix, "", "", debug);
6902  }
6903 
6905  static void
6906  writeSparse (std::ostream& out,
6907  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6908  const bool debug=false)
6909  {
6910  writeSparse (out, *pMatrix, "", "", debug);
6911  }
6912 
6941  static void
6942  writeDenseFile (const std::string& filename,
6943  const multivector_type& X,
6944  const std::string& matrixName,
6945  const std::string& matrixDescription,
6946  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6947  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6948  {
6949  const int myRank = X.getMap ().is_null () ? 0 :
6950  (X.getMap ()->getComm ().is_null () ? 0 :
6951  X.getMap ()->getComm ()->getRank ());
6952  std::ofstream out;
6953 
6954  if (myRank == 0) { // Only open the file on Process 0.
6955  out.open (filename.c_str());
6956  }
6957 
6958  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6959  // We can rely on the destructor of the output stream to close
6960  // the file on scope exit, even if writeDense() throws an
6961  // exception.
6962  }
6963 
6969  static void
6970  writeDenseFile (const std::string& filename,
6971  const Teuchos::RCP<const multivector_type>& X,
6972  const std::string& matrixName,
6973  const std::string& matrixDescription,
6974  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6975  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6976  {
6977  TEUCHOS_TEST_FOR_EXCEPTION(
6978  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6979  "writeDenseFile: The input MultiVector X is null.");
6980  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6981  }
6982 
6988  static void
6989  writeDenseFile (const std::string& filename,
6990  const multivector_type& X,
6991  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6992  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6993  {
6994  writeDenseFile (filename, X, "", "", err, dbg);
6995  }
6996 
7002  static void
7003  writeDenseFile (const std::string& filename,
7004  const Teuchos::RCP<const multivector_type>& X,
7005  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7006  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7007  {
7008  TEUCHOS_TEST_FOR_EXCEPTION(
7009  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7010  "writeDenseFile: The input MultiVector X is null.");
7011  writeDenseFile (filename, *X, err, dbg);
7012  }
7013 
7014 
7045  static void
7046  writeDense (std::ostream& out,
7047  const multivector_type& X,
7048  const std::string& matrixName,
7049  const std::string& matrixDescription,
7050  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7051  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7052  {
7053  using Teuchos::Comm;
7054  using Teuchos::outArg;
7055  using Teuchos::REDUCE_MAX;
7056  using Teuchos::reduceAll;
7057  using Teuchos::RCP;
7058  using std::endl;
7059 
7060  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7061  Teuchos::null : X.getMap ()->getComm ();
7062  const int myRank = comm.is_null () ? 0 : comm->getRank ();
7063 
7064  // If the caller provides a nonnull debug output stream, we
7065  // print debugging output to it. This is a local thing; we
7066  // don't have to check across processes.
7067  const bool debug = ! dbg.is_null ();
7068  if (debug) {
7069  dbg->pushTab ();
7070  std::ostringstream os;
7071  os << myRank << ": writeDense" << endl;
7072  *dbg << os.str ();
7073  dbg->pushTab ();
7074  }
7075  // Print the Matrix Market header.
7076  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
7077 
7078  // Print each column one at a time. This is a (perhaps)
7079  // temporary fix for Bug 6288.
7080  const size_t numVecs = X.getNumVectors ();
7081  for (size_t j = 0; j < numVecs; ++j) {
7082  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
7083  }
7084 
7085  if (debug) {
7086  dbg->popTab ();
7087  std::ostringstream os;
7088  os << myRank << ": writeDense: Done" << endl;
7089  *dbg << os.str ();
7090  dbg->popTab ();
7091  }
7092  }
7093 
7094  private:
7095 
7121  static void
7122  writeDenseHeader (std::ostream& out,
7123  const multivector_type& X,
7124  const std::string& matrixName,
7125  const std::string& matrixDescription,
7126  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7127  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7128  {
7129  using Teuchos::Comm;
7130  using Teuchos::outArg;
7131  using Teuchos::RCP;
7132  using Teuchos::REDUCE_MAX;
7133  using Teuchos::reduceAll;
7134  using std::endl;
7135  typedef Teuchos::ScalarTraits<scalar_type> STS;
7136  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
7137 
7138  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
7139  Teuchos::null : X.getMap ()->getComm ();
7140  const int myRank = comm.is_null () ? 0 : comm->getRank ();
7141  int lclErr = 0; // whether this MPI process has seen an error
7142  int gblErr = 0; // whether we know if some MPI process has seen an error
7143 
7144  // If the caller provides a nonnull debug output stream, we
7145  // print debugging output to it. This is a local thing; we
7146  // don't have to check across processes.
7147  const bool debug = ! dbg.is_null ();
7148 
7149  if (debug) {
7150  dbg->pushTab ();
7151  std::ostringstream os;
7152  os << myRank << ": writeDenseHeader" << endl;
7153  *dbg << os.str ();
7154  dbg->pushTab ();
7155  }
7156 
7157  //
7158  // Process 0: Write the MatrixMarket header.
7159  //
7160  if (myRank == 0) {
7161  try {
7162  // Print the Matrix Market header. MultiVector stores data
7163  // nonsymmetrically, hence "general" in the banner line.
7164  // Print first to a temporary string output stream, and then
7165  // write it to the main output stream, so that at least the
7166  // header output has transactional semantics. We can't
7167  // guarantee transactional semantics for the whole output,
7168  // since that would not be memory scalable. (This could be
7169  // done in the file system by using a temporary file; we
7170  // don't do this, but users could.)
7171  std::ostringstream hdr;
7172  {
7173  std::string dataType;
7174  if (STS::isComplex) {
7175  dataType = "complex";
7176  } else if (STS::isOrdinal) {
7177  dataType = "integer";
7178  } else {
7179  dataType = "real";
7180  }
7181  hdr << "%%MatrixMarket matrix array " << dataType << " general"
7182  << endl;
7183  }
7184 
7185  // Print comments (the matrix name and / or description).
7186  if (matrixName != "") {
7187  printAsComment (hdr, matrixName);
7188  }
7189  if (matrixDescription != "") {
7190  printAsComment (hdr, matrixDescription);
7191  }
7192  // Print the Matrix Market dimensions header for dense matrices.
7193  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
7194 
7195  // Write the MatrixMarket header to the output stream.
7196  out << hdr.str ();
7197  } catch (std::exception& e) {
7198  if (! err.is_null ()) {
7199  *err << prefix << "While writing the Matrix Market header, "
7200  "Process 0 threw an exception: " << e.what () << endl;
7201  }
7202  lclErr = 1;
7203  }
7204  } // if I am Process 0
7205 
7206  // Establish global agreement on the error state. It wouldn't
7207  // be good for other processes to keep going, if Process 0
7208  // finds out that it can't write to the given output stream.
7209  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
7210  TEUCHOS_TEST_FOR_EXCEPTION(
7211  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
7212  "which prevented this method from completing.");
7213 
7214  if (debug) {
7215  dbg->popTab ();
7216  *dbg << myRank << ": writeDenseHeader: Done" << endl;
7217  dbg->popTab ();
7218  }
7219  }
7220 
7238  static void
7239  writeDenseColumn (std::ostream& out,
7240  const multivector_type& X,
7241  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7242  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7243  {
7244  using Teuchos::arcp;
7245  using Teuchos::Array;
7246  using Teuchos::ArrayRCP;
7247  using Teuchos::ArrayView;
7248  using Teuchos::Comm;
7249  using Teuchos::CommRequest;
7250  using Teuchos::ireceive;
7251  using Teuchos::isend;
7252  using Teuchos::outArg;
7253  using Teuchos::REDUCE_MAX;
7254  using Teuchos::reduceAll;
7255  using Teuchos::RCP;
7256  using Teuchos::TypeNameTraits;
7257  using Teuchos::wait;
7258  using std::endl;
7259  typedef Teuchos::ScalarTraits<scalar_type> STS;
7260 
7261  const Comm<int>& comm = * (X.getMap ()->getComm ());
7262  const int myRank = comm.getRank ();
7263  const int numProcs = comm.getSize ();
7264  int lclErr = 0; // whether this MPI process has seen an error
7265  int gblErr = 0; // whether we know if some MPI process has seen an error
7266 
7267  // If the caller provides a nonnull debug output stream, we
7268  // print debugging output to it. This is a local thing; we
7269  // don't have to check across processes.
7270  const bool debug = ! dbg.is_null ();
7271 
7272  if (debug) {
7273  dbg->pushTab ();
7274  std::ostringstream os;
7275  os << myRank << ": writeDenseColumn" << endl;
7276  *dbg << os.str ();
7277  dbg->pushTab ();
7278  }
7279 
7280  // Make the output stream write floating-point numbers in
7281  // scientific notation. It will politely put the output
7282  // stream back to its state on input, when this scope
7283  // terminates.
7284  Teuchos::SetScientific<scalar_type> sci (out);
7285 
7286  const size_t myNumRows = X.getLocalLength ();
7287  const size_t numCols = X.getNumVectors ();
7288  // Use a different tag for the "size" messages than for the
7289  // "data" messages, in order to help us debug any mix-ups.
7290  const int sizeTag = 1337;
7291  const int dataTag = 1338;
7292 
7293  // Process 0 pipelines nonblocking receives with file output.
7294  //
7295  // Constraints:
7296  // - Process 0 can't post a receive for another process'
7297  // actual data, until it posts and waits on the receive
7298  // from that process with the amount of data to receive.
7299  // (We could just post receives with a max data size, but
7300  // I feel uncomfortable about that.)
7301  // - The C++ standard library doesn't allow nonblocking
7302  // output to an std::ostream. (Thus, we have to start a
7303  // receive or send before starting the write, and hope
7304  // that MPI completes it in the background.)
7305  //
7306  // Process 0: Post receive-size receives from Processes 1 and 2.
7307  // Process 1: Post send-size send to Process 0.
7308  // Process 2: Post send-size send to Process 0.
7309  //
7310  // All processes: Pack my entries.
7311  //
7312  // Process 1:
7313  // - Post send-data send to Process 0.
7314  // - Wait on my send-size send to Process 0.
7315  //
7316  // Process 0:
7317  // - Print MatrixMarket header.
7318  // - Print my entries.
7319  // - Wait on receive-size receive from Process 1.
7320  // - Post receive-data receive from Process 1.
7321  //
7322  // For each process p = 1, 2, ... numProcs-1:
7323  // If I am Process 0:
7324  // - Post receive-size receive from Process p + 2
7325  // - Wait on receive-size receive from Process p + 1
7326  // - Post receive-data receive from Process p + 1
7327  // - Wait on receive-data receive from Process p
7328  // - Write data from Process p.
7329  // Else if I am Process p:
7330  // - Wait on my send-data send.
7331  // Else if I am Process p+1:
7332  // - Post send-data send to Process 0.
7333  // - Wait on my send-size send.
7334  // Else if I am Process p+2:
7335  // - Post send-size send to Process 0.
7336  //
7337  // Pipelining has three goals here:
7338  // 1. Overlap communication (the receives) with file I/O
7339  // 2. Give Process 0 a chance to prepost some receives,
7340  // before sends show up, by packing local data before
7341  // posting sends
7342  // 3. Don't post _all_ receives or _all_ sends, because that
7343  // wouldn't be memory scalable. (Just because we can't
7344  // see how much memory MPI consumes, doesn't mean that it
7345  // doesn't consume any!)
7346 
7347  // These are used on every process. sendReqSize[0] holds the
7348  // number of rows on this process, and sendReqBuf holds this
7349  // process' data. Process 0 packs into sendReqBuf, but
7350  // doesn't send; it only uses that for printing. All other
7351  // processes send both of these to Process 0.
7352  RCP<CommRequest<int> > sendReqSize, sendReqData;
7353 
7354  // These are used only on Process 0, for received data. Keep
7355  // 3 of each, and treat the arrays as circular buffers. When
7356  // receiving from Process p, the corresponding array index
7357  // here is p % 3.
7358  Array<ArrayRCP<size_t> > recvSizeBufs (3);
7359  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
7360  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7361  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7362 
7363  // Buffer for nonblocking send of the "send size."
7364  ArrayRCP<size_t> sendDataSize (1);
7365  sendDataSize[0] = myNumRows;
7366 
7367  if (myRank == 0) {
7368  if (debug) {
7369  std::ostringstream os;
7370  os << myRank << ": Post receive-size receives from "
7371  "Procs 1 and 2: tag = " << sizeTag << endl;
7372  *dbg << os.str ();
7373  }
7374  // Process 0: Post receive-size receives from Processes 1 and 2.
7375  recvSizeBufs[0].resize (1);
7376  // Set these three to an invalid value as a flag. If we
7377  // don't get these messages, then the invalid value will
7378  // remain, so we can test for it.
7379  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7380  recvSizeBufs[1].resize (1);
7381  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7382  recvSizeBufs[2].resize (1);
7383  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
7384  if (numProcs > 1) {
7385  recvSizeReqs[1] =
7386  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
7387  }
7388  if (numProcs > 2) {
7389  recvSizeReqs[2] =
7390  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
7391  }
7392  }
7393  else if (myRank == 1 || myRank == 2) {
7394  if (debug) {
7395  std::ostringstream os;
7396  os << myRank << ": Post send-size send: size = "
7397  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7398  *dbg << os.str ();
7399  }
7400  // Prime the pipeline by having Processes 1 and 2 start
7401  // their send-size sends. We don't want _all_ the processes
7402  // to start their send-size sends, because that wouldn't be
7403  // memory scalable.
7404  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7405  }
7406  else {
7407  if (debug) {
7408  std::ostringstream os;
7409  os << myRank << ": Not posting my send-size send yet" << endl;
7410  *dbg << os.str ();
7411  }
7412  }
7413 
7414  //
7415  // Pack my entries, in column-major order.
7416  //
7417  if (debug) {
7418  std::ostringstream os;
7419  os << myRank << ": Pack my entries" << endl;
7420  *dbg << os.str ();
7421  }
7422  ArrayRCP<scalar_type> sendDataBuf;
7423  try {
7424  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7425  X.get1dCopy (sendDataBuf (), myNumRows);
7426  }
7427  catch (std::exception& e) {
7428  lclErr = 1;
7429  if (! err.is_null ()) {
7430  std::ostringstream os;
7431  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7432  "entries threw an exception: " << e.what () << endl;
7433  *err << os.str ();
7434  }
7435  }
7436  if (debug) {
7437  std::ostringstream os;
7438  os << myRank << ": Done packing my entries" << endl;
7439  *dbg << os.str ();
7440  }
7441 
7442  //
7443  // Process 1: post send-data send to Process 0.
7444  //
7445  if (myRank == 1) {
7446  if (debug) {
7447  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7448  << endl;
7449  }
7450  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7451  }
7452 
7453  //
7454  // Process 0: Write my entries.
7455  //
7456  if (myRank == 0) {
7457  if (debug) {
7458  std::ostringstream os;
7459  os << myRank << ": Write my entries" << endl;
7460  *dbg << os.str ();
7461  }
7462 
7463  // Write Process 0's data to the output stream.
7464  // Matrix Market prints dense matrices in column-major order.
7465  const size_t printNumRows = myNumRows;
7466  ArrayView<const scalar_type> printData = sendDataBuf ();
7467  const size_t printStride = printNumRows;
7468  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7469  lclErr = 1;
7470  if (! err.is_null ()) {
7471  std::ostringstream os;
7472  os << "Process " << myRank << ": My MultiVector data's size "
7473  << printData.size () << " does not match my local dimensions "
7474  << printStride << " x " << numCols << "." << endl;
7475  *err << os.str ();
7476  }
7477  }
7478  else {
7479  // Matrix Market dense format wants one number per line.
7480  // It wants each complex number as two real numbers (real
7481  // resp. imaginary parts) with a space between.
7482  for (size_t col = 0; col < numCols; ++col) {
7483  for (size_t row = 0; row < printNumRows; ++row) {
7484  if (STS::isComplex) {
7485  out << STS::real (printData[row + col * printStride]) << " "
7486  << STS::imag (printData[row + col * printStride]) << endl;
7487  } else {
7488  out << printData[row + col * printStride] << endl;
7489  }
7490  }
7491  }
7492  }
7493  }
7494 
7495  if (myRank == 0) {
7496  // Wait on receive-size receive from Process 1.
7497  const int recvRank = 1;
7498  const int circBufInd = recvRank % 3;
7499  if (debug) {
7500  std::ostringstream os;
7501  os << myRank << ": Wait on receive-size receive from Process "
7502  << recvRank << endl;
7503  *dbg << os.str ();
7504  }
7505  if (numProcs > 1) {
7506  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7507 
7508  // We received the number of rows of data. (The data
7509  // come in two columns.)
7510  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7511  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7512  lclErr = 1;
7513  if (! err.is_null ()) {
7514  std::ostringstream os;
7515  os << myRank << ": Result of receive-size receive from Process "
7516  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7517  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7518  "This should never happen, and suggests that the receive never "
7519  "got posted. Please report this bug to the Tpetra developers."
7520  << endl;
7521  *err << os.str ();
7522  }
7523 
7524  // If we're going to continue after error, set the
7525  // number of rows to receive to a reasonable size. This
7526  // may cause MPI_ERR_TRUNCATE if the sending process is
7527  // sending more than 0 rows, but that's better than MPI
7528  // overflowing due to the huge positive value that is
7529  // Teuchos::OrdinalTraits<size_t>::invalid().
7530  recvNumRows = 0;
7531  }
7532 
7533  // Post receive-data receive from Process 1.
7534  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7535  if (debug) {
7536  std::ostringstream os;
7537  os << myRank << ": Post receive-data receive from Process "
7538  << recvRank << ": tag = " << dataTag << ", buffer size = "
7539  << recvDataBufs[circBufInd].size () << endl;
7540  *dbg << os.str ();
7541  }
7542  if (! recvSizeReqs[circBufInd].is_null ()) {
7543  lclErr = 1;
7544  if (! err.is_null ()) {
7545  std::ostringstream os;
7546  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7547  "null, before posting the receive-data receive from Process "
7548  << recvRank << ". This should never happen. Please report "
7549  "this bug to the Tpetra developers." << endl;
7550  *err << os.str ();
7551  }
7552  }
7553  recvDataReqs[circBufInd] =
7554  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7555  recvRank, dataTag, comm);
7556  } // numProcs > 1
7557  }
7558  else if (myRank == 1) {
7559  // Wait on my send-size send.
7560  if (debug) {
7561  std::ostringstream os;
7562  os << myRank << ": Wait on my send-size send" << endl;
7563  *dbg << os.str ();
7564  }
7565  wait<int> (comm, outArg (sendReqSize));
7566  }
7567 
7568  //
7569  // Pipeline loop
7570  //
7571  for (int p = 1; p < numProcs; ++p) {
7572  if (myRank == 0) {
7573  if (p + 2 < numProcs) {
7574  // Post receive-size receive from Process p + 2.
7575  const int recvRank = p + 2;
7576  const int circBufInd = recvRank % 3;
7577  if (debug) {
7578  std::ostringstream os;
7579  os << myRank << ": Post receive-size receive from Process "
7580  << recvRank << ": tag = " << sizeTag << endl;
7581  *dbg << os.str ();
7582  }
7583  if (! recvSizeReqs[circBufInd].is_null ()) {
7584  lclErr = 1;
7585  if (! err.is_null ()) {
7586  std::ostringstream os;
7587  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7588  << "null, for the receive-size receive from Process "
7589  << recvRank << "! This may mean that this process never "
7590  << "finished waiting for the receive from Process "
7591  << (recvRank - 3) << "." << endl;
7592  *err << os.str ();
7593  }
7594  }
7595  recvSizeReqs[circBufInd] =
7596  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7597  recvRank, sizeTag, comm);
7598  }
7599 
7600  if (p + 1 < numProcs) {
7601  const int recvRank = p + 1;
7602  const int circBufInd = recvRank % 3;
7603 
7604  // Wait on receive-size receive from Process p + 1.
7605  if (debug) {
7606  std::ostringstream os;
7607  os << myRank << ": Wait on receive-size receive from Process "
7608  << recvRank << endl;
7609  *dbg << os.str ();
7610  }
7611  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7612 
7613  // We received the number of rows of data. (The data
7614  // come in two columns.)
7615  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7616  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7617  lclErr = 1;
7618  if (! err.is_null ()) {
7619  std::ostringstream os;
7620  os << myRank << ": Result of receive-size receive from Process "
7621  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7622  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7623  "This should never happen, and suggests that the receive never "
7624  "got posted. Please report this bug to the Tpetra developers."
7625  << endl;
7626  *err << os.str ();
7627  }
7628  // If we're going to continue after error, set the
7629  // number of rows to receive to a reasonable size.
7630  // This may cause MPI_ERR_TRUNCATE if the sending
7631  // process sends more than 0 rows, but that's better
7632  // than MPI overflowing due to the huge positive value
7633  // Teuchos::OrdinalTraits<size_t>::invalid().
7634  recvNumRows = 0;
7635  }
7636 
7637  // Post receive-data receive from Process p + 1.
7638  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7639  if (debug) {
7640  std::ostringstream os;
7641  os << myRank << ": Post receive-data receive from Process "
7642  << recvRank << ": tag = " << dataTag << ", buffer size = "
7643  << recvDataBufs[circBufInd].size () << endl;
7644  *dbg << os.str ();
7645  }
7646  if (! recvDataReqs[circBufInd].is_null ()) {
7647  lclErr = 1;
7648  if (! err.is_null ()) {
7649  std::ostringstream os;
7650  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7651  << "null, for the receive-data receive from Process "
7652  << recvRank << "! This may mean that this process never "
7653  << "finished waiting for the receive from Process "
7654  << (recvRank - 3) << "." << endl;
7655  *err << os.str ();
7656  }
7657  }
7658  recvDataReqs[circBufInd] =
7659  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7660  recvRank, dataTag, comm);
7661  }
7662 
7663  // Wait on receive-data receive from Process p.
7664  const int recvRank = p;
7665  const int circBufInd = recvRank % 3;
7666  if (debug) {
7667  std::ostringstream os;
7668  os << myRank << ": Wait on receive-data receive from Process "
7669  << recvRank << endl;
7670  *dbg << os.str ();
7671  }
7672  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7673 
7674  // Write Process p's data. Number of rows lives in
7675  // recvSizeBufs[circBufInd], and the actual data live in
7676  // recvDataBufs[circBufInd]. Do this after posting receives,
7677  // in order to expose overlap of comm. with file I/O.
7678  if (debug) {
7679  std::ostringstream os;
7680  os << myRank << ": Write entries from Process " << recvRank
7681  << endl;
7682  *dbg << os.str () << endl;
7683  }
7684  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7685  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7686  lclErr = 1;
7687  if (! err.is_null ()) {
7688  std::ostringstream os;
7689  os << myRank << ": Result of receive-size receive from Process "
7690  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7691  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7692  << ". This should never happen, and suggests that its "
7693  "receive-size receive was never posted. "
7694  "Please report this bug to the Tpetra developers." << endl;
7695  *err << os.str ();
7696  }
7697  // If we're going to continue after error, set the
7698  // number of rows to print to a reasonable size.
7699  printNumRows = 0;
7700  }
7701  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7702  lclErr = 1;
7703  if (! err.is_null ()) {
7704  std::ostringstream os;
7705  os << myRank << ": Result of receive-size receive from Proc "
7706  << recvRank << " was " << printNumRows << " > 0, but "
7707  "recvDataBufs[" << circBufInd << "] is null. This should "
7708  "never happen. Please report this bug to the Tpetra "
7709  "developers." << endl;
7710  *err << os.str ();
7711  }
7712  // If we're going to continue after error, set the
7713  // number of rows to print to a reasonable size.
7714  printNumRows = 0;
7715  }
7716 
7717  // Write the received data to the output stream.
7718  // Matrix Market prints dense matrices in column-major order.
7719  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7720  const size_t printStride = printNumRows;
7721  // Matrix Market dense format wants one number per line.
7722  // It wants each complex number as two real numbers (real
7723  // resp. imaginary parts) with a space between.
7724  for (size_t col = 0; col < numCols; ++col) {
7725  for (size_t row = 0; row < printNumRows; ++row) {
7726  if (STS::isComplex) {
7727  out << STS::real (printData[row + col * printStride]) << " "
7728  << STS::imag (printData[row + col * printStride]) << endl;
7729  } else {
7730  out << printData[row + col * printStride] << endl;
7731  }
7732  }
7733  }
7734  }
7735  else if (myRank == p) { // Process p
7736  // Wait on my send-data send.
7737  if (debug) {
7738  std::ostringstream os;
7739  os << myRank << ": Wait on my send-data send" << endl;
7740  *dbg << os.str ();
7741  }
7742  wait<int> (comm, outArg (sendReqData));
7743  }
7744  else if (myRank == p + 1) { // Process p + 1
7745  // Post send-data send to Process 0.
7746  if (debug) {
7747  std::ostringstream os;
7748  os << myRank << ": Post send-data send: tag = " << dataTag
7749  << endl;
7750  *dbg << os.str ();
7751  }
7752  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7753  // Wait on my send-size send.
7754  if (debug) {
7755  std::ostringstream os;
7756  os << myRank << ": Wait on my send-size send" << endl;
7757  *dbg << os.str ();
7758  }
7759  wait<int> (comm, outArg (sendReqSize));
7760  }
7761  else if (myRank == p + 2) { // Process p + 2
7762  // Post send-size send to Process 0.
7763  if (debug) {
7764  std::ostringstream os;
7765  os << myRank << ": Post send-size send: size = "
7766  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7767  *dbg << os.str ();
7768  }
7769  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7770  }
7771  }
7772 
7773  // Establish global agreement on the error state.
7774  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7775  TEUCHOS_TEST_FOR_EXCEPTION(
7776  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7777  "experienced some kind of error and was unable to complete.");
7778 
7779  if (debug) {
7780  dbg->popTab ();
7781  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7782  dbg->popTab ();
7783  }
7784  }
7785 
7786  public:
7787 
7793  static void
7794  writeDense (std::ostream& out,
7795  const Teuchos::RCP<const multivector_type>& X,
7796  const std::string& matrixName,
7797  const std::string& matrixDescription,
7798  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7799  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7800  {
7801  TEUCHOS_TEST_FOR_EXCEPTION(
7802  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7803  "writeDense: The input MultiVector X is null.");
7804  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7805  }
7806 
7812  static void
7813  writeDense (std::ostream& out,
7814  const multivector_type& X,
7815  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7816  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7817  {
7818  writeDense (out, X, "", "", err, dbg);
7819  }
7820 
7826  static void
7827  writeDense (std::ostream& out,
7828  const Teuchos::RCP<const multivector_type>& X,
7829  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7830  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7831  {
7832  TEUCHOS_TEST_FOR_EXCEPTION(
7833  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7834  "writeDense: The input MultiVector X is null.");
7835  writeDense (out, *X, "", "", err, dbg);
7836  }
7837 
7857  static void
7858  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7859  {
7860  Teuchos::RCP<Teuchos::FancyOStream> err =
7861  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7862  writeMap (out, map, err, debug);
7863  }
7864 
7873  static void