Tpetra parallel linear algebra  Version of the Day
MatrixMarket_Tpetra.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Tpetra: Templated Linear Algebra Services Package
5 // Copyright (2008) Sandia Corporation
6 //
7 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ************************************************************************
40 // @HEADER
41 
42 #ifndef __MatrixMarket_Tpetra_hpp
43 #define __MatrixMarket_Tpetra_hpp
44 
57 #include "Tpetra_CrsMatrix.hpp"
58 #include "Tpetra_Operator.hpp"
59 #include "Tpetra_Vector.hpp"
61 #include "Teuchos_MatrixMarket_Raw_Adder.hpp"
62 #include "Teuchos_MatrixMarket_Raw_Graph_Adder.hpp"
63 #include "Teuchos_MatrixMarket_SymmetrizingAdder.hpp"
64 #include "Teuchos_MatrixMarket_SymmetrizingGraphAdder.hpp"
65 #include "Teuchos_MatrixMarket_assignScalar.hpp"
66 #include "Teuchos_MatrixMarket_Banner.hpp"
67 #include "Teuchos_MatrixMarket_CoordDataReader.hpp"
68 #include "Teuchos_SetScientific.hpp"
69 #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->getNodeElementList();
439  const size_type myNumRows = myRows.size();
440  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(myNumRows) !=
441  pRowMap->getNodeNumElements(),
442  std::logic_error,
443  "pRowMap->getNodeElementList().size() = "
444  << myNumRows
445  << " != pRowMap->getNodeNumElements() = "
446  << pRowMap->getNodeNumElements() << ". "
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->getNodeElementList().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  StaticProfile));
808 
809  // List of the global indices of my rows.
810  // They may or may not be contiguous.
811  ArrayView<const GO> myRows = pRowMap->getNodeElementList ();
812  const size_type myNumRows = myRows.size ();
813 
814  // Add this processor's matrix entries to the CrsMatrix.
815  const GO indexBase = pRowMap->getIndexBase ();
816  for (size_type i = 0; i < myNumRows; ++i) {
817  const size_type myCurPos = myRowPtr[i];
818  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
819  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
820  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
821 
822  // Modify the column indices in place to have the right index base.
823  for (size_type k = 0; k < curNumEntries; ++k) {
824  curColInd[k] += indexBase;
825  }
826  // Avoid constructing empty views of ArrayRCP objects.
827  if (curNumEntries > 0) {
828  A->insertGlobalValues (myRows[i], curColInd, curValues);
829  }
830  }
831  // We've entered in all our matrix entries, so we can delete
832  // the original data. This will save memory when we call
833  // fillComplete(), so that we never keep more than two copies
834  // of the matrix's data in memory at once.
835  myNumEntriesPerRow = null;
836  myRowPtr = null;
837  myColInd = null;
838  myValues = null;
839 
840  if (callFillComplete) {
841  A->fillComplete (pDomainMap, pRangeMap);
842  }
843  return A;
844  }
845 
851  static Teuchos::RCP<sparse_matrix_type>
852  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
853  Teuchos::ArrayRCP<size_t>& myRowPtr,
854  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
855  Teuchos::ArrayRCP<scalar_type>& myValues,
856  const Teuchos::RCP<const map_type>& pRowMap,
857  const Teuchos::RCP<const map_type>& pRangeMap,
858  const Teuchos::RCP<const map_type>& pDomainMap,
859  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
860  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams)
861  {
862  using Teuchos::ArrayView;
863  using Teuchos::null;
864  using Teuchos::RCP;
865  using Teuchos::rcp;
866  using std::cerr;
867  using std::endl;
868  // Typedef to make certain type declarations shorter.
869  typedef global_ordinal_type GO;
870 
871  // The row pointer array always has at least one entry, even
872  // if the matrix has zero rows. myNumEntriesPerRow, myColInd,
873  // and myValues would all be empty arrays in that degenerate
874  // case, but the row and domain maps would still be nonnull
875  // (though they would be trivial maps).
876  TEUCHOS_TEST_FOR_EXCEPTION(
877  myRowPtr.is_null(), std::logic_error,
878  "makeMatrix: myRowPtr array is null. "
879  "Please report this bug to the Tpetra developers.");
880  TEUCHOS_TEST_FOR_EXCEPTION(
881  pDomainMap.is_null(), std::logic_error,
882  "makeMatrix: domain map is null. "
883  "Please report this bug to the Tpetra developers.");
884  TEUCHOS_TEST_FOR_EXCEPTION(
885  pRangeMap.is_null(), std::logic_error,
886  "makeMatrix: range map is null. "
887  "Please report this bug to the Tpetra developers.");
888  TEUCHOS_TEST_FOR_EXCEPTION(
889  pRowMap.is_null(), std::logic_error,
890  "makeMatrix: row map is null. "
891  "Please report this bug to the Tpetra developers.");
892 
893  // Construct the CrsMatrix, using the row map, with the
894  // constructor specifying the number of nonzeros for each row.
895  RCP<sparse_matrix_type> A =
896  rcp (new sparse_matrix_type (pRowMap, myNumEntriesPerRow(),
897  StaticProfile, constructorParams));
898 
899  // List of the global indices of my rows.
900  // They may or may not be contiguous.
901  ArrayView<const GO> myRows = pRowMap->getNodeElementList();
902  const size_type myNumRows = myRows.size();
903 
904  // Add this processor's matrix entries to the CrsMatrix.
905  const GO indexBase = pRowMap->getIndexBase ();
906  for (size_type i = 0; i < myNumRows; ++i) {
907  const size_type myCurPos = myRowPtr[i];
908  const local_ordinal_type curNumEntries = myNumEntriesPerRow[i];
909  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
910  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
911 
912  // Modify the column indices in place to have the right index base.
913  for (size_type k = 0; k < curNumEntries; ++k) {
914  curColInd[k] += indexBase;
915  }
916  if (curNumEntries > 0) {
917  A->insertGlobalValues (myRows[i], curColInd, curValues);
918  }
919  }
920  // We've entered in all our matrix entries, so we can delete
921  // the original data. This will save memory when we call
922  // fillComplete(), so that we never keep more than two copies
923  // of the matrix's data in memory at once.
924  myNumEntriesPerRow = null;
925  myRowPtr = null;
926  myColInd = null;
927  myValues = null;
928 
929  A->fillComplete (pDomainMap, pRangeMap, fillCompleteParams);
930  return A;
931  }
932 
937  static Teuchos::RCP<sparse_matrix_type>
938  makeMatrix (Teuchos::ArrayRCP<size_t>& myNumEntriesPerRow,
939  Teuchos::ArrayRCP<size_t>& myRowPtr,
940  Teuchos::ArrayRCP<global_ordinal_type>& myColInd,
941  Teuchos::ArrayRCP<scalar_type>& myValues,
942  const Teuchos::RCP<const map_type>& rowMap,
943  Teuchos::RCP<const map_type>& colMap,
944  const Teuchos::RCP<const map_type>& domainMap,
945  const Teuchos::RCP<const map_type>& rangeMap,
946  const bool callFillComplete = true)
947  {
948  using Teuchos::ArrayView;
949  using Teuchos::as;
950  using Teuchos::null;
951  using Teuchos::RCP;
952  using Teuchos::rcp;
953  typedef global_ordinal_type GO;
954 
955  // Construct the CrsMatrix.
956 
957  RCP<sparse_matrix_type> A; // the matrix to return.
958  if (colMap.is_null ()) { // the user didn't provide a column Map
959  A = rcp (new sparse_matrix_type (rowMap, myNumEntriesPerRow, StaticProfile));
960  } else { // the user provided a column Map
961  A = rcp (new sparse_matrix_type (rowMap, colMap, myNumEntriesPerRow, StaticProfile));
962  }
963 
964  // List of the global indices of my rows.
965  // They may or may not be contiguous.
966  ArrayView<const GO> myRows = rowMap->getNodeElementList ();
967  const size_type myNumRows = myRows.size ();
968 
969  // Add this process' matrix entries to the CrsMatrix.
970  const GO indexBase = rowMap->getIndexBase ();
971  for (size_type i = 0; i < myNumRows; ++i) {
972  const size_type myCurPos = myRowPtr[i];
973  const size_type curNumEntries = as<size_type> (myNumEntriesPerRow[i]);
974  ArrayView<GO> curColInd = myColInd.view (myCurPos, curNumEntries);
975  ArrayView<scalar_type> curValues = myValues.view (myCurPos, curNumEntries);
976 
977  // Modify the column indices in place to have the right index base.
978  for (size_type k = 0; k < curNumEntries; ++k) {
979  curColInd[k] += indexBase;
980  }
981  if (curNumEntries > 0) {
982  A->insertGlobalValues (myRows[i], curColInd, curValues);
983  }
984  }
985  // We've entered in all our matrix entries, so we can delete
986  // the original data. This will save memory when we call
987  // fillComplete(), so that we never keep more than two copies
988  // of the matrix's data in memory at once.
989  myNumEntriesPerRow = null;
990  myRowPtr = null;
991  myColInd = null;
992  myValues = null;
993 
994  if (callFillComplete) {
995  A->fillComplete (domainMap, rangeMap);
996  if (colMap.is_null ()) {
997  colMap = A->getColMap ();
998  }
999  }
1000  return A;
1001  }
1002 
1003  private:
1004 
1021  static Teuchos::RCP<const Teuchos::MatrixMarket::Banner>
1022  readBanner (std::istream& in,
1023  size_t& lineNumber,
1024  const bool tolerant=false,
1025  const bool /* debug */=false,
1026  const bool isGraph=false)
1027  {
1028  using Teuchos::MatrixMarket::Banner;
1029  using Teuchos::RCP;
1030  using Teuchos::rcp;
1031  using std::cerr;
1032  using std::endl;
1033  typedef Teuchos::ScalarTraits<scalar_type> STS;
1034 
1035  RCP<Banner> pBanner; // On output, if successful: the read-in Banner.
1036  std::string line; // If read from stream successful: the Banner line
1037 
1038  // Try to read a line from the input stream.
1039  const bool readFailed = ! getline(in, line);
1040  TEUCHOS_TEST_FOR_EXCEPTION(readFailed, std::invalid_argument,
1041  "Failed to get Matrix Market banner line from input.");
1042 
1043  // We read a line from the input stream.
1044  lineNumber++;
1045 
1046  // Assume that the line we found is the Banner line.
1047  try {
1048  pBanner = rcp (new Banner (line, tolerant));
1049  } catch (std::exception& e) {
1050  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1051  "Matrix Market banner line contains syntax error(s): "
1052  << e.what());
1053  }
1054  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->objectType() != "matrix",
1055  std::invalid_argument, "The Matrix Market file does not contain "
1056  "matrix data. Its Banner (first) line says that its object type is \""
1057  << pBanner->matrixType() << "\", rather than the required \"matrix\".");
1058 
1059  // Validate the data type of the matrix, with respect to the
1060  // Scalar type of the CrsMatrix entries.
1061  TEUCHOS_TEST_FOR_EXCEPTION(
1062  ! STS::isComplex && pBanner->dataType() == "complex",
1063  std::invalid_argument,
1064  "The Matrix Market file contains complex-valued data, but you are "
1065  "trying to read it into a matrix containing entries of the real-"
1066  "valued Scalar type \""
1067  << Teuchos::TypeNameTraits<scalar_type>::name() << "\".");
1068  TEUCHOS_TEST_FOR_EXCEPTION(
1069  !isGraph &&
1070  pBanner->dataType() != "real" &&
1071  pBanner->dataType() != "complex" &&
1072  pBanner->dataType() != "integer",
1073  std::invalid_argument,
1074  "When reading Matrix Market data into a Tpetra::CrsMatrix, the "
1075  "Matrix Market file may not contain a \"pattern\" matrix. A "
1076  "pattern matrix is really just a graph with no weights. It "
1077  "should be stored in a CrsGraph, not a CrsMatrix.");
1078 
1079  TEUCHOS_TEST_FOR_EXCEPTION(
1080  isGraph &&
1081  pBanner->dataType() != "pattern",
1082  std::invalid_argument,
1083  "When reading Matrix Market data into a Tpetra::CrsGraph, the "
1084  "Matrix Market file must contain a \"pattern\" matrix.");
1085 
1086  return pBanner;
1087  }
1088 
1111  static Teuchos::Tuple<global_ordinal_type, 3>
1112  readCoordDims (std::istream& in,
1113  size_t& lineNumber,
1114  const Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1115  const Teuchos::RCP<const comm_type>& pComm,
1116  const bool tolerant = false,
1117  const bool /* debug */ = false)
1118  {
1119  using Teuchos::MatrixMarket::readCoordinateDimensions;
1120  using Teuchos::Tuple;
1121 
1122  // Packed coordinate matrix dimensions (numRows, numCols,
1123  // numNonzeros); computed on Rank 0 and broadcasted to all MPI
1124  // ranks.
1125  Tuple<global_ordinal_type, 3> dims;
1126 
1127  // Read in the coordinate matrix dimensions from the input
1128  // stream. "success" tells us whether reading in the
1129  // coordinate matrix dimensions succeeded ("Guilty unless
1130  // proven innocent").
1131  bool success = false;
1132  if (pComm->getRank() == 0) {
1133  TEUCHOS_TEST_FOR_EXCEPTION(pBanner->matrixType() != "coordinate",
1134  std::invalid_argument, "The Tpetra::CrsMatrix Matrix Market reader "
1135  "only accepts \"coordinate\" (sparse) matrix data.");
1136  // Unpacked coordinate matrix dimensions
1137  global_ordinal_type numRows, numCols, numNonzeros;
1138  // Only MPI Rank 0 reads from the input stream
1139  success = readCoordinateDimensions (in, numRows, numCols,
1140  numNonzeros, lineNumber,
1141  tolerant);
1142  // Pack up the data into a Tuple so we can send them with
1143  // one broadcast instead of three.
1144  dims[0] = numRows;
1145  dims[1] = numCols;
1146  dims[2] = numNonzeros;
1147  }
1148  // Only Rank 0 did the reading, so it decides success.
1149  //
1150  // FIXME (mfh 02 Feb 2011) Teuchos::broadcast doesn't know how
1151  // to send bools. For now, we convert to/from int instead,
1152  // using the usual "true is 1, false is 0" encoding.
1153  {
1154  int the_success = success ? 1 : 0; // only matters on MPI Rank 0
1155  Teuchos::broadcast (*pComm, 0, &the_success);
1156  success = (the_success == 1);
1157  }
1158  if (success) {
1159  // Broadcast (numRows, numCols, numNonzeros) from Rank 0
1160  // to all the other MPI ranks.
1161  Teuchos::broadcast (*pComm, 0, dims);
1162  }
1163  else {
1164  // Perhaps in tolerant mode, we could set all the
1165  // dimensions to zero for now, and deduce correct
1166  // dimensions by reading all of the file's entries and
1167  // computing the max(row index) and max(column index).
1168  // However, for now we just error out in that case.
1169  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
1170  "Error reading Matrix Market sparse matrix: failed to read "
1171  "coordinate matrix dimensions.");
1172  }
1173  return dims;
1174  }
1175 
1186  typedef Teuchos::MatrixMarket::SymmetrizingAdder<Teuchos::MatrixMarket::Raw::Adder<scalar_type, global_ordinal_type> > adder_type;
1187 
1188  typedef Teuchos::MatrixMarket::SymmetrizingGraphAdder<Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> > graph_adder_type;
1189 
1215  static Teuchos::RCP<adder_type>
1216  makeAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1217  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1218  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1219  const bool tolerant=false,
1220  const bool debug=false)
1221  {
1222  if (pComm->getRank () == 0) {
1223  typedef Teuchos::MatrixMarket::Raw::Adder<scalar_type,
1225  raw_adder_type;
1226  Teuchos::RCP<raw_adder_type> pRaw =
1227  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1228  tolerant, debug));
1229  return Teuchos::rcp (new adder_type (pRaw, pBanner->symmType ()));
1230  }
1231  else {
1232  return Teuchos::null;
1233  }
1234  }
1235 
1261  static Teuchos::RCP<graph_adder_type>
1262  makeGraphAdder (const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1263  Teuchos::RCP<const Teuchos::MatrixMarket::Banner>& pBanner,
1264  const Teuchos::Tuple<global_ordinal_type, 3>& dims,
1265  const bool tolerant=false,
1266  const bool debug=false)
1267  {
1268  if (pComm->getRank () == 0) {
1269  typedef Teuchos::MatrixMarket::Raw::GraphAdder<global_ordinal_type> raw_adder_type;
1270  Teuchos::RCP<raw_adder_type> pRaw =
1271  Teuchos::rcp (new raw_adder_type (dims[0], dims[1], dims[2],
1272  tolerant, debug));
1273  return Teuchos::rcp (new graph_adder_type (pRaw, pBanner->symmType ()));
1274  }
1275  else {
1276  return Teuchos::null;
1277  }
1278  }
1279 
1281  static Teuchos::RCP<sparse_graph_type>
1282  readSparseGraphHelper (std::istream& in,
1283  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1284  const Teuchos::RCP<const map_type>& rowMap,
1285  Teuchos::RCP<const map_type>& colMap,
1286  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1287  const bool tolerant,
1288  const bool debug)
1289  {
1290  using Teuchos::MatrixMarket::Banner;
1291  using Teuchos::RCP;
1292  using Teuchos::ptr;
1293  using Teuchos::Tuple;
1294  using std::cerr;
1295  using std::endl;
1296 
1297  const int myRank = pComm->getRank ();
1298  const int rootRank = 0;
1299 
1300  // Current line number in the input stream. Various calls
1301  // will modify this depending on the number of lines that are
1302  // read from the input stream. Only Rank 0 modifies this.
1303  size_t lineNumber = 1;
1304 
1305  if (debug && myRank == rootRank) {
1306  cerr << "Matrix Market reader: readGraph:" << endl
1307  << "-- Reading banner line" << endl;
1308  }
1309 
1310  // The "Banner" tells you whether the input stream represents
1311  // a sparse matrix, the symmetry type of the matrix, and the
1312  // type of the data it contains.
1313  //
1314  // pBanner will only be nonnull on MPI Rank 0. It will be
1315  // null on all other MPI processes.
1316  RCP<const Banner> pBanner;
1317  {
1318  // We read and validate the Banner on Proc 0, but broadcast
1319  // the validation result to all processes.
1320  // Teuchos::broadcast doesn't currently work with bool, so
1321  // we use int (true -> 1, false -> 0).
1322  int bannerIsCorrect = 1;
1323  std::ostringstream errMsg;
1324 
1325  if (myRank == rootRank) {
1326  // Read the Banner line from the input stream.
1327  try {
1328  pBanner = readBanner (in, lineNumber, tolerant, debug, true);
1329  }
1330  catch (std::exception& e) {
1331  errMsg << "Attempt to read the Matrix Market file's Banner line "
1332  "threw an exception: " << e.what();
1333  bannerIsCorrect = 0;
1334  }
1335 
1336  if (bannerIsCorrect) {
1337  // Validate the Banner for the case of a sparse graph.
1338  // We validate on Proc 0, since it reads the Banner.
1339 
1340  // In intolerant mode, the matrix type must be "coordinate".
1341  if (! tolerant && pBanner->matrixType() != "coordinate") {
1342  bannerIsCorrect = 0;
1343  errMsg << "The Matrix Market input file must contain a "
1344  "\"coordinate\"-format sparse graph in order to create a "
1345  "Tpetra::CrsGraph object from it, but the file's matrix "
1346  "type is \"" << pBanner->matrixType() << "\" instead.";
1347  }
1348  // In tolerant mode, we allow the matrix type to be
1349  // anything other than "array" (which would mean that
1350  // the file contains a dense matrix).
1351  if (tolerant && pBanner->matrixType() == "array") {
1352  bannerIsCorrect = 0;
1353  errMsg << "Matrix Market file must contain a \"coordinate\"-"
1354  "format sparse graph in order to create a Tpetra::CrsGraph "
1355  "object from it, but the file's matrix type is \"array\" "
1356  "instead. That probably means the file contains dense matrix "
1357  "data.";
1358  }
1359  }
1360  } // Proc 0: Done reading the Banner, hopefully successfully.
1361 
1362  // Broadcast from Proc 0 whether the Banner was read correctly.
1363  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
1364 
1365  // If the Banner is invalid, all processes throw an
1366  // exception. Only Proc 0 gets the exception message, but
1367  // that's OK, since the main point is to "stop the world"
1368  // (rather than throw an exception on one process and leave
1369  // the others hanging).
1370  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
1371  std::invalid_argument, errMsg.str ());
1372  } // Done reading the Banner line and broadcasting success.
1373  if (debug && myRank == rootRank) {
1374  cerr << "-- Reading dimensions line" << endl;
1375  }
1376 
1377  // Read the graph dimensions from the Matrix Market metadata.
1378  // dims = (numRows, numCols, numEntries). Proc 0 does the
1379  // reading, but it broadcasts the results to all MPI
1380  // processes. Thus, readCoordDims() is a collective
1381  // operation. It does a collective check for correctness too.
1382  Tuple<global_ordinal_type, 3> dims =
1383  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
1384 
1385  if (debug && myRank == rootRank) {
1386  cerr << "-- Making Adder for collecting graph data" << endl;
1387  }
1388 
1389  // "Adder" object for collecting all the sparse graph entries
1390  // from the input stream. This is only nonnull on Proc 0.
1391  // The Adder internally converts the one-based indices (native
1392  // Matrix Market format) into zero-based indices.
1393  RCP<graph_adder_type> pAdder =
1394  makeGraphAdder (pComm, pBanner, dims, tolerant, debug);
1395 
1396  if (debug && myRank == rootRank) {
1397  cerr << "-- Reading graph data" << endl;
1398  }
1399  //
1400  // Read the graph entries from the input stream on Proc 0.
1401  //
1402  {
1403  // We use readSuccess to broadcast the results of the read
1404  // (succeeded or not) to all MPI processes. Since
1405  // Teuchos::broadcast doesn't currently know how to send
1406  // bools, we convert to int (true -> 1, false -> 0).
1407  int readSuccess = 1;
1408  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
1409  if (myRank == rootRank) {
1410  try {
1411  // Reader for "coordinate" format sparse graph data.
1412  typedef Teuchos::MatrixMarket::CoordPatternReader<graph_adder_type,
1413  global_ordinal_type> reader_type;
1414  reader_type reader (pAdder);
1415 
1416  // Read the sparse graph entries.
1417  std::pair<bool, std::vector<size_t> > results =
1418  reader.read (in, lineNumber, tolerant, debug);
1419  readSuccess = results.first ? 1 : 0;
1420  }
1421  catch (std::exception& e) {
1422  readSuccess = 0;
1423  errMsg << e.what();
1424  }
1425  }
1426  broadcast (*pComm, rootRank, ptr (&readSuccess));
1427 
1428  // It would be nice to add a "verbose" flag, so that in
1429  // tolerant mode, we could log any bad line number(s) on
1430  // Proc 0. For now, we just throw if the read fails to
1431  // succeed.
1432  //
1433  // Question: If we're in tolerant mode, and if the read did
1434  // not succeed, should we attempt to call fillComplete()?
1435  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
1436  "Failed to read the Matrix Market sparse graph file: "
1437  << errMsg.str());
1438  } // Done reading the graph entries (stored on Proc 0 for now)
1439 
1440  if (debug && myRank == rootRank) {
1441  cerr << "-- Successfully read the Matrix Market data" << endl;
1442  }
1443 
1444  // In tolerant mode, we need to rebroadcast the graph
1445  // dimensions, since they may be different after reading the
1446  // actual graph data. We only need to broadcast the number
1447  // of rows and columns. Only Rank 0 needs to know the actual
1448  // global number of entries, since (a) we need to merge
1449  // duplicates on Rank 0 first anyway, and (b) when we
1450  // distribute the entries, each rank other than Rank 0 will
1451  // only need to know how many entries it owns, not the total
1452  // number of entries.
1453  if (tolerant) {
1454  if (debug && myRank == rootRank) {
1455  cerr << "-- Tolerant mode: rebroadcasting graph dimensions"
1456  << endl
1457  << "----- Dimensions before: "
1458  << dims[0] << " x " << dims[1]
1459  << endl;
1460  }
1461  // Packed coordinate graph dimensions (numRows, numCols).
1462  Tuple<global_ordinal_type, 2> updatedDims;
1463  if (myRank == rootRank) {
1464  // If one or more bottom rows of the graph contain no
1465  // entries, then the Adder will report that the number
1466  // of rows is less than that specified in the
1467  // metadata. We allow this case, and favor the
1468  // metadata so that the zero row(s) will be included.
1469  updatedDims[0] =
1470  std::max (dims[0], pAdder->getAdder()->numRows());
1471  updatedDims[1] = pAdder->getAdder()->numCols();
1472  }
1473  broadcast (*pComm, rootRank, updatedDims);
1474  dims[0] = updatedDims[0];
1475  dims[1] = updatedDims[1];
1476  if (debug && myRank == rootRank) {
1477  cerr << "----- Dimensions after: " << dims[0] << " x "
1478  << dims[1] << endl;
1479  }
1480  }
1481  else {
1482  // In strict mode, we require that the graph's metadata and
1483  // its actual data agree, at least somewhat. In particular,
1484  // the number of rows must agree, since otherwise we cannot
1485  // distribute the graph correctly.
1486 
1487  // Teuchos::broadcast() doesn't know how to broadcast bools,
1488  // so we use an int with the standard 1 == true, 0 == false
1489  // encoding.
1490  int dimsMatch = 1;
1491  if (myRank == rootRank) {
1492  // If one or more bottom rows of the graph contain no
1493  // entries, then the Adder will report that the number of
1494  // rows is less than that specified in the metadata. We
1495  // allow this case, and favor the metadata, but do not
1496  // allow the Adder to think there are more rows in the
1497  // graph than the metadata says.
1498  if (dims[0] < pAdder->getAdder ()->numRows ()) {
1499  dimsMatch = 0;
1500  }
1501  }
1502  broadcast (*pComm, 0, ptr (&dimsMatch));
1503  if (dimsMatch == 0) {
1504  // We're in an error state anyway, so we might as well
1505  // work a little harder to print an informative error
1506  // message.
1507  //
1508  // Broadcast the Adder's idea of the graph dimensions
1509  // from Proc 0 to all processes.
1510  Tuple<global_ordinal_type, 2> addersDims;
1511  if (myRank == rootRank) {
1512  addersDims[0] = pAdder->getAdder()->numRows();
1513  addersDims[1] = pAdder->getAdder()->numCols();
1514  }
1515  broadcast (*pComm, 0, addersDims);
1516  TEUCHOS_TEST_FOR_EXCEPTION(
1517  dimsMatch == 0, std::runtime_error,
1518  "The graph metadata says that the graph is " << dims[0] << " x "
1519  << dims[1] << ", but the actual data says that the graph is "
1520  << addersDims[0] << " x " << addersDims[1] << ". That means the "
1521  "data includes more rows than reported in the metadata. This "
1522  "is not allowed when parsing in strict mode. Parse the graph in "
1523  "tolerant mode to ignore the metadata when it disagrees with the "
1524  "data.");
1525  }
1526  } // Matrix dimensions (# rows, # cols, # entries) agree.
1527 
1528  // Create a map describing a distribution where the root owns EVERYTHING
1529  RCP<map_type> proc0Map;
1530  global_ordinal_type indexBase;
1531  if(Teuchos::is_null(rowMap)) {
1532  indexBase = 0;
1533  }
1534  else {
1535  indexBase = rowMap->getIndexBase();
1536  }
1537  if(myRank == rootRank) {
1538  proc0Map = rcp(new map_type(dims[0],dims[0],indexBase,pComm));
1539  }
1540  else {
1541  proc0Map = rcp(new map_type(dims[0],0,indexBase,pComm));
1542  }
1543 
1544  // Create the graph where the root owns EVERYTHING
1545  std::map<global_ordinal_type, size_t> numEntriesPerRow_map;
1546  if (myRank == rootRank) {
1547  const auto& entries = pAdder()->getAdder()->getEntries();
1548  // This will count duplicates, but it's better than dense.
1549  // An even better approach would use a classic algorithm,
1550  // likely in Saad's old textbook, for converting COO (entries)
1551  // to CSR (the local part of the sparse matrix data structure).
1552  for (const auto& entry : entries) {
1553  const global_ordinal_type gblRow = entry.rowIndex () + indexBase;
1554  ++numEntriesPerRow_map[gblRow];
1555  }
1556  }
1557 
1558  Teuchos::Array<size_t> numEntriesPerRow (proc0Map->getNodeNumElements ());
1559  for (const auto& ent : numEntriesPerRow_map) {
1560  const local_ordinal_type lclRow = proc0Map->getLocalElement (ent.first);
1561  numEntriesPerRow[lclRow] = ent.second;
1562  }
1563  // Free anything we don't need before allocating the graph.
1564  // Swapping with an empty data structure is the standard idiom
1565  // for freeing memory used by Standard Library containers.
1566  // (Just resizing to 0 doesn't promise to free memory.)
1567  {
1568  std::map<global_ordinal_type, size_t> empty_map;
1569  std::swap (numEntriesPerRow_map, empty_map);
1570  }
1571 
1572  RCP<sparse_graph_type> proc0Graph =
1573  rcp(new sparse_graph_type(proc0Map,numEntriesPerRow (),
1574  StaticProfile,constructorParams));
1575  if(myRank == rootRank) {
1576  typedef Teuchos::MatrixMarket::Raw::GraphElement<global_ordinal_type> element_type;
1577 
1578  // Get the entries
1579  const std::vector<element_type>& entries =
1580  pAdder->getAdder()->getEntries();
1581 
1582  // Insert them one at a time
1583  for(size_t curPos=0; curPos<entries.size(); curPos++) {
1584  const element_type& curEntry = entries[curPos];
1585  const global_ordinal_type curRow = curEntry.rowIndex()+indexBase;
1586  const global_ordinal_type curCol = curEntry.colIndex()+indexBase;
1587  Teuchos::ArrayView<const global_ordinal_type> colView(&curCol,1);
1588  proc0Graph->insertGlobalIndices(curRow,colView);
1589  }
1590  }
1591  proc0Graph->fillComplete();
1592 
1593  RCP<sparse_graph_type> distGraph;
1594  if(Teuchos::is_null(rowMap))
1595  {
1596  // Create a map describing the distribution we actually want
1597  RCP<map_type> distMap =
1598  rcp(new map_type(dims[0],0,pComm,GloballyDistributed));
1599 
1600  // Create the graph with that distribution too
1601  distGraph = rcp(new sparse_graph_type(distMap,colMap,0,StaticProfile,constructorParams));
1602 
1603  // Create an importer/exporter/vandelay to redistribute the graph
1604  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1605  import_type importer (proc0Map, distMap);
1606 
1607  // Import the data
1608  distGraph->doImport(*proc0Graph,importer,INSERT);
1609  }
1610  else {
1611  distGraph = rcp(new sparse_graph_type(rowMap,colMap,0,StaticProfile,constructorParams));
1612 
1613  // Create an importer/exporter/vandelay to redistribute the graph
1614  typedef Import<local_ordinal_type, global_ordinal_type, node_type> import_type;
1615  import_type importer (proc0Map, rowMap);
1616 
1617  // Import the data
1618  distGraph->doImport(*proc0Graph,importer,INSERT);
1619  }
1620 
1621  return distGraph;
1622  }
1623 
1624  public:
1648  static Teuchos::RCP<sparse_graph_type>
1649  readSparseGraphFile (const std::string& filename,
1650  const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
1651  const bool callFillComplete=true,
1652  const bool tolerant=false,
1653  const bool debug=false)
1654  {
1655  using Teuchos::broadcast;
1656  using Teuchos::outArg;
1657 
1658  // Only open the file on Process 0. Test carefully to make
1659  // sure that the file opened successfully (and broadcast that
1660  // result to all processes to prevent a hang on exception
1661  // throw), since it's a common mistake to misspell a filename.
1662  std::ifstream in;
1663  int opened = 0;
1664  if (comm->getRank () == 0) {
1665  try {
1666  in.open (filename.c_str ());
1667  opened = in.is_open();
1668  }
1669  catch (...) {
1670  opened = 0;
1671  }
1672  }
1673  broadcast<int, int> (*comm, 0, outArg (opened));
1674  TEUCHOS_TEST_FOR_EXCEPTION
1675  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1676  "Failed to open file \"" << filename << "\" on Process 0.");
1677  return readSparseGraph (in, comm,
1678  callFillComplete,
1679  tolerant, debug);
1680  // We can rely on the destructor of the input stream to close
1681  // the file on scope exit, even if readSparseGraph() throws an
1682  // exception.
1683  }
1684 
1685 
1714  static Teuchos::RCP<sparse_graph_type>
1715  readSparseGraphFile (const std::string& filename,
1716  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1717  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1718  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1719  const bool tolerant=false,
1720  const bool debug=false)
1721  {
1722  using Teuchos::broadcast;
1723  using Teuchos::outArg;
1724 
1725  // Only open the file on Process 0. Test carefully to make
1726  // sure that the file opened successfully (and broadcast that
1727  // result to all processes to prevent a hang on exception
1728  // throw), since it's a common mistake to misspell a filename.
1729  std::ifstream in;
1730  int opened = 0;
1731  if (pComm->getRank () == 0) {
1732  try {
1733  in.open (filename.c_str ());
1734  opened = in.is_open();
1735  }
1736  catch (...) {
1737  opened = 0;
1738  }
1739  }
1740  broadcast<int, int> (*pComm, 0, outArg (opened));
1741  TEUCHOS_TEST_FOR_EXCEPTION
1742  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1743  "Failed to open file \"" << filename << "\" on Process 0.");
1744  if (pComm->getRank () == 0) { // only open the input file on Process 0
1745  in.open (filename.c_str ());
1746  }
1747  return readSparseGraph (in, pComm,
1748  constructorParams,
1749  fillCompleteParams, tolerant, debug);
1750  // We can rely on the destructor of the input stream to close
1751  // the file on scope exit, even if readSparseGraph() throws an
1752  // exception.
1753  }
1754 
1755 
1793  static Teuchos::RCP<sparse_graph_type>
1794  readSparseGraphFile (const std::string& filename,
1795  const Teuchos::RCP<const map_type>& rowMap,
1796  Teuchos::RCP<const map_type>& colMap,
1797  const Teuchos::RCP<const map_type>& domainMap,
1798  const Teuchos::RCP<const map_type>& rangeMap,
1799  const bool callFillComplete=true,
1800  const bool tolerant=false,
1801  const bool debug=false)
1802  {
1803  using Teuchos::broadcast;
1804  using Teuchos::Comm;
1805  using Teuchos::outArg;
1806  using Teuchos::RCP;
1807 
1808  TEUCHOS_TEST_FOR_EXCEPTION
1809  (rowMap.is_null (), std::invalid_argument,
1810  "Input rowMap must be nonnull.");
1811  RCP<const Comm<int> > comm = rowMap->getComm ();
1812  if (comm.is_null ()) {
1813  // If the input communicator is null on some process, then
1814  // that process does not participate in the collective.
1815  return Teuchos::null;
1816  }
1817 
1818  // Only open the file on Process 0. Test carefully to make
1819  // sure that the file opened successfully (and broadcast that
1820  // result to all processes to prevent a hang on exception
1821  // throw), since it's a common mistake to misspell a filename.
1822  std::ifstream in;
1823  int opened = 0;
1824  if (comm->getRank () == 0) {
1825  try {
1826  in.open (filename.c_str ());
1827  opened = in.is_open();
1828  }
1829  catch (...) {
1830  opened = 0;
1831  }
1832  }
1833  broadcast<int, int> (*comm, 0, outArg (opened));
1834  TEUCHOS_TEST_FOR_EXCEPTION
1835  (opened == 0, std::runtime_error, "readSparseGraphFile: "
1836  "Failed to open file \"" << filename << "\" on Process 0.");
1837  return readSparseGraph (in, rowMap, colMap, domainMap, rangeMap,
1838  callFillComplete, tolerant, debug);
1839  }
1840 
1866  static Teuchos::RCP<sparse_graph_type>
1867  readSparseGraph (std::istream& in,
1868  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1869  const bool callFillComplete=true,
1870  const bool tolerant=false,
1871  const bool debug=false)
1872  {
1873  Teuchos::RCP<const map_type> fakeRowMap;
1874  Teuchos::RCP<const map_type> fakeColMap;
1875  Teuchos::RCP<Teuchos::ParameterList> fakeCtorParams;
1876 
1877  Teuchos::RCP<sparse_graph_type> graph =
1878  readSparseGraphHelper (in, pComm,
1879  fakeRowMap, fakeColMap,
1880  fakeCtorParams, tolerant, debug);
1881  if (callFillComplete) {
1882  graph->fillComplete ();
1883  }
1884  return graph;
1885  }
1886 
1887 
1917  static Teuchos::RCP<sparse_graph_type>
1918  readSparseGraph (std::istream& in,
1919  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
1920  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
1921  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
1922  const bool tolerant=false,
1923  const bool debug=false)
1924  {
1925  Teuchos::RCP<const map_type> fakeRowMap;
1926  Teuchos::RCP<const map_type> fakeColMap;
1927  Teuchos::RCP<sparse_graph_type> graph =
1928  readSparseGraphHelper (in, pComm,
1929  fakeRowMap, fakeColMap,
1930  constructorParams, tolerant, debug);
1931  graph->fillComplete (fillCompleteParams);
1932  return graph;
1933  }
1934 
1935 
1976  static Teuchos::RCP<sparse_graph_type>
1977  readSparseGraph (std::istream& in,
1978  const Teuchos::RCP<const map_type>& rowMap,
1979  Teuchos::RCP<const map_type>& colMap,
1980  const Teuchos::RCP<const map_type>& domainMap,
1981  const Teuchos::RCP<const map_type>& rangeMap,
1982  const bool callFillComplete=true,
1983  const bool tolerant=false,
1984  const bool debug=false)
1985  {
1986  Teuchos::RCP<sparse_graph_type> graph =
1987  readSparseGraphHelper (in, rowMap->getComm (),
1988  rowMap, colMap, Teuchos::null, tolerant,
1989  debug);
1990  if (callFillComplete) {
1991  graph->fillComplete (domainMap, rangeMap);
1992  }
1993  return graph;
1994  }
1995 
1996 #include "MatrixMarket_TpetraNew.hpp"
1997 
2021  static Teuchos::RCP<sparse_matrix_type>
2022  readSparseFile (const std::string& filename,
2023  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2024  const bool callFillComplete=true,
2025  const bool tolerant=false,
2026  const bool debug=false)
2027  {
2028  const int myRank = pComm->getRank ();
2029  std::ifstream in;
2030 
2031  // Only open the file on Rank 0.
2032  if (myRank == 0) {
2033  in.open (filename.c_str ());
2034  }
2035  // FIXME (mfh 16 Jun 2015) Do a broadcast to make sure that
2036  // opening the file succeeded, before continuing. That will
2037  // avoid hangs if the read doesn't work. On the other hand,
2038  // readSparse could do that too, by checking the status of the
2039  // std::ostream.
2040 
2041  return readSparse (in, pComm, callFillComplete, tolerant, debug);
2042  // We can rely on the destructor of the input stream to close
2043  // the file on scope exit, even if readSparse() throws an
2044  // exception.
2045  }
2046 
2047 
2076  static Teuchos::RCP<sparse_matrix_type>
2077  readSparseFile (const std::string& filename,
2078  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2079  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2080  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2081  const bool tolerant=false,
2082  const bool debug=false)
2083  {
2084  std::ifstream in;
2085  if (pComm->getRank () == 0) { // only open on Process 0
2086  in.open (filename.c_str ());
2087  }
2088  return readSparse (in, pComm, constructorParams,
2089  fillCompleteParams, tolerant, debug);
2090  }
2091 
2092 
2130  static Teuchos::RCP<sparse_matrix_type>
2131  readSparseFile (const std::string& filename,
2132  const Teuchos::RCP<const map_type>& rowMap,
2133  Teuchos::RCP<const map_type>& colMap,
2134  const Teuchos::RCP<const map_type>& domainMap,
2135  const Teuchos::RCP<const map_type>& rangeMap,
2136  const bool callFillComplete=true,
2137  const bool tolerant=false,
2138  const bool debug=false)
2139  {
2140  using Teuchos::broadcast;
2141  using Teuchos::Comm;
2142  using Teuchos::outArg;
2143  using Teuchos::RCP;
2144 
2145  TEUCHOS_TEST_FOR_EXCEPTION(
2146  rowMap.is_null (), std::invalid_argument,
2147  "Row Map must be nonnull.");
2148 
2149  RCP<const Comm<int> > comm = rowMap->getComm ();
2150  const int myRank = comm->getRank ();
2151 
2152  // Only open the file on Process 0. Test carefully to make
2153  // sure that the file opened successfully (and broadcast that
2154  // result to all processes to prevent a hang on exception
2155  // throw), since it's a common mistake to misspell a filename.
2156  std::ifstream in;
2157  int opened = 0;
2158  if (myRank == 0) {
2159  try {
2160  in.open (filename.c_str ());
2161  opened = in.is_open();
2162  }
2163  catch (...) {
2164  opened = 0;
2165  }
2166  }
2167  broadcast<int, int> (*comm, 0, outArg (opened));
2168  TEUCHOS_TEST_FOR_EXCEPTION(
2169  opened == 0, std::runtime_error,
2170  "readSparseFile: Failed to open file \"" << filename << "\" on "
2171  "Process 0.");
2172  return readSparse (in, rowMap, colMap, domainMap, rangeMap,
2173  callFillComplete, tolerant, debug);
2174  }
2175 
2201  static Teuchos::RCP<sparse_matrix_type>
2202  readSparse (std::istream& in,
2203  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2204  const bool callFillComplete=true,
2205  const bool tolerant=false,
2206  const bool debug=false)
2207  {
2208  using Teuchos::MatrixMarket::Banner;
2209  using Teuchos::arcp;
2210  using Teuchos::ArrayRCP;
2211  using Teuchos::broadcast;
2212  using Teuchos::null;
2213  using Teuchos::ptr;
2214  using Teuchos::RCP;
2215  using Teuchos::REDUCE_MAX;
2216  using Teuchos::reduceAll;
2217  using Teuchos::Tuple;
2218  using std::cerr;
2219  using std::endl;
2220  typedef Teuchos::ScalarTraits<scalar_type> STS;
2221 
2222  const bool extraDebug = false;
2223  const int myRank = pComm->getRank ();
2224  const int rootRank = 0;
2225 
2226  // Current line number in the input stream. Various calls
2227  // will modify this depending on the number of lines that are
2228  // read from the input stream. Only Rank 0 modifies this.
2229  size_t lineNumber = 1;
2230 
2231  if (debug && myRank == rootRank) {
2232  cerr << "Matrix Market reader: readSparse:" << endl
2233  << "-- Reading banner line" << endl;
2234  }
2235 
2236  // The "Banner" tells you whether the input stream represents
2237  // a sparse matrix, the symmetry type of the matrix, and the
2238  // type of the data it contains.
2239  //
2240  // pBanner will only be nonnull on MPI Rank 0. It will be
2241  // null on all other MPI processes.
2242  RCP<const Banner> pBanner;
2243  {
2244  // We read and validate the Banner on Proc 0, but broadcast
2245  // the validation result to all processes.
2246  // Teuchos::broadcast doesn't currently work with bool, so
2247  // we use int (true -> 1, false -> 0).
2248  int bannerIsCorrect = 1;
2249  std::ostringstream errMsg;
2250 
2251  if (myRank == rootRank) {
2252  // Read the Banner line from the input stream.
2253  try {
2254  pBanner = readBanner (in, lineNumber, tolerant, debug);
2255  }
2256  catch (std::exception& e) {
2257  errMsg << "Attempt to read the Matrix Market file's Banner line "
2258  "threw an exception: " << e.what();
2259  bannerIsCorrect = 0;
2260  }
2261 
2262  if (bannerIsCorrect) {
2263  // Validate the Banner for the case of a sparse matrix.
2264  // We validate on Proc 0, since it reads the Banner.
2265 
2266  // In intolerant mode, the matrix type must be "coordinate".
2267  if (! tolerant && pBanner->matrixType() != "coordinate") {
2268  bannerIsCorrect = 0;
2269  errMsg << "The Matrix Market input file must contain a "
2270  "\"coordinate\"-format sparse matrix in order to create a "
2271  "Tpetra::CrsMatrix object from it, but the file's matrix "
2272  "type is \"" << pBanner->matrixType() << "\" instead.";
2273  }
2274  // In tolerant mode, we allow the matrix type to be
2275  // anything other than "array" (which would mean that
2276  // the file contains a dense matrix).
2277  if (tolerant && pBanner->matrixType() == "array") {
2278  bannerIsCorrect = 0;
2279  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2280  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2281  "object from it, but the file's matrix type is \"array\" "
2282  "instead. That probably means the file contains dense matrix "
2283  "data.";
2284  }
2285  }
2286  } // Proc 0: Done reading the Banner, hopefully successfully.
2287 
2288  // Broadcast from Proc 0 whether the Banner was read correctly.
2289  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2290 
2291  // If the Banner is invalid, all processes throw an
2292  // exception. Only Proc 0 gets the exception message, but
2293  // that's OK, since the main point is to "stop the world"
2294  // (rather than throw an exception on one process and leave
2295  // the others hanging).
2296  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2297  std::invalid_argument, errMsg.str ());
2298  } // Done reading the Banner line and broadcasting success.
2299  if (debug && myRank == rootRank) {
2300  cerr << "-- Reading dimensions line" << endl;
2301  }
2302 
2303  // Read the matrix dimensions from the Matrix Market metadata.
2304  // dims = (numRows, numCols, numEntries). Proc 0 does the
2305  // reading, but it broadcasts the results to all MPI
2306  // processes. Thus, readCoordDims() is a collective
2307  // operation. It does a collective check for correctness too.
2308  Tuple<global_ordinal_type, 3> dims =
2309  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2310 
2311  if (debug && myRank == rootRank) {
2312  cerr << "-- Making Adder for collecting matrix data" << endl;
2313  }
2314 
2315  // "Adder" object for collecting all the sparse matrix entries
2316  // from the input stream. This is only nonnull on Proc 0.
2317  RCP<adder_type> pAdder =
2318  makeAdder (pComm, pBanner, dims, tolerant, debug);
2319 
2320  if (debug && myRank == rootRank) {
2321  cerr << "-- Reading matrix data" << endl;
2322  }
2323  //
2324  // Read the matrix entries from the input stream on Proc 0.
2325  //
2326  {
2327  // We use readSuccess to broadcast the results of the read
2328  // (succeeded or not) to all MPI processes. Since
2329  // Teuchos::broadcast doesn't currently know how to send
2330  // bools, we convert to int (true -> 1, false -> 0).
2331  int readSuccess = 1;
2332  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2333  if (myRank == rootRank) {
2334  try {
2335  // Reader for "coordinate" format sparse matrix data.
2336  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2337  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2338  reader_type reader (pAdder);
2339 
2340  // Read the sparse matrix entries.
2341  std::pair<bool, std::vector<size_t> > results =
2342  reader.read (in, lineNumber, tolerant, debug);
2343  readSuccess = results.first ? 1 : 0;
2344  }
2345  catch (std::exception& e) {
2346  readSuccess = 0;
2347  errMsg << e.what();
2348  }
2349  }
2350  broadcast (*pComm, rootRank, ptr (&readSuccess));
2351 
2352  // It would be nice to add a "verbose" flag, so that in
2353  // tolerant mode, we could log any bad line number(s) on
2354  // Proc 0. For now, we just throw if the read fails to
2355  // succeed.
2356  //
2357  // Question: If we're in tolerant mode, and if the read did
2358  // not succeed, should we attempt to call fillComplete()?
2359  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2360  "Failed to read the Matrix Market sparse matrix file: "
2361  << errMsg.str());
2362  } // Done reading the matrix entries (stored on Proc 0 for now)
2363 
2364  if (debug && myRank == rootRank) {
2365  cerr << "-- Successfully read the Matrix Market data" << endl;
2366  }
2367 
2368  // In tolerant mode, we need to rebroadcast the matrix
2369  // dimensions, since they may be different after reading the
2370  // actual matrix data. We only need to broadcast the number
2371  // of rows and columns. Only Rank 0 needs to know the actual
2372  // global number of entries, since (a) we need to merge
2373  // duplicates on Rank 0 first anyway, and (b) when we
2374  // distribute the entries, each rank other than Rank 0 will
2375  // only need to know how many entries it owns, not the total
2376  // number of entries.
2377  if (tolerant) {
2378  if (debug && myRank == rootRank) {
2379  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2380  << endl
2381  << "----- Dimensions before: "
2382  << dims[0] << " x " << dims[1]
2383  << endl;
2384  }
2385  // Packed coordinate matrix dimensions (numRows, numCols).
2386  Tuple<global_ordinal_type, 2> updatedDims;
2387  if (myRank == rootRank) {
2388  // If one or more bottom rows of the matrix contain no
2389  // entries, then the Adder will report that the number
2390  // of rows is less than that specified in the
2391  // metadata. We allow this case, and favor the
2392  // metadata so that the zero row(s) will be included.
2393  updatedDims[0] =
2394  std::max (dims[0], pAdder->getAdder()->numRows());
2395  updatedDims[1] = pAdder->getAdder()->numCols();
2396  }
2397  broadcast (*pComm, rootRank, updatedDims);
2398  dims[0] = updatedDims[0];
2399  dims[1] = updatedDims[1];
2400  if (debug && myRank == rootRank) {
2401  cerr << "----- Dimensions after: " << dims[0] << " x "
2402  << dims[1] << endl;
2403  }
2404  }
2405  else {
2406  // In strict mode, we require that the matrix's metadata and
2407  // its actual data agree, at least somewhat. In particular,
2408  // the number of rows must agree, since otherwise we cannot
2409  // distribute the matrix correctly.
2410 
2411  // Teuchos::broadcast() doesn't know how to broadcast bools,
2412  // so we use an int with the standard 1 == true, 0 == false
2413  // encoding.
2414  int dimsMatch = 1;
2415  if (myRank == rootRank) {
2416  // If one or more bottom rows of the matrix contain no
2417  // entries, then the Adder will report that the number of
2418  // rows is less than that specified in the metadata. We
2419  // allow this case, and favor the metadata, but do not
2420  // allow the Adder to think there are more rows in the
2421  // matrix than the metadata says.
2422  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2423  dimsMatch = 0;
2424  }
2425  }
2426  broadcast (*pComm, 0, ptr (&dimsMatch));
2427  if (dimsMatch == 0) {
2428  // We're in an error state anyway, so we might as well
2429  // work a little harder to print an informative error
2430  // message.
2431  //
2432  // Broadcast the Adder's idea of the matrix dimensions
2433  // from Proc 0 to all processes.
2434  Tuple<global_ordinal_type, 2> addersDims;
2435  if (myRank == rootRank) {
2436  addersDims[0] = pAdder->getAdder()->numRows();
2437  addersDims[1] = pAdder->getAdder()->numCols();
2438  }
2439  broadcast (*pComm, 0, addersDims);
2440  TEUCHOS_TEST_FOR_EXCEPTION(
2441  dimsMatch == 0, std::runtime_error,
2442  "The matrix metadata says that the matrix is " << dims[0] << " x "
2443  << dims[1] << ", but the actual data says that the matrix is "
2444  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2445  "data includes more rows than reported in the metadata. This "
2446  "is not allowed when parsing in strict mode. Parse the matrix in "
2447  "tolerant mode to ignore the metadata when it disagrees with the "
2448  "data.");
2449  }
2450  } // Matrix dimensions (# rows, # cols, # entries) agree.
2451 
2452  if (debug && myRank == rootRank) {
2453  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
2454  }
2455 
2456  // Now that we've read in all the matrix entries from the
2457  // input stream into the adder on Proc 0, post-process them
2458  // into CSR format (still on Proc 0). This will facilitate
2459  // distributing them to all the processors.
2460  //
2461  // These arrays represent the global matrix data as a CSR
2462  // matrix (with numEntriesPerRow as redundant but convenient
2463  // metadata, since it's computable from rowPtr and vice
2464  // versa). They are valid only on Proc 0.
2465  ArrayRCP<size_t> numEntriesPerRow;
2466  ArrayRCP<size_t> rowPtr;
2467  ArrayRCP<global_ordinal_type> colInd;
2468  ArrayRCP<scalar_type> values;
2469 
2470  // Proc 0 first merges duplicate entries, and then converts
2471  // the coordinate-format matrix data to CSR.
2472  {
2473  int mergeAndConvertSucceeded = 1;
2474  std::ostringstream errMsg;
2475 
2476  if (myRank == rootRank) {
2477  try {
2478  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
2479  global_ordinal_type> element_type;
2480 
2481  // Number of rows in the matrix. If we are in tolerant
2482  // mode, we've already synchronized dims with the actual
2483  // matrix data. If in strict mode, we should use dims
2484  // (as read from the file's metadata) rather than the
2485  // matrix data to determine the dimensions. (The matrix
2486  // data will claim fewer rows than the metadata, if one
2487  // or more rows have no entries stored in the file.)
2488  const size_type numRows = dims[0];
2489 
2490  // Additively merge duplicate matrix entries.
2491  pAdder->getAdder()->merge ();
2492 
2493  // Get a temporary const view of the merged matrix entries.
2494  const std::vector<element_type>& entries =
2495  pAdder->getAdder()->getEntries();
2496 
2497  // Number of matrix entries (after merging).
2498  const size_t numEntries = (size_t)entries.size();
2499 
2500  if (debug) {
2501  cerr << "----- Proc 0: Matrix has numRows=" << numRows
2502  << " rows and numEntries=" << numEntries
2503  << " entries." << endl;
2504  }
2505 
2506  // Make space for the CSR matrix data. Converting to
2507  // CSR is easier if we fill numEntriesPerRow with zeros
2508  // at first.
2509  numEntriesPerRow = arcp<size_t> (numRows);
2510  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
2511  rowPtr = arcp<size_t> (numRows+1);
2512  std::fill (rowPtr.begin(), rowPtr.end(), 0);
2513  colInd = arcp<global_ordinal_type> (numEntries);
2514  values = arcp<scalar_type> (numEntries);
2515 
2516  // Convert from array-of-structs coordinate format to CSR
2517  // (compressed sparse row) format.
2518  global_ordinal_type prvRow = 0;
2519  size_t curPos = 0;
2520  rowPtr[0] = 0;
2521  for (curPos = 0; curPos < numEntries; ++curPos) {
2522  const element_type& curEntry = entries[curPos];
2523  const global_ordinal_type curRow = curEntry.rowIndex();
2524  TEUCHOS_TEST_FOR_EXCEPTION(
2525  curRow < prvRow, std::logic_error,
2526  "Row indices are out of order, even though they are supposed "
2527  "to be sorted. curRow = " << curRow << ", prvRow = "
2528  << prvRow << ", at curPos = " << curPos << ". Please report "
2529  "this bug to the Tpetra developers.");
2530  if (curRow > prvRow) {
2531  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
2532  rowPtr[r] = curPos;
2533  }
2534  prvRow = curRow;
2535  }
2536  numEntriesPerRow[curRow]++;
2537  colInd[curPos] = curEntry.colIndex();
2538  values[curPos] = curEntry.value();
2539  }
2540  // rowPtr has one more entry than numEntriesPerRow. The
2541  // last entry of rowPtr is the number of entries in
2542  // colInd and values.
2543  rowPtr[numRows] = numEntries;
2544  } // Finished conversion to CSR format
2545  catch (std::exception& e) {
2546  mergeAndConvertSucceeded = 0;
2547  errMsg << "Failed to merge sparse matrix entries and convert to "
2548  "CSR format: " << e.what();
2549  }
2550 
2551  if (debug && mergeAndConvertSucceeded) {
2552  // Number of rows in the matrix.
2553  const size_type numRows = dims[0];
2554  const size_type maxToDisplay = 100;
2555 
2556  cerr << "----- Proc 0: numEntriesPerRow[0.."
2557  << (numEntriesPerRow.size()-1) << "] ";
2558  if (numRows > maxToDisplay) {
2559  cerr << "(only showing first and last few entries) ";
2560  }
2561  cerr << "= [";
2562  if (numRows > 0) {
2563  if (numRows > maxToDisplay) {
2564  for (size_type k = 0; k < 2; ++k) {
2565  cerr << numEntriesPerRow[k] << " ";
2566  }
2567  cerr << "... ";
2568  for (size_type k = numRows-2; k < numRows-1; ++k) {
2569  cerr << numEntriesPerRow[k] << " ";
2570  }
2571  }
2572  else {
2573  for (size_type k = 0; k < numRows-1; ++k) {
2574  cerr << numEntriesPerRow[k] << " ";
2575  }
2576  }
2577  cerr << numEntriesPerRow[numRows-1];
2578  } // numRows > 0
2579  cerr << "]" << endl;
2580 
2581  cerr << "----- Proc 0: rowPtr ";
2582  if (numRows > maxToDisplay) {
2583  cerr << "(only showing first and last few entries) ";
2584  }
2585  cerr << "= [";
2586  if (numRows > maxToDisplay) {
2587  for (size_type k = 0; k < 2; ++k) {
2588  cerr << rowPtr[k] << " ";
2589  }
2590  cerr << "... ";
2591  for (size_type k = numRows-2; k < numRows; ++k) {
2592  cerr << rowPtr[k] << " ";
2593  }
2594  }
2595  else {
2596  for (size_type k = 0; k < numRows; ++k) {
2597  cerr << rowPtr[k] << " ";
2598  }
2599  }
2600  cerr << rowPtr[numRows] << "]" << endl;
2601  }
2602  } // if myRank == rootRank
2603  } // Done converting sparse matrix data to CSR format
2604 
2605  // Now we're done with the Adder, so we can release the
2606  // reference ("free" it) to save space. This only actually
2607  // does anything on Rank 0, since pAdder is null on all the
2608  // other MPI processes.
2609  pAdder = null;
2610 
2611  if (debug && myRank == rootRank) {
2612  cerr << "-- Making range, domain, and row maps" << endl;
2613  }
2614 
2615  // Make the maps that describe the matrix's range and domain,
2616  // and the distribution of its rows. Creating a Map is a
2617  // collective operation, so we don't have to do a broadcast of
2618  // a success Boolean.
2619  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
2620  RCP<const map_type> pDomainMap =
2621  makeDomainMap (pRangeMap, dims[0], dims[1]);
2622  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
2623 
2624  if (debug && myRank == rootRank) {
2625  cerr << "-- Distributing the matrix data" << endl;
2626  }
2627 
2628  // Distribute the matrix data. Each processor has to add the
2629  // rows that it owns. If you try to make Proc 0 call
2630  // insertGlobalValues() for _all_ the rows, not just those it
2631  // owns, then fillComplete() will compute the number of
2632  // columns incorrectly. That's why Proc 0 has to distribute
2633  // the matrix data and why we make all the processors (not
2634  // just Proc 0) call insertGlobalValues() on their own data.
2635  //
2636  // These arrays represent each processor's part of the matrix
2637  // data, in "CSR" format (sort of, since the row indices might
2638  // not be contiguous).
2639  ArrayRCP<size_t> myNumEntriesPerRow;
2640  ArrayRCP<size_t> myRowPtr;
2641  ArrayRCP<global_ordinal_type> myColInd;
2642  ArrayRCP<scalar_type> myValues;
2643  // Distribute the matrix data. This is a collective operation.
2644  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
2645  numEntriesPerRow, rowPtr, colInd, values, debug);
2646 
2647  if (debug && myRank == rootRank) {
2648  cerr << "-- Inserting matrix entries on each processor";
2649  if (callFillComplete) {
2650  cerr << " and calling fillComplete()";
2651  }
2652  cerr << endl;
2653  }
2654  // Each processor inserts its part of the matrix data, and
2655  // then they all call fillComplete(). This method invalidates
2656  // the my* distributed matrix data before calling
2657  // fillComplete(), in order to save space. In general, we
2658  // never store more than two copies of the matrix's entries in
2659  // memory at once, which is no worse than what Tpetra
2660  // promises.
2661  RCP<sparse_matrix_type> pMatrix =
2662  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
2663  pRowMap, pRangeMap, pDomainMap, callFillComplete);
2664  // Only use a reduce-all in debug mode to check if pMatrix is
2665  // null. Otherwise, just throw an exception. We never expect
2666  // a null pointer here, so we can save a communication.
2667  if (debug) {
2668  int localIsNull = pMatrix.is_null () ? 1 : 0;
2669  int globalIsNull = 0;
2670  reduceAll (*pComm, REDUCE_MAX, localIsNull, ptr (&globalIsNull));
2671  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
2672  "Reader::makeMatrix() returned a null pointer on at least one "
2673  "process. Please report this bug to the Tpetra developers.");
2674  }
2675  else {
2676  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
2677  "Reader::makeMatrix() returned a null pointer. "
2678  "Please report this bug to the Tpetra developers.");
2679  }
2680 
2681  // We can't get the dimensions of the matrix until after
2682  // fillComplete() is called. Thus, we can't do the sanity
2683  // check (dimensions read from the Matrix Market data,
2684  // vs. dimensions reported by the CrsMatrix) unless the user
2685  // asked makeMatrix() to call fillComplete().
2686  //
2687  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
2688  // what one might think it does, so you have to ask the range
2689  // resp. domain map for the number of rows resp. columns.
2690  if (callFillComplete) {
2691  const int numProcs = pComm->getSize ();
2692 
2693  if (extraDebug && debug) {
2694  const global_size_t globalNumRows =
2695  pRangeMap->getGlobalNumElements ();
2696  const global_size_t globalNumCols =
2697  pDomainMap->getGlobalNumElements ();
2698  if (myRank == rootRank) {
2699  cerr << "-- Matrix is "
2700  << globalNumRows << " x " << globalNumCols
2701  << " with " << pMatrix->getGlobalNumEntries()
2702  << " entries, and index base "
2703  << pMatrix->getIndexBase() << "." << endl;
2704  }
2705  pComm->barrier ();
2706  for (int p = 0; p < numProcs; ++p) {
2707  if (myRank == p) {
2708  cerr << "-- Proc " << p << " owns "
2709  << pMatrix->getNodeNumCols() << " columns, and "
2710  << pMatrix->getNodeNumEntries() << " entries." << endl;
2711  }
2712  pComm->barrier ();
2713  }
2714  } // if (extraDebug && debug)
2715  } // if (callFillComplete)
2716 
2717  if (debug && myRank == rootRank) {
2718  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
2719  << endl;
2720  }
2721  return pMatrix;
2722  }
2723 
2724 
2753  static Teuchos::RCP<sparse_matrix_type>
2754  readSparse (std::istream& in,
2755  const Teuchos::RCP<const Teuchos::Comm<int> >& pComm,
2756  const Teuchos::RCP<Teuchos::ParameterList>& constructorParams,
2757  const Teuchos::RCP<Teuchos::ParameterList>& fillCompleteParams,
2758  const bool tolerant=false,
2759  const bool debug=false)
2760  {
2761  using Teuchos::MatrixMarket::Banner;
2762  using Teuchos::arcp;
2763  using Teuchos::ArrayRCP;
2764  using Teuchos::broadcast;
2765  using Teuchos::null;
2766  using Teuchos::ptr;
2767  using Teuchos::RCP;
2768  using Teuchos::reduceAll;
2769  using Teuchos::Tuple;
2770  using std::cerr;
2771  using std::endl;
2772  typedef Teuchos::ScalarTraits<scalar_type> STS;
2773 
2774  const bool extraDebug = false;
2775  const int myRank = pComm->getRank ();
2776  const int rootRank = 0;
2777 
2778  // Current line number in the input stream. Various calls
2779  // will modify this depending on the number of lines that are
2780  // read from the input stream. Only Rank 0 modifies this.
2781  size_t lineNumber = 1;
2782 
2783  if (debug && myRank == rootRank) {
2784  cerr << "Matrix Market reader: readSparse:" << endl
2785  << "-- Reading banner line" << endl;
2786  }
2787 
2788  // The "Banner" tells you whether the input stream represents
2789  // a sparse matrix, the symmetry type of the matrix, and the
2790  // type of the data it contains.
2791  //
2792  // pBanner will only be nonnull on MPI Rank 0. It will be
2793  // null on all other MPI processes.
2794  RCP<const Banner> pBanner;
2795  {
2796  // We read and validate the Banner on Proc 0, but broadcast
2797  // the validation result to all processes.
2798  // Teuchos::broadcast doesn't currently work with bool, so
2799  // we use int (true -> 1, false -> 0).
2800  int bannerIsCorrect = 1;
2801  std::ostringstream errMsg;
2802 
2803  if (myRank == rootRank) {
2804  // Read the Banner line from the input stream.
2805  try {
2806  pBanner = readBanner (in, lineNumber, tolerant, debug);
2807  }
2808  catch (std::exception& e) {
2809  errMsg << "Attempt to read the Matrix Market file's Banner line "
2810  "threw an exception: " << e.what();
2811  bannerIsCorrect = 0;
2812  }
2813 
2814  if (bannerIsCorrect) {
2815  // Validate the Banner for the case of a sparse matrix.
2816  // We validate on Proc 0, since it reads the Banner.
2817 
2818  // In intolerant mode, the matrix type must be "coordinate".
2819  if (! tolerant && pBanner->matrixType() != "coordinate") {
2820  bannerIsCorrect = 0;
2821  errMsg << "The Matrix Market input file must contain a "
2822  "\"coordinate\"-format sparse matrix in order to create a "
2823  "Tpetra::CrsMatrix object from it, but the file's matrix "
2824  "type is \"" << pBanner->matrixType() << "\" instead.";
2825  }
2826  // In tolerant mode, we allow the matrix type to be
2827  // anything other than "array" (which would mean that
2828  // the file contains a dense matrix).
2829  if (tolerant && pBanner->matrixType() == "array") {
2830  bannerIsCorrect = 0;
2831  errMsg << "Matrix Market file must contain a \"coordinate\"-"
2832  "format sparse matrix in order to create a Tpetra::CrsMatrix "
2833  "object from it, but the file's matrix type is \"array\" "
2834  "instead. That probably means the file contains dense matrix "
2835  "data.";
2836  }
2837  }
2838  } // Proc 0: Done reading the Banner, hopefully successfully.
2839 
2840  // Broadcast from Proc 0 whether the Banner was read correctly.
2841  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
2842 
2843  // If the Banner is invalid, all processes throw an
2844  // exception. Only Proc 0 gets the exception message, but
2845  // that's OK, since the main point is to "stop the world"
2846  // (rather than throw an exception on one process and leave
2847  // the others hanging).
2848  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
2849  std::invalid_argument, errMsg.str ());
2850  } // Done reading the Banner line and broadcasting success.
2851  if (debug && myRank == rootRank) {
2852  cerr << "-- Reading dimensions line" << endl;
2853  }
2854 
2855  // Read the matrix dimensions from the Matrix Market metadata.
2856  // dims = (numRows, numCols, numEntries). Proc 0 does the
2857  // reading, but it broadcasts the results to all MPI
2858  // processes. Thus, readCoordDims() is a collective
2859  // operation. It does a collective check for correctness too.
2860  Tuple<global_ordinal_type, 3> dims =
2861  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
2862 
2863  if (debug && myRank == rootRank) {
2864  cerr << "-- Making Adder for collecting matrix data" << endl;
2865  }
2866 
2867  // "Adder" object for collecting all the sparse matrix entries
2868  // from the input stream. This is only nonnull on Proc 0.
2869  RCP<adder_type> pAdder =
2870  makeAdder (pComm, pBanner, dims, tolerant, debug);
2871 
2872  if (debug && myRank == rootRank) {
2873  cerr << "-- Reading matrix data" << endl;
2874  }
2875  //
2876  // Read the matrix entries from the input stream on Proc 0.
2877  //
2878  {
2879  // We use readSuccess to broadcast the results of the read
2880  // (succeeded or not) to all MPI processes. Since
2881  // Teuchos::broadcast doesn't currently know how to send
2882  // bools, we convert to int (true -> 1, false -> 0).
2883  int readSuccess = 1;
2884  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
2885  if (myRank == rootRank) {
2886  try {
2887  // Reader for "coordinate" format sparse matrix data.
2888  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
2889  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
2890  reader_type reader (pAdder);
2891 
2892  // Read the sparse matrix entries.
2893  std::pair<bool, std::vector<size_t> > results =
2894  reader.read (in, lineNumber, tolerant, debug);
2895  readSuccess = results.first ? 1 : 0;
2896  }
2897  catch (std::exception& e) {
2898  readSuccess = 0;
2899  errMsg << e.what();
2900  }
2901  }
2902  broadcast (*pComm, rootRank, ptr (&readSuccess));
2903 
2904  // It would be nice to add a "verbose" flag, so that in
2905  // tolerant mode, we could log any bad line number(s) on
2906  // Proc 0. For now, we just throw if the read fails to
2907  // succeed.
2908  //
2909  // Question: If we're in tolerant mode, and if the read did
2910  // not succeed, should we attempt to call fillComplete()?
2911  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
2912  "Failed to read the Matrix Market sparse matrix file: "
2913  << errMsg.str());
2914  } // Done reading the matrix entries (stored on Proc 0 for now)
2915 
2916  if (debug && myRank == rootRank) {
2917  cerr << "-- Successfully read the Matrix Market data" << endl;
2918  }
2919 
2920  // In tolerant mode, we need to rebroadcast the matrix
2921  // dimensions, since they may be different after reading the
2922  // actual matrix data. We only need to broadcast the number
2923  // of rows and columns. Only Rank 0 needs to know the actual
2924  // global number of entries, since (a) we need to merge
2925  // duplicates on Rank 0 first anyway, and (b) when we
2926  // distribute the entries, each rank other than Rank 0 will
2927  // only need to know how many entries it owns, not the total
2928  // number of entries.
2929  if (tolerant) {
2930  if (debug && myRank == rootRank) {
2931  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
2932  << endl
2933  << "----- Dimensions before: "
2934  << dims[0] << " x " << dims[1]
2935  << endl;
2936  }
2937  // Packed coordinate matrix dimensions (numRows, numCols).
2938  Tuple<global_ordinal_type, 2> updatedDims;
2939  if (myRank == rootRank) {
2940  // If one or more bottom rows of the matrix contain no
2941  // entries, then the Adder will report that the number
2942  // of rows is less than that specified in the
2943  // metadata. We allow this case, and favor the
2944  // metadata so that the zero row(s) will be included.
2945  updatedDims[0] =
2946  std::max (dims[0], pAdder->getAdder()->numRows());
2947  updatedDims[1] = pAdder->getAdder()->numCols();
2948  }
2949  broadcast (*pComm, rootRank, updatedDims);
2950  dims[0] = updatedDims[0];
2951  dims[1] = updatedDims[1];
2952  if (debug && myRank == rootRank) {
2953  cerr << "----- Dimensions after: " << dims[0] << " x "
2954  << dims[1] << endl;
2955  }
2956  }
2957  else {
2958  // In strict mode, we require that the matrix's metadata and
2959  // its actual data agree, at least somewhat. In particular,
2960  // the number of rows must agree, since otherwise we cannot
2961  // distribute the matrix correctly.
2962 
2963  // Teuchos::broadcast() doesn't know how to broadcast bools,
2964  // so we use an int with the standard 1 == true, 0 == false
2965  // encoding.
2966  int dimsMatch = 1;
2967  if (myRank == rootRank) {
2968  // If one or more bottom rows of the matrix contain no
2969  // entries, then the Adder will report that the number of
2970  // rows is less than that specified in the metadata. We
2971  // allow this case, and favor the metadata, but do not
2972  // allow the Adder to think there are more rows in the
2973  // matrix than the metadata says.
2974  if (dims[0] < pAdder->getAdder ()->numRows ()) {
2975  dimsMatch = 0;
2976  }
2977  }
2978  broadcast (*pComm, 0, ptr (&dimsMatch));
2979  if (dimsMatch == 0) {
2980  // We're in an error state anyway, so we might as well
2981  // work a little harder to print an informative error
2982  // message.
2983  //
2984  // Broadcast the Adder's idea of the matrix dimensions
2985  // from Proc 0 to all processes.
2986  Tuple<global_ordinal_type, 2> addersDims;
2987  if (myRank == rootRank) {
2988  addersDims[0] = pAdder->getAdder()->numRows();
2989  addersDims[1] = pAdder->getAdder()->numCols();
2990  }
2991  broadcast (*pComm, 0, addersDims);
2992  TEUCHOS_TEST_FOR_EXCEPTION(
2993  dimsMatch == 0, std::runtime_error,
2994  "The matrix metadata says that the matrix is " << dims[0] << " x "
2995  << dims[1] << ", but the actual data says that the matrix is "
2996  << addersDims[0] << " x " << addersDims[1] << ". That means the "
2997  "data includes more rows than reported in the metadata. This "
2998  "is not allowed when parsing in strict mode. Parse the matrix in "
2999  "tolerant mode to ignore the metadata when it disagrees with the "
3000  "data.");
3001  }
3002  } // Matrix dimensions (# rows, # cols, # entries) agree.
3003 
3004  if (debug && myRank == rootRank) {
3005  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3006  }
3007 
3008  // Now that we've read in all the matrix entries from the
3009  // input stream into the adder on Proc 0, post-process them
3010  // into CSR format (still on Proc 0). This will facilitate
3011  // distributing them to all the processors.
3012  //
3013  // These arrays represent the global matrix data as a CSR
3014  // matrix (with numEntriesPerRow as redundant but convenient
3015  // metadata, since it's computable from rowPtr and vice
3016  // versa). They are valid only on Proc 0.
3017  ArrayRCP<size_t> numEntriesPerRow;
3018  ArrayRCP<size_t> rowPtr;
3019  ArrayRCP<global_ordinal_type> colInd;
3020  ArrayRCP<scalar_type> values;
3021 
3022  // Proc 0 first merges duplicate entries, and then converts
3023  // the coordinate-format matrix data to CSR.
3024  {
3025  int mergeAndConvertSucceeded = 1;
3026  std::ostringstream errMsg;
3027 
3028  if (myRank == rootRank) {
3029  try {
3030  typedef Teuchos::MatrixMarket::Raw::Element<scalar_type,
3031  global_ordinal_type> element_type;
3032 
3033  // Number of rows in the matrix. If we are in tolerant
3034  // mode, we've already synchronized dims with the actual
3035  // matrix data. If in strict mode, we should use dims
3036  // (as read from the file's metadata) rather than the
3037  // matrix data to determine the dimensions. (The matrix
3038  // data will claim fewer rows than the metadata, if one
3039  // or more rows have no entries stored in the file.)
3040  const size_type numRows = dims[0];
3041 
3042  // Additively merge duplicate matrix entries.
3043  pAdder->getAdder()->merge ();
3044 
3045  // Get a temporary const view of the merged matrix entries.
3046  const std::vector<element_type>& entries =
3047  pAdder->getAdder()->getEntries();
3048 
3049  // Number of matrix entries (after merging).
3050  const size_t numEntries = (size_t)entries.size();
3051 
3052  if (debug) {
3053  cerr << "----- Proc 0: Matrix has numRows=" << numRows
3054  << " rows and numEntries=" << numEntries
3055  << " entries." << endl;
3056  }
3057 
3058  // Make space for the CSR matrix data. Converting to
3059  // CSR is easier if we fill numEntriesPerRow with zeros
3060  // at first.
3061  numEntriesPerRow = arcp<size_t> (numRows);
3062  std::fill (numEntriesPerRow.begin(), numEntriesPerRow.end(), 0);
3063  rowPtr = arcp<size_t> (numRows+1);
3064  std::fill (rowPtr.begin(), rowPtr.end(), 0);
3065  colInd = arcp<global_ordinal_type> (numEntries);
3066  values = arcp<scalar_type> (numEntries);
3067 
3068  // Convert from array-of-structs coordinate format to CSR
3069  // (compressed sparse row) format.
3070  global_ordinal_type prvRow = 0;
3071  size_t curPos = 0;
3072  rowPtr[0] = 0;
3073  for (curPos = 0; curPos < numEntries; ++curPos) {
3074  const element_type& curEntry = entries[curPos];
3075  const global_ordinal_type curRow = curEntry.rowIndex();
3076  TEUCHOS_TEST_FOR_EXCEPTION(
3077  curRow < prvRow, std::logic_error,
3078  "Row indices are out of order, even though they are supposed "
3079  "to be sorted. curRow = " << curRow << ", prvRow = "
3080  << prvRow << ", at curPos = " << curPos << ". Please report "
3081  "this bug to the Tpetra developers.");
3082  if (curRow > prvRow) {
3083  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3084  rowPtr[r] = curPos;
3085  }
3086  prvRow = curRow;
3087  }
3088  numEntriesPerRow[curRow]++;
3089  colInd[curPos] = curEntry.colIndex();
3090  values[curPos] = curEntry.value();
3091  }
3092  // rowPtr has one more entry than numEntriesPerRow. The
3093  // last entry of rowPtr is the number of entries in
3094  // colInd and values.
3095  rowPtr[numRows] = numEntries;
3096  } // Finished conversion to CSR format
3097  catch (std::exception& e) {
3098  mergeAndConvertSucceeded = 0;
3099  errMsg << "Failed to merge sparse matrix entries and convert to "
3100  "CSR format: " << e.what();
3101  }
3102 
3103  if (debug && mergeAndConvertSucceeded) {
3104  // Number of rows in the matrix.
3105  const size_type numRows = dims[0];
3106  const size_type maxToDisplay = 100;
3107 
3108  cerr << "----- Proc 0: numEntriesPerRow[0.."
3109  << (numEntriesPerRow.size()-1) << "] ";
3110  if (numRows > maxToDisplay) {
3111  cerr << "(only showing first and last few entries) ";
3112  }
3113  cerr << "= [";
3114  if (numRows > 0) {
3115  if (numRows > maxToDisplay) {
3116  for (size_type k = 0; k < 2; ++k) {
3117  cerr << numEntriesPerRow[k] << " ";
3118  }
3119  cerr << "... ";
3120  for (size_type k = numRows-2; k < numRows-1; ++k) {
3121  cerr << numEntriesPerRow[k] << " ";
3122  }
3123  }
3124  else {
3125  for (size_type k = 0; k < numRows-1; ++k) {
3126  cerr << numEntriesPerRow[k] << " ";
3127  }
3128  }
3129  cerr << numEntriesPerRow[numRows-1];
3130  } // numRows > 0
3131  cerr << "]" << endl;
3132 
3133  cerr << "----- Proc 0: rowPtr ";
3134  if (numRows > maxToDisplay) {
3135  cerr << "(only showing first and last few entries) ";
3136  }
3137  cerr << "= [";
3138  if (numRows > maxToDisplay) {
3139  for (size_type k = 0; k < 2; ++k) {
3140  cerr << rowPtr[k] << " ";
3141  }
3142  cerr << "... ";
3143  for (size_type k = numRows-2; k < numRows; ++k) {
3144  cerr << rowPtr[k] << " ";
3145  }
3146  }
3147  else {
3148  for (size_type k = 0; k < numRows; ++k) {
3149  cerr << rowPtr[k] << " ";
3150  }
3151  }
3152  cerr << rowPtr[numRows] << "]" << endl;
3153  }
3154  } // if myRank == rootRank
3155  } // Done converting sparse matrix data to CSR format
3156 
3157  // Now we're done with the Adder, so we can release the
3158  // reference ("free" it) to save space. This only actually
3159  // does anything on Rank 0, since pAdder is null on all the
3160  // other MPI processes.
3161  pAdder = null;
3162 
3163  if (debug && myRank == rootRank) {
3164  cerr << "-- Making range, domain, and row maps" << endl;
3165  }
3166 
3167  // Make the maps that describe the matrix's range and domain,
3168  // and the distribution of its rows. Creating a Map is a
3169  // collective operation, so we don't have to do a broadcast of
3170  // a success Boolean.
3171  RCP<const map_type> pRangeMap = makeRangeMap (pComm, dims[0]);
3172  RCP<const map_type> pDomainMap =
3173  makeDomainMap (pRangeMap, dims[0], dims[1]);
3174  RCP<const map_type> pRowMap = makeRowMap (null, pComm, dims[0]);
3175 
3176  if (debug && myRank == rootRank) {
3177  cerr << "-- Distributing the matrix data" << endl;
3178  }
3179 
3180  // Distribute the matrix data. Each processor has to add the
3181  // rows that it owns. If you try to make Proc 0 call
3182  // insertGlobalValues() for _all_ the rows, not just those it
3183  // owns, then fillComplete() will compute the number of
3184  // columns incorrectly. That's why Proc 0 has to distribute
3185  // the matrix data and why we make all the processors (not
3186  // just Proc 0) call insertGlobalValues() on their own data.
3187  //
3188  // These arrays represent each processor's part of the matrix
3189  // data, in "CSR" format (sort of, since the row indices might
3190  // not be contiguous).
3191  ArrayRCP<size_t> myNumEntriesPerRow;
3192  ArrayRCP<size_t> myRowPtr;
3193  ArrayRCP<global_ordinal_type> myColInd;
3194  ArrayRCP<scalar_type> myValues;
3195  // Distribute the matrix data. This is a collective operation.
3196  distribute (myNumEntriesPerRow, myRowPtr, myColInd, myValues, pRowMap,
3197  numEntriesPerRow, rowPtr, colInd, values, debug);
3198 
3199  if (debug && myRank == rootRank) {
3200  cerr << "-- Inserting matrix entries on each process "
3201  "and calling fillComplete()" << endl;
3202  }
3203  // Each processor inserts its part of the matrix data, and
3204  // then they all call fillComplete(). This method invalidates
3205  // the my* distributed matrix data before calling
3206  // fillComplete(), in order to save space. In general, we
3207  // never store more than two copies of the matrix's entries in
3208  // memory at once, which is no worse than what Tpetra
3209  // promises.
3210  Teuchos::RCP<sparse_matrix_type> pMatrix =
3211  makeMatrix (myNumEntriesPerRow, myRowPtr, myColInd, myValues,
3212  pRowMap, pRangeMap, pDomainMap, constructorParams,
3213  fillCompleteParams);
3214  // Only use a reduce-all in debug mode to check if pMatrix is
3215  // null. Otherwise, just throw an exception. We never expect
3216  // a null pointer here, so we can save a communication.
3217  if (debug) {
3218  int localIsNull = pMatrix.is_null () ? 1 : 0;
3219  int globalIsNull = 0;
3220  reduceAll (*pComm, Teuchos::REDUCE_MAX, localIsNull, ptr (&globalIsNull));
3221  TEUCHOS_TEST_FOR_EXCEPTION(globalIsNull != 0, std::logic_error,
3222  "Reader::makeMatrix() returned a null pointer on at least one "
3223  "process. Please report this bug to the Tpetra developers.");
3224  }
3225  else {
3226  TEUCHOS_TEST_FOR_EXCEPTION(pMatrix.is_null(), std::logic_error,
3227  "Reader::makeMatrix() returned a null pointer. "
3228  "Please report this bug to the Tpetra developers.");
3229  }
3230 
3231  // Sanity check for dimensions (read from the Matrix Market
3232  // data, vs. dimensions reported by the CrsMatrix).
3233  //
3234  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3235  // what one might think it does, so you have to ask the range
3236  // resp. domain map for the number of rows resp. columns.
3237  if (extraDebug && debug) {
3238  const int numProcs = pComm->getSize ();
3239  const global_size_t globalNumRows =
3240  pRangeMap->getGlobalNumElements();
3241  const global_size_t globalNumCols =
3242  pDomainMap->getGlobalNumElements();
3243  if (myRank == rootRank) {
3244  cerr << "-- Matrix is "
3245  << globalNumRows << " x " << globalNumCols
3246  << " with " << pMatrix->getGlobalNumEntries()
3247  << " entries, and index base "
3248  << pMatrix->getIndexBase() << "." << endl;
3249  }
3250  pComm->barrier ();
3251  for (int p = 0; p < numProcs; ++p) {
3252  if (myRank == p) {
3253  cerr << "-- Proc " << p << " owns "
3254  << pMatrix->getNodeNumCols() << " columns, and "
3255  << pMatrix->getNodeNumEntries() << " entries." << endl;
3256  }
3257  pComm->barrier ();
3258  }
3259  } // if (extraDebug && debug)
3260 
3261  if (debug && myRank == rootRank) {
3262  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3263  << endl;
3264  }
3265  return pMatrix;
3266  }
3267 
3268 
3309  static Teuchos::RCP<sparse_matrix_type>
3310  readSparse (std::istream& in,
3311  const Teuchos::RCP<const map_type>& rowMap,
3312  Teuchos::RCP<const map_type>& colMap,
3313  const Teuchos::RCP<const map_type>& domainMap,
3314  const Teuchos::RCP<const map_type>& rangeMap,
3315  const bool callFillComplete=true,
3316  const bool tolerant=false,
3317  const bool debug=false)
3318  {
3319  using Teuchos::MatrixMarket::Banner;
3320  using Teuchos::arcp;
3321  using Teuchos::ArrayRCP;
3322  using Teuchos::ArrayView;
3323  using Teuchos::as;
3324  using Teuchos::broadcast;
3325  using Teuchos::Comm;
3326  using Teuchos::null;
3327  using Teuchos::ptr;
3328  using Teuchos::RCP;
3329  using Teuchos::reduceAll;
3330  using Teuchos::Tuple;
3331  using std::cerr;
3332  using std::endl;
3333  typedef Teuchos::ScalarTraits<scalar_type> STS;
3334 
3335  RCP<const Comm<int> > pComm = rowMap->getComm ();
3336  const int myRank = pComm->getRank ();
3337  const int rootRank = 0;
3338  const bool extraDebug = false;
3339 
3340  // Fast checks for invalid input. We can't check other
3341  // attributes of the Maps until we've read in the matrix
3342  // dimensions.
3343  TEUCHOS_TEST_FOR_EXCEPTION(
3344  rowMap.is_null (), std::invalid_argument,
3345  "Row Map must be nonnull.");
3346  TEUCHOS_TEST_FOR_EXCEPTION(
3347  rangeMap.is_null (), std::invalid_argument,
3348  "Range Map must be nonnull.");
3349  TEUCHOS_TEST_FOR_EXCEPTION(
3350  domainMap.is_null (), std::invalid_argument,
3351  "Domain Map must be nonnull.");
3352  TEUCHOS_TEST_FOR_EXCEPTION(
3353  rowMap->getComm().getRawPtr() != pComm.getRawPtr(),
3354  std::invalid_argument,
3355  "The specified row Map's communicator (rowMap->getComm())"
3356  "differs from the given separately supplied communicator pComm.");
3357  TEUCHOS_TEST_FOR_EXCEPTION(
3358  domainMap->getComm().getRawPtr() != pComm.getRawPtr(),
3359  std::invalid_argument,
3360  "The specified domain Map's communicator (domainMap->getComm())"
3361  "differs from the given separately supplied communicator pComm.");
3362  TEUCHOS_TEST_FOR_EXCEPTION(
3363  rangeMap->getComm().getRawPtr() != pComm.getRawPtr(),
3364  std::invalid_argument,
3365  "The specified range Map's communicator (rangeMap->getComm())"
3366  "differs from the given separately supplied communicator pComm.");
3367 
3368  // Current line number in the input stream. Various calls
3369  // will modify this depending on the number of lines that are
3370  // read from the input stream. Only Rank 0 modifies this.
3371  size_t lineNumber = 1;
3372 
3373  if (debug && myRank == rootRank) {
3374  cerr << "Matrix Market reader: readSparse:" << endl
3375  << "-- Reading banner line" << endl;
3376  }
3377 
3378  // The "Banner" tells you whether the input stream represents
3379  // a sparse matrix, the symmetry type of the matrix, and the
3380  // type of the data it contains.
3381  //
3382  // pBanner will only be nonnull on MPI Rank 0. It will be
3383  // null on all other MPI processes.
3384  RCP<const Banner> pBanner;
3385  {
3386  // We read and validate the Banner on Proc 0, but broadcast
3387  // the validation result to all processes.
3388  // Teuchos::broadcast doesn't currently work with bool, so
3389  // we use int (true -> 1, false -> 0).
3390  int bannerIsCorrect = 1;
3391  std::ostringstream errMsg;
3392 
3393  if (myRank == rootRank) {
3394  // Read the Banner line from the input stream.
3395  try {
3396  pBanner = readBanner (in, lineNumber, tolerant, debug);
3397  }
3398  catch (std::exception& e) {
3399  errMsg << "Attempt to read the Matrix Market file's Banner line "
3400  "threw an exception: " << e.what();
3401  bannerIsCorrect = 0;
3402  }
3403 
3404  if (bannerIsCorrect) {
3405  // Validate the Banner for the case of a sparse matrix.
3406  // We validate on Proc 0, since it reads the Banner.
3407 
3408  // In intolerant mode, the matrix type must be "coordinate".
3409  if (! tolerant && pBanner->matrixType() != "coordinate") {
3410  bannerIsCorrect = 0;
3411  errMsg << "The Matrix Market input file must contain a "
3412  "\"coordinate\"-format sparse matrix in order to create a "
3413  "Tpetra::CrsMatrix object from it, but the file's matrix "
3414  "type is \"" << pBanner->matrixType() << "\" instead.";
3415  }
3416  // In tolerant mode, we allow the matrix type to be
3417  // anything other than "array" (which would mean that
3418  // the file contains a dense matrix).
3419  if (tolerant && pBanner->matrixType() == "array") {
3420  bannerIsCorrect = 0;
3421  errMsg << "Matrix Market file must contain a \"coordinate\"-"
3422  "format sparse matrix in order to create a Tpetra::CrsMatrix "
3423  "object from it, but the file's matrix type is \"array\" "
3424  "instead. That probably means the file contains dense matrix "
3425  "data.";
3426  }
3427  }
3428  } // Proc 0: Done reading the Banner, hopefully successfully.
3429 
3430  // Broadcast from Proc 0 whether the Banner was read correctly.
3431  broadcast (*pComm, rootRank, ptr (&bannerIsCorrect));
3432 
3433  // If the Banner is invalid, all processes throw an
3434  // exception. Only Proc 0 gets the exception message, but
3435  // that's OK, since the main point is to "stop the world"
3436  // (rather than throw an exception on one process and leave
3437  // the others hanging).
3438  TEUCHOS_TEST_FOR_EXCEPTION(bannerIsCorrect == 0,
3439  std::invalid_argument, errMsg.str ());
3440  } // Done reading the Banner line and broadcasting success.
3441  if (debug && myRank == rootRank) {
3442  cerr << "-- Reading dimensions line" << endl;
3443  }
3444 
3445  // Read the matrix dimensions from the Matrix Market metadata.
3446  // dims = (numRows, numCols, numEntries). Proc 0 does the
3447  // reading, but it broadcasts the results to all MPI
3448  // processes. Thus, readCoordDims() is a collective
3449  // operation. It does a collective check for correctness too.
3450  Tuple<global_ordinal_type, 3> dims =
3451  readCoordDims (in, lineNumber, pBanner, pComm, tolerant, debug);
3452 
3453  if (debug && myRank == rootRank) {
3454  cerr << "-- Making Adder for collecting matrix data" << endl;
3455  }
3456 
3457  // "Adder" object for collecting all the sparse matrix entries
3458  // from the input stream. This is only nonnull on Proc 0.
3459  // The Adder internally converts the one-based indices (native
3460  // Matrix Market format) into zero-based indices.
3461  RCP<adder_type> pAdder =
3462  makeAdder (pComm, pBanner, dims, tolerant, debug);
3463 
3464  if (debug && myRank == rootRank) {
3465  cerr << "-- Reading matrix data" << endl;
3466  }
3467  //
3468  // Read the matrix entries from the input stream on Proc 0.
3469  //
3470  {
3471  // We use readSuccess to broadcast the results of the read
3472  // (succeeded or not) to all MPI processes. Since
3473  // Teuchos::broadcast doesn't currently know how to send
3474  // bools, we convert to int (true -> 1, false -> 0).
3475  int readSuccess = 1;
3476  std::ostringstream errMsg; // Exception message (only valid on Proc 0)
3477  if (myRank == rootRank) {
3478  try {
3479  // Reader for "coordinate" format sparse matrix data.
3480  typedef Teuchos::MatrixMarket::CoordDataReader<adder_type,
3481  global_ordinal_type, scalar_type, STS::isComplex> reader_type;
3482  reader_type reader (pAdder);
3483 
3484  // Read the sparse matrix entries.
3485  std::pair<bool, std::vector<size_t> > results =
3486  reader.read (in, lineNumber, tolerant, debug);
3487  readSuccess = results.first ? 1 : 0;
3488  }
3489  catch (std::exception& e) {
3490  readSuccess = 0;
3491  errMsg << e.what();
3492  }
3493  }
3494  broadcast (*pComm, rootRank, ptr (&readSuccess));
3495 
3496  // It would be nice to add a "verbose" flag, so that in
3497  // tolerant mode, we could log any bad line number(s) on
3498  // Proc 0. For now, we just throw if the read fails to
3499  // succeed.
3500  //
3501  // Question: If we're in tolerant mode, and if the read did
3502  // not succeed, should we attempt to call fillComplete()?
3503  TEUCHOS_TEST_FOR_EXCEPTION(readSuccess == 0, std::runtime_error,
3504  "Failed to read the Matrix Market sparse matrix file: "
3505  << errMsg.str());
3506  } // Done reading the matrix entries (stored on Proc 0 for now)
3507 
3508  if (debug && myRank == rootRank) {
3509  cerr << "-- Successfully read the Matrix Market data" << endl;
3510  }
3511 
3512  // In tolerant mode, we need to rebroadcast the matrix
3513  // dimensions, since they may be different after reading the
3514  // actual matrix data. We only need to broadcast the number
3515  // of rows and columns. Only Rank 0 needs to know the actual
3516  // global number of entries, since (a) we need to merge
3517  // duplicates on Rank 0 first anyway, and (b) when we
3518  // distribute the entries, each rank other than Rank 0 will
3519  // only need to know how many entries it owns, not the total
3520  // number of entries.
3521  if (tolerant) {
3522  if (debug && myRank == rootRank) {
3523  cerr << "-- Tolerant mode: rebroadcasting matrix dimensions"
3524  << endl
3525  << "----- Dimensions before: "
3526  << dims[0] << " x " << dims[1]
3527  << endl;
3528  }
3529  // Packed coordinate matrix dimensions (numRows, numCols).
3530  Tuple<global_ordinal_type, 2> updatedDims;
3531  if (myRank == rootRank) {
3532  // If one or more bottom rows of the matrix contain no
3533  // entries, then the Adder will report that the number
3534  // of rows is less than that specified in the
3535  // metadata. We allow this case, and favor the
3536  // metadata so that the zero row(s) will be included.
3537  updatedDims[0] =
3538  std::max (dims[0], pAdder->getAdder()->numRows());
3539  updatedDims[1] = pAdder->getAdder()->numCols();
3540  }
3541  broadcast (*pComm, rootRank, updatedDims);
3542  dims[0] = updatedDims[0];
3543  dims[1] = updatedDims[1];
3544  if (debug && myRank == rootRank) {
3545  cerr << "----- Dimensions after: " << dims[0] << " x "
3546  << dims[1] << endl;
3547  }
3548  }
3549  else {
3550  // In strict mode, we require that the matrix's metadata and
3551  // its actual data agree, at least somewhat. In particular,
3552  // the number of rows must agree, since otherwise we cannot
3553  // distribute the matrix correctly.
3554 
3555  // Teuchos::broadcast() doesn't know how to broadcast bools,
3556  // so we use an int with the standard 1 == true, 0 == false
3557  // encoding.
3558  int dimsMatch = 1;
3559  if (myRank == rootRank) {
3560  // If one or more bottom rows of the matrix contain no
3561  // entries, then the Adder will report that the number of
3562  // rows is less than that specified in the metadata. We
3563  // allow this case, and favor the metadata, but do not
3564  // allow the Adder to think there are more rows in the
3565  // matrix than the metadata says.
3566  if (dims[0] < pAdder->getAdder ()->numRows ()) {
3567  dimsMatch = 0;
3568  }
3569  }
3570  broadcast (*pComm, 0, ptr (&dimsMatch));
3571  if (dimsMatch == 0) {
3572  // We're in an error state anyway, so we might as well
3573  // work a little harder to print an informative error
3574  // message.
3575  //
3576  // Broadcast the Adder's idea of the matrix dimensions
3577  // from Proc 0 to all processes.
3578  Tuple<global_ordinal_type, 2> addersDims;
3579  if (myRank == rootRank) {
3580  addersDims[0] = pAdder->getAdder()->numRows();
3581  addersDims[1] = pAdder->getAdder()->numCols();
3582  }
3583  broadcast (*pComm, 0, addersDims);
3584  TEUCHOS_TEST_FOR_EXCEPTION(
3585  dimsMatch == 0, std::runtime_error,
3586  "The matrix metadata says that the matrix is " << dims[0] << " x "
3587  << dims[1] << ", but the actual data says that the matrix is "
3588  << addersDims[0] << " x " << addersDims[1] << ". That means the "
3589  "data includes more rows than reported in the metadata. This "
3590  "is not allowed when parsing in strict mode. Parse the matrix in "
3591  "tolerant mode to ignore the metadata when it disagrees with the "
3592  "data.");
3593  }
3594  } // Matrix dimensions (# rows, # cols, # entries) agree.
3595 
3596  if (debug && myRank == rootRank) {
3597  cerr << "-- Converting matrix data into CSR format on Proc 0" << endl;
3598  }
3599 
3600  // Now that we've read in all the matrix entries from the
3601  // input stream into the adder on Proc 0, post-process them
3602  // into CSR format (still on Proc 0). This will facilitate
3603  // distributing them to all the processors.
3604  //
3605  // These arrays represent the global matrix data as a CSR
3606  // matrix (with numEntriesPerRow as redundant but convenient
3607  // metadata, since it's computable from rowPtr and vice
3608  // versa). They are valid only on Proc 0.
3609  ArrayRCP<size_t> numEntriesPerRow;
3610  ArrayRCP<size_t> rowPtr;
3611  ArrayRCP<global_ordinal_type> colInd;
3612  ArrayRCP<scalar_type> values;
3613  size_t maxNumEntriesPerRow = 0;
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  for (global_ordinal_type r = prvRow+1; r <= curRow; ++r) {
3677  rowPtr[r] = curPos;
3678  }
3679  prvRow = curRow;
3680  }
3681  numEntriesPerRow[curRow]++;
3682  colInd[curPos] = curEntry.colIndex();
3683  values[curPos] = curEntry.value();
3684  }
3685  // rowPtr has one more entry than numEntriesPerRow. The
3686  // last entry of rowPtr is the number of entries in
3687  // colInd and values.
3688  rowPtr[numRows] = numEntries;
3689  } // Finished conversion to CSR format
3690  catch (std::exception& e) {
3691  mergeAndConvertSucceeded = 0;
3692  errMsg << "Failed to merge sparse matrix entries and convert to "
3693  "CSR format: " << e.what();
3694  }
3695 
3696  if (debug && mergeAndConvertSucceeded) {
3697  // Number of rows in the matrix.
3698  const size_type numRows = dims[0];
3699  const size_type maxToDisplay = 100;
3700 
3701  cerr << "----- Proc 0: numEntriesPerRow[0.."
3702  << (numEntriesPerRow.size()-1) << "] ";
3703  if (numRows > maxToDisplay) {
3704  cerr << "(only showing first and last few entries) ";
3705  }
3706  cerr << "= [";
3707  if (numRows > 0) {
3708  if (numRows > maxToDisplay) {
3709  for (size_type k = 0; k < 2; ++k) {
3710  cerr << numEntriesPerRow[k] << " ";
3711  }
3712  cerr << "... ";
3713  for (size_type k = numRows-2; k < numRows-1; ++k) {
3714  cerr << numEntriesPerRow[k] << " ";
3715  }
3716  }
3717  else {
3718  for (size_type k = 0; k < numRows-1; ++k) {
3719  cerr << numEntriesPerRow[k] << " ";
3720  }
3721  }
3722  cerr << numEntriesPerRow[numRows-1];
3723  } // numRows > 0
3724  cerr << "]" << endl;
3725 
3726  cerr << "----- Proc 0: rowPtr ";
3727  if (numRows > maxToDisplay) {
3728  cerr << "(only showing first and last few entries) ";
3729  }
3730  cerr << "= [";
3731  if (numRows > maxToDisplay) {
3732  for (size_type k = 0; k < 2; ++k) {
3733  cerr << rowPtr[k] << " ";
3734  }
3735  cerr << "... ";
3736  for (size_type k = numRows-2; k < numRows; ++k) {
3737  cerr << rowPtr[k] << " ";
3738  }
3739  }
3740  else {
3741  for (size_type k = 0; k < numRows; ++k) {
3742  cerr << rowPtr[k] << " ";
3743  }
3744  }
3745  cerr << rowPtr[numRows] << "]" << endl;
3746 
3747  cerr << "----- Proc 0: colInd = [";
3748  for (size_t k = 0; k < rowPtr[numRows]; ++k) {
3749  cerr << colInd[k] << " ";
3750  }
3751  cerr << "]" << endl;
3752  }
3753  } // if myRank == rootRank
3754  } // Done converting sparse matrix data to CSR format
3755 
3756  // Now we're done with the Adder, so we can release the
3757  // reference ("free" it) to save space. This only actually
3758  // does anything on Rank 0, since pAdder is null on all the
3759  // other MPI processes.
3760  pAdder = null;
3761 
3762  // Verify details of the Maps. Don't count the global number
3763  // of entries in the row Map, since that number doesn't
3764  // correctly count overlap.
3765  if (debug && myRank == rootRank) {
3766  cerr << "-- Verifying Maps" << endl;
3767  }
3768  TEUCHOS_TEST_FOR_EXCEPTION(
3769  as<global_size_t> (dims[0]) != rangeMap->getGlobalNumElements(),
3770  std::invalid_argument,
3771  "The range Map has " << rangeMap->getGlobalNumElements ()
3772  << " entries, but the matrix has a global number of rows " << dims[0]
3773  << ".");
3774  TEUCHOS_TEST_FOR_EXCEPTION(
3775  as<global_size_t> (dims[1]) != domainMap->getGlobalNumElements (),
3776  std::invalid_argument,
3777  "The domain Map has " << domainMap->getGlobalNumElements ()
3778  << " entries, but the matrix has a global number of columns "
3779  << dims[1] << ".");
3780 
3781  // Create a row Map which is entirely owned on Proc 0.
3782  RCP<Teuchos::FancyOStream> err = debug ?
3783  Teuchos::getFancyOStream (Teuchos::rcpFromRef (cerr)) : null;
3784 
3785  RCP<const map_type> gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
3786  ArrayView<const global_ordinal_type> myRows =
3787  gatherRowMap->getNodeElementList ();
3788  const size_type myNumRows = myRows.size ();
3789  const global_ordinal_type indexBase = gatherRowMap->getIndexBase ();
3790 
3791  ArrayRCP<size_t> gatherNumEntriesPerRow = arcp<size_t>(myNumRows);
3792  for (size_type i_ = 0; i_ < myNumRows; i_++) {
3793  gatherNumEntriesPerRow[i_] = numEntriesPerRow[myRows[i_]-indexBase];
3794  if (gatherNumEntriesPerRow[i_] > maxNumEntriesPerRow)
3795  maxNumEntriesPerRow = gatherNumEntriesPerRow[i_];
3796  }
3797 
3798  // Create a matrix using this Map, and fill in on Proc 0. We
3799  // know how many entries there are in each row, so we can use
3800  // static profile.
3801  RCP<sparse_matrix_type> A_proc0 =
3802  rcp (new sparse_matrix_type (gatherRowMap, gatherNumEntriesPerRow (),
3803  Tpetra::StaticProfile));
3804  if (myRank == rootRank) {
3805  if (debug) {
3806  cerr << "-- Proc 0: Filling gather matrix" << endl;
3807  }
3808  if (debug) {
3809  cerr << "---- Rows: " << Teuchos::toString (myRows) << endl;
3810  }
3811 
3812  // Add Proc 0's matrix entries to the CrsMatrix.
3813  for (size_type i_ = 0; i_ < myNumRows; ++i_) {
3814  size_type i = myRows[i_] - indexBase;
3815 
3816  const size_type curPos = as<size_type> (rowPtr[i]);
3817  const local_ordinal_type curNumEntries = numEntriesPerRow[i];
3818  ArrayView<global_ordinal_type> curColInd =
3819  colInd.view (curPos, curNumEntries);
3820  ArrayView<scalar_type> curValues =
3821  values.view (curPos, curNumEntries);
3822 
3823  // Modify the column indices in place to have the right index base.
3824  for (size_type k = 0; k < curNumEntries; ++k) {
3825  curColInd[k] += indexBase;
3826  }
3827  if (debug) {
3828  cerr << "------ Columns: " << Teuchos::toString (curColInd) << endl;
3829  cerr << "------ Values: " << Teuchos::toString (curValues) << endl;
3830  }
3831  // Avoid constructing empty views of ArrayRCP objects.
3832  if (curNumEntries > 0) {
3833  A_proc0->insertGlobalValues (myRows[i_], curColInd, curValues);
3834  }
3835  }
3836  // Now we can save space by deallocating numEntriesPerRow,
3837  // rowPtr, colInd, and values, since we've already put those
3838  // data in the matrix.
3839  numEntriesPerRow = null;
3840  rowPtr = null;
3841  colInd = null;
3842  values = null;
3843  } // if myRank == rootRank
3844 
3845  broadcast<int,size_t> (*pComm, 0, &maxNumEntriesPerRow);
3846 
3847  RCP<sparse_matrix_type> A;
3848  if (colMap.is_null ()) {
3849  A = rcp (new sparse_matrix_type (rowMap, maxNumEntriesPerRow));
3850  } else {
3851  A = rcp (new sparse_matrix_type (rowMap, colMap, maxNumEntriesPerRow));
3852  }
3854  export_type exp (gatherRowMap, rowMap);
3855  A->doExport (*A_proc0, exp, INSERT);
3856 
3857  if (callFillComplete) {
3858  A->fillComplete (domainMap, rangeMap);
3859  }
3860 
3861  // We can't get the dimensions of the matrix until after
3862  // fillComplete() is called. Thus, we can't do the sanity
3863  // check (dimensions read from the Matrix Market data,
3864  // vs. dimensions reported by the CrsMatrix) unless the user
3865  // asked us to call fillComplete().
3866  //
3867  // Note that pMatrix->getGlobalNum{Rows,Cols}() does _not_ do
3868  // what one might think it does, so you have to ask the range
3869  // resp. domain map for the number of rows resp. columns.
3870  if (callFillComplete) {
3871  const int numProcs = pComm->getSize ();
3872 
3873  if (extraDebug && debug) {
3874  const global_size_t globalNumRows = rangeMap->getGlobalNumElements ();
3875  const global_size_t globalNumCols = domainMap->getGlobalNumElements ();
3876  if (myRank == rootRank) {
3877  cerr << "-- Matrix is "
3878  << globalNumRows << " x " << globalNumCols
3879  << " with " << A->getGlobalNumEntries()
3880  << " entries, and index base "
3881  << A->getIndexBase() << "." << endl;
3882  }
3883  pComm->barrier ();
3884  for (int p = 0; p < numProcs; ++p) {
3885  if (myRank == p) {
3886  cerr << "-- Proc " << p << " owns "
3887  << A->getNodeNumCols() << " columns, and "
3888  << A->getNodeNumEntries() << " entries." << endl;
3889  }
3890  pComm->barrier ();
3891  }
3892  } // if (extraDebug && debug)
3893  } // if (callFillComplete)
3894 
3895  if (debug && myRank == rootRank) {
3896  cerr << "-- Done creating the CrsMatrix from the Matrix Market data"
3897  << endl;
3898  }
3899  return A;
3900  }
3901 
3930  static Teuchos::RCP<multivector_type>
3931  readDenseFile (const std::string& filename,
3932  const Teuchos::RCP<const comm_type>& comm,
3933  Teuchos::RCP<const map_type>& map,
3934  const bool tolerant=false,
3935  const bool debug=false)
3936  {
3937  using Teuchos::broadcast;
3938  using Teuchos::outArg;
3939 
3940  std::ifstream in;
3941  int opened = 0;
3942  if (comm->getRank() == 0) {
3943  try {
3944  in.open (filename.c_str ());
3945  opened = in.is_open();
3946  }
3947  catch (...) {
3948  opened = 0;
3949  }
3950  }
3951  broadcast<int, int> (*comm, 0, outArg (opened));
3952  TEUCHOS_TEST_FOR_EXCEPTION(
3953  opened == 0, std::runtime_error,
3954  "readDenseFile: Failed to open file \"" << filename << "\" on "
3955  "Process 0.");
3956  return readDense (in, comm, map, tolerant, debug);
3957  }
3958 
3959 
3989  static Teuchos::RCP<vector_type>
3990  readVectorFile (const std::string& filename,
3991  const Teuchos::RCP<const comm_type>& comm,
3992  Teuchos::RCP<const map_type>& map,
3993  const bool tolerant=false,
3994  const bool debug=false)
3995  {
3996  using Teuchos::broadcast;
3997  using Teuchos::outArg;
3998 
3999  std::ifstream in;
4000  int opened = 0;
4001  if (comm->getRank() == 0) {
4002  try {
4003  in.open (filename.c_str ());
4004  opened = in.is_open();
4005  }
4006  catch (...) {
4007  opened = 0;
4008  }
4009  }
4010  broadcast<int, int> (*comm, 0, outArg (opened));
4011  TEUCHOS_TEST_FOR_EXCEPTION(
4012  opened == 0, std::runtime_error,
4013  "readVectorFile: Failed to open file \"" << filename << "\" on "
4014  "Process 0.");
4015  return readVector (in, comm, map, tolerant, debug);
4016  }
4017 
4018 
4085  static Teuchos::RCP<multivector_type>
4086  readDense (std::istream& in,
4087  const Teuchos::RCP<const comm_type>& comm,
4088  Teuchos::RCP<const map_type>& map,
4089  const bool tolerant=false,
4090  const bool debug=false)
4091  {
4092  Teuchos::RCP<Teuchos::FancyOStream> err =
4093  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4094  return readDenseImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4095  }
4096 
4097 
4099  static Teuchos::RCP<vector_type>
4100  readVector (std::istream& in,
4101  const Teuchos::RCP<const comm_type>& comm,
4102  Teuchos::RCP<const map_type>& map,
4103  const bool tolerant=false,
4104  const bool debug=false)
4105  {
4106  Teuchos::RCP<Teuchos::FancyOStream> err =
4107  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
4108  return readVectorImpl<scalar_type> (in, comm, map, err, tolerant, debug);
4109  }
4110 
4111 
4132  static Teuchos::RCP<const map_type>
4133  readMapFile (const std::string& filename,
4134  const Teuchos::RCP<const comm_type>& comm,
4135  const bool tolerant=false,
4136  const bool debug=false)
4137  {
4138  using Teuchos::inOutArg;
4139  using Teuchos::broadcast;
4140  std::ifstream in;
4141 
4142  int success = 1;
4143  if (comm->getRank () == 0) { // Only open the file on Proc 0.
4144  in.open (filename.c_str ()); // Destructor closes safely
4145  if (! in) {
4146  success = 0;
4147  }
4148  }
4149  broadcast<int, int> (*comm, 0, inOutArg (success));
4150  TEUCHOS_TEST_FOR_EXCEPTION(
4151  success == 0, std::runtime_error,
4152  "Tpetra::MatrixMarket::Reader::readMapFile: "
4153  "Failed to read file \"" << filename << "\" on Process 0.");
4154  return readMap (in, comm, tolerant, debug);
4155  }
4156 
4157 
4158  private:
4159  template<class MultiVectorScalarType>
4160  static Teuchos::RCP<Tpetra::MultiVector<MultiVectorScalarType,
4163  node_type> >
4164  readDenseImpl (std::istream& in,
4165  const Teuchos::RCP<const comm_type>& comm,
4166  Teuchos::RCP<const map_type>& map,
4167  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4168  const bool tolerant=false,
4169  const bool debug=false)
4170  {
4171  using Teuchos::MatrixMarket::Banner;
4172  using Teuchos::MatrixMarket::checkCommentLine;
4173  using Teuchos::ArrayRCP;
4174  using Teuchos::as;
4175  using Teuchos::broadcast;
4176  using Teuchos::outArg;
4177  using Teuchos::RCP;
4178  using Teuchos::Tuple;
4179  using std::endl;
4180  typedef MultiVectorScalarType ST;
4181  typedef local_ordinal_type LO;
4182  typedef global_ordinal_type GO;
4183  typedef node_type NT;
4184  typedef Teuchos::ScalarTraits<ST> STS;
4185  typedef typename STS::magnitudeType MT;
4186  typedef Teuchos::ScalarTraits<MT> STM;
4188 
4189  // Rank 0 is the only (MPI) process allowed to read from the
4190  // input stream.
4191  const int myRank = comm->getRank ();
4192 
4193  if (! err.is_null ()) {
4194  err->pushTab ();
4195  }
4196  if (debug) {
4197  *err << myRank << ": readDenseImpl" << endl;
4198  }
4199  if (! err.is_null ()) {
4200  err->pushTab ();
4201  }
4202 
4203  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4204  // instances be identical and that the Node instances be
4205  // identical. The essential condition is more complicated to
4206  // test and isn't the same for all Node types. Thus, we just
4207  // leave it up to the user.
4208 
4209  // // If map is nonnull, check the precondition that its
4210  // // communicator resp. node equal comm resp. node. Checking
4211  // // now avoids doing a lot of file reading before we detect the
4212  // // violated precondition.
4213  // TEUCHOS_TEST_FOR_EXCEPTION(
4214  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4215  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4216  // "communicator and node must equal the supplied communicator resp. "
4217  // "node.");
4218 
4219  // Process 0 will read in the matrix dimensions from the file,
4220  // and broadcast them to all ranks in the given communicator.
4221  // There are only 2 dimensions in the matrix, but we use the
4222  // third element of the Tuple to encode the banner's reported
4223  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4224  // (same as "real"). We don't allow pattern matrices (i.e.,
4225  // graphs) since they only make sense for sparse data.
4226  Tuple<GO, 3> dims;
4227  dims[0] = 0;
4228  dims[1] = 0;
4229 
4230  // Current line number in the input stream. Only valid on
4231  // Proc 0. Various calls will modify this depending on the
4232  // number of lines that are read from the input stream.
4233  size_t lineNumber = 1;
4234 
4235  // Capture errors and their messages on Proc 0.
4236  std::ostringstream exMsg;
4237  int localBannerReadSuccess = 1;
4238  int localDimsReadSuccess = 1;
4239 
4240  // Only Proc 0 gets to read matrix data from the input stream.
4241  if (myRank == 0) {
4242  if (debug) {
4243  *err << myRank << ": readDenseImpl: Reading banner line (dense)" << endl;
4244  }
4245 
4246  // The "Banner" tells you whether the input stream
4247  // represents a dense matrix, the symmetry type of the
4248  // matrix, and the type of the data it contains.
4249  RCP<const Banner> pBanner;
4250  try {
4251  pBanner = readBanner (in, lineNumber, tolerant, debug);
4252  } catch (std::exception& e) {
4253  exMsg << e.what ();
4254  localBannerReadSuccess = 0;
4255  }
4256  // Make sure the input stream is the right kind of data.
4257  if (localBannerReadSuccess) {
4258  if (pBanner->matrixType () != "array") {
4259  exMsg << "The Matrix Market file does not contain dense matrix "
4260  "data. Its banner (first) line says that its matrix type is \""
4261  << pBanner->matrixType () << "\", rather that the required "
4262  "\"array\".";
4263  localBannerReadSuccess = 0;
4264  } else if (pBanner->dataType() == "pattern") {
4265  exMsg << "The Matrix Market file's banner (first) "
4266  "line claims that the matrix's data type is \"pattern\". This does "
4267  "not make sense for a dense matrix, yet the file reports the matrix "
4268  "as dense. The only valid data types for a dense matrix are "
4269  "\"real\", \"complex\", and \"integer\".";
4270  localBannerReadSuccess = 0;
4271  } else {
4272  // Encode the data type reported by the Banner as the
4273  // third element of the dimensions Tuple.
4274  dims[2] = encodeDataType (pBanner->dataType ());
4275  }
4276  } // if we successfully read the banner line
4277 
4278  // At this point, we've successfully read the banner line.
4279  // Now read the dimensions line.
4280  if (localBannerReadSuccess) {
4281  if (debug) {
4282  *err << myRank << ": readDenseImpl: Reading dimensions line (dense)" << endl;
4283  }
4284  // Keep reading lines from the input stream until we find
4285  // a non-comment line, or until we run out of lines. The
4286  // latter is an error, since every "array" format Matrix
4287  // Market file must have a dimensions line after the
4288  // banner (even if the matrix has zero rows or columns, or
4289  // zero entries).
4290  std::string line;
4291  bool commentLine = true;
4292 
4293  while (commentLine) {
4294  // Test whether it is even valid to read from the input
4295  // stream wrapping the line.
4296  if (in.eof () || in.fail ()) {
4297  exMsg << "Unable to get array dimensions line (at all) from line "
4298  << lineNumber << " of input stream. The input stream "
4299  << "claims that it is "
4300  << (in.eof() ? "at end-of-file." : "in a failed state.");
4301  localDimsReadSuccess = 0;
4302  } else {
4303  // Try to get the next line from the input stream.
4304  if (getline (in, line)) {
4305  ++lineNumber; // We did actually read a line.
4306  }
4307  // Is the current line a comment line? Ignore start
4308  // and size; they are only useful for reading the
4309  // actual matrix entries. (We could use them here as
4310  // an optimization, but we've chosen not to.)
4311  size_t start = 0, size = 0;
4312  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4313  } // whether we failed to read the line at all
4314  } // while the line we just read is a comment line
4315 
4316  //
4317  // Get <numRows> <numCols> from the line we just read.
4318  //
4319  std::istringstream istr (line);
4320 
4321  // Test whether it is even valid to read from the input
4322  // stream wrapping the line.
4323  if (istr.eof () || istr.fail ()) {
4324  exMsg << "Unable to read any data from line " << lineNumber
4325  << " of input; the line should contain the matrix dimensions "
4326  << "\"<numRows> <numCols>\".";
4327  localDimsReadSuccess = 0;
4328  } else { // It's valid to read from the line.
4329  GO theNumRows = 0;
4330  istr >> theNumRows; // Read in the number of rows.
4331  if (istr.fail ()) {
4332  exMsg << "Failed to get number of rows from line "
4333  << lineNumber << " of input; the line should contains the "
4334  << "matrix dimensions \"<numRows> <numCols>\".";
4335  localDimsReadSuccess = 0;
4336  } else { // We successfully read the number of rows
4337  dims[0] = theNumRows; // Save the number of rows
4338  if (istr.eof ()) { // Do we still have data to read?
4339  exMsg << "No more data after number of rows on line "
4340  << lineNumber << " of input; the line should contain the "
4341  << "matrix dimensions \"<numRows> <numCols>\".";
4342  localDimsReadSuccess = 0;
4343  } else { // Still data left to read; read in number of columns.
4344  GO theNumCols = 0;
4345  istr >> theNumCols; // Read in the number of columns
4346  if (istr.fail ()) {
4347  exMsg << "Failed to get number of columns from line "
4348  << lineNumber << " of input; the line should contain "
4349  << "the matrix dimensions \"<numRows> <numCols>\".";
4350  localDimsReadSuccess = 0;
4351  } else { // We successfully read the number of columns
4352  dims[1] = theNumCols; // Save the number of columns
4353  } // if istr.fail ()
4354  } // if istr.eof ()
4355  } // if we read the number of rows
4356  } // if the input stream wrapping the dims line was (in)valid
4357  } // if we successfully read the banner line
4358  } // if (myRank == 0)
4359 
4360  // Broadcast the matrix dimensions, the encoded data type, and
4361  // whether or not Proc 0 succeeded in reading the banner and
4362  // dimensions.
4363  Tuple<GO, 5> bannerDimsReadResult;
4364  if (myRank == 0) {
4365  bannerDimsReadResult[0] = dims[0]; // numRows
4366  bannerDimsReadResult[1] = dims[1]; // numCols
4367  bannerDimsReadResult[2] = dims[2]; // encoded data type
4368  bannerDimsReadResult[3] = localBannerReadSuccess;
4369  bannerDimsReadResult[4] = localDimsReadSuccess;
4370  }
4371  // Broadcast matrix dimensions and the encoded data type from
4372  // Proc 0 to all the MPI processes.
4373  broadcast (*comm, 0, bannerDimsReadResult);
4374 
4375  TEUCHOS_TEST_FOR_EXCEPTION(
4376  bannerDimsReadResult[3] == 0, std::runtime_error,
4377  "Failed to read banner line: " << exMsg.str ());
4378  TEUCHOS_TEST_FOR_EXCEPTION(
4379  bannerDimsReadResult[4] == 0, std::runtime_error,
4380  "Failed to read matrix dimensions line: " << exMsg.str ());
4381  if (myRank != 0) {
4382  dims[0] = bannerDimsReadResult[0];
4383  dims[1] = bannerDimsReadResult[1];
4384  dims[2] = bannerDimsReadResult[2];
4385  }
4386 
4387  // Tpetra objects want the matrix dimensions in these types.
4388  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4389  const size_t numCols = static_cast<size_t> (dims[1]);
4390 
4391  // Make a "Proc 0 owns everything" Map that we will use to
4392  // read in the multivector entries in the correct order on
4393  // Proc 0. This must be a collective
4394  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4395  if (map.is_null ()) {
4396  // The user didn't supply a Map. Make a contiguous
4397  // distributed Map for them, using the read-in multivector
4398  // dimensions.
4399  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4400  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4401  // At this point, map exists and has a nonnull node.
4402  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4403  comm);
4404  }
4405  else { // The user supplied a Map.
4406  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4407  }
4408 
4409  // Make a multivector X owned entirely by Proc 0.
4410  RCP<MV> X = createMultiVector<ST, LO, GO, NT> (proc0Map, numCols);
4411 
4412  //
4413  // On Proc 0, read the Matrix Market data from the input
4414  // stream into the multivector X.
4415  //
4416  int localReadDataSuccess = 1;
4417  if (myRank == 0) {
4418  try {
4419  if (debug) {
4420  *err << myRank << ": readDenseImpl: Reading matrix data (dense)"
4421  << endl;
4422  }
4423 
4424  // Make sure that we can get a 1-D view of X.
4425  TEUCHOS_TEST_FOR_EXCEPTION(
4426  ! X->isConstantStride (), std::logic_error,
4427  "Can't get a 1-D view of the entries of the MultiVector X on "
4428  "Process 0, because the stride between the columns of X is not "
4429  "constant. This shouldn't happen because we just created X and "
4430  "haven't filled it in yet. Please report this bug to the Tpetra "
4431  "developers.");
4432 
4433  // Get a writeable 1-D view of the entries of X. Rank 0
4434  // owns all of them. The view will expire at the end of
4435  // scope, so (if necessary) it will be written back to X
4436  // at this time.
4437  ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4438  TEUCHOS_TEST_FOR_EXCEPTION(
4439  as<global_size_t> (X_view.size ()) < numRows * numCols,
4440  std::logic_error,
4441  "The view of X has size " << X_view << " which is not enough to "
4442  "accommodate the expected number of entries numRows*numCols = "
4443  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4444  "Please report this bug to the Tpetra developers.");
4445  const size_t stride = X->getStride ();
4446 
4447  // The third element of the dimensions Tuple encodes the data
4448  // type reported by the Banner: "real" == 0, "complex" == 1,
4449  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4450  // allow dense matrices to be pattern matrices, so dims[2] ==
4451  // 0 or 1. We've already checked for this above.
4452  const bool isComplex = (dims[2] == 1);
4453  size_type count = 0, curRow = 0, curCol = 0;
4454 
4455  std::string line;
4456  while (getline (in, line)) {
4457  ++lineNumber;
4458  // Is the current line a comment line? If it's not,
4459  // line.substr(start,size) contains the data.
4460  size_t start = 0, size = 0;
4461  const bool commentLine =
4462  checkCommentLine (line, start, size, lineNumber, tolerant);
4463  if (! commentLine) {
4464  // Make sure we have room in which to put the new matrix
4465  // entry. We check this only after checking for a
4466  // comment line, because there may be one or more
4467  // comment lines at the end of the file. In tolerant
4468  // mode, we simply ignore any extra data.
4469  if (count >= X_view.size()) {
4470  if (tolerant) {
4471  break;
4472  }
4473  else {
4474  TEUCHOS_TEST_FOR_EXCEPTION(
4475  count >= X_view.size(),
4476  std::runtime_error,
4477  "The Matrix Market input stream has more data in it than "
4478  "its metadata reported. Current line number is "
4479  << lineNumber << ".");
4480  }
4481  }
4482 
4483  // mfh 19 Dec 2012: Ignore everything up to the initial
4484  // colon. writeDense() has the option to print out the
4485  // global row index in front of each entry, followed by
4486  // a colon and space.
4487  {
4488  const size_t pos = line.substr (start, size).find (':');
4489  if (pos != std::string::npos) {
4490  start = pos+1;
4491  }
4492  }
4493  std::istringstream istr (line.substr (start, size));
4494  // Does the line contain anything at all? Can we
4495  // safely read from the input stream wrapping the
4496  // line?
4497  if (istr.eof() || istr.fail()) {
4498  // In tolerant mode, simply ignore the line.
4499  if (tolerant) {
4500  break;
4501  }
4502  // We repeat the full test here so the exception
4503  // message is more informative.
4504  TEUCHOS_TEST_FOR_EXCEPTION(
4505  ! tolerant && (istr.eof() || istr.fail()),
4506  std::runtime_error,
4507  "Line " << lineNumber << " of the Matrix Market file is "
4508  "empty, or we cannot read from it for some other reason.");
4509  }
4510  // Current matrix entry to read in.
4511  ST val = STS::zero();
4512  // Real and imaginary parts of the current matrix entry.
4513  // The imaginary part is zero if the matrix is real-valued.
4514  MT real = STM::zero(), imag = STM::zero();
4515 
4516  // isComplex refers to the input stream's data, not to
4517  // the scalar type S. It's OK to read real-valued
4518  // data into a matrix storing complex-valued data; in
4519  // that case, all entries' imaginary parts are zero.
4520  if (isComplex) {
4521  // STS::real() and STS::imag() return a copy of
4522  // their respective components, not a writeable
4523  // reference. Otherwise we could just assign to
4524  // them using the istream extraction operator (>>).
4525  // That's why we have separate magnitude type "real"
4526  // and "imag" variables.
4527 
4528  // Attempt to read the real part of the current entry.
4529  istr >> real;
4530  if (istr.fail()) {
4531  TEUCHOS_TEST_FOR_EXCEPTION(
4532  ! tolerant && istr.eof(), std::runtime_error,
4533  "Failed to get the real part of a complex-valued matrix "
4534  "entry from line " << lineNumber << " of the Matrix Market "
4535  "file.");
4536  // In tolerant mode, just skip bad lines.
4537  if (tolerant) {
4538  break;
4539  }
4540  } else if (istr.eof()) {
4541  TEUCHOS_TEST_FOR_EXCEPTION(
4542  ! tolerant && istr.eof(), std::runtime_error,
4543  "Missing imaginary part of a complex-valued matrix entry "
4544  "on line " << lineNumber << " of the Matrix Market file.");
4545  // In tolerant mode, let any missing imaginary part be 0.
4546  } else {
4547  // Attempt to read the imaginary part of the current
4548  // matrix entry.
4549  istr >> imag;
4550  TEUCHOS_TEST_FOR_EXCEPTION(
4551  ! tolerant && istr.fail(), std::runtime_error,
4552  "Failed to get the imaginary part of a complex-valued "
4553  "matrix entry from line " << lineNumber << " of the "
4554  "Matrix Market file.");
4555  // In tolerant mode, let any missing or corrupted
4556  // imaginary part be 0.
4557  }
4558  } else { // Matrix Market file contains real-valued data.
4559  // Attempt to read the current matrix entry.
4560  istr >> real;
4561  TEUCHOS_TEST_FOR_EXCEPTION(
4562  ! tolerant && istr.fail(), std::runtime_error,
4563  "Failed to get a real-valued matrix entry from line "
4564  << lineNumber << " of the Matrix Market file.");
4565  // In tolerant mode, simply ignore the line if
4566  // we failed to read a matrix entry.
4567  if (istr.fail() && tolerant) {
4568  break;
4569  }
4570  }
4571  // In tolerant mode, we simply let pass through whatever
4572  // data we got.
4573  TEUCHOS_TEST_FOR_EXCEPTION(
4574  ! tolerant && istr.fail(), std::runtime_error,
4575  "Failed to read matrix data from line " << lineNumber
4576  << " of the Matrix Market file.");
4577 
4578  // Assign val = ST(real, imag).
4579  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
4580 
4581  curRow = count % numRows;
4582  curCol = count / numRows;
4583  X_view[curRow + curCol*stride] = val;
4584  ++count;
4585  } // if not a comment line
4586  } // while there are still lines in the file, get the next one
4587 
4588  TEUCHOS_TEST_FOR_EXCEPTION(
4589  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
4590  std::runtime_error,
4591  "The Matrix Market metadata reports that the dense matrix is "
4592  << numRows << " x " << numCols << ", and thus has "
4593  << numRows*numCols << " total entries, but we only found " << count
4594  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
4595  } catch (std::exception& e) {
4596  exMsg << e.what ();
4597  localReadDataSuccess = 0;
4598  }
4599  } // if (myRank == 0)
4600 
4601  if (debug) {
4602  *err << myRank << ": readDenseImpl: done reading data" << endl;
4603  }
4604 
4605  // Synchronize on whether Proc 0 successfully read the data.
4606  int globalReadDataSuccess = localReadDataSuccess;
4607  broadcast (*comm, 0, outArg (globalReadDataSuccess));
4608  TEUCHOS_TEST_FOR_EXCEPTION(
4609  globalReadDataSuccess == 0, std::runtime_error,
4610  "Failed to read the multivector's data: " << exMsg.str ());
4611 
4612  // If there's only one MPI process and the user didn't supply
4613  // a Map (i.e., pMap is null), we're done. Set pMap to the
4614  // Map used to distribute X, and return X.
4615  if (comm->getSize () == 1 && map.is_null ()) {
4616  map = proc0Map;
4617  if (! err.is_null ()) {
4618  err->popTab ();
4619  }
4620  if (debug) {
4621  *err << myRank << ": readDenseImpl: done" << endl;
4622  }
4623  if (! err.is_null ()) {
4624  err->popTab ();
4625  }
4626  return X;
4627  }
4628 
4629  if (debug) {
4630  *err << myRank << ": readDenseImpl: Creating target MV" << endl;
4631  }
4632 
4633  // Make a multivector Y with the distributed map pMap.
4634  RCP<MV> Y = createMultiVector<ST, LO, GO, NT> (map, numCols);
4635 
4636  if (debug) {
4637  *err << myRank << ": readDenseImpl: Creating Export" << endl;
4638  }
4639 
4640  // Make an Export object that will export X to Y. First
4641  // argument is the source map, second argument is the target
4642  // map.
4643  Export<LO, GO, NT> exporter (proc0Map, map, err);
4644 
4645  if (debug) {
4646  *err << myRank << ": readDenseImpl: Exporting" << endl;
4647  }
4648  // Export X into Y.
4649  Y->doExport (*X, exporter, INSERT);
4650 
4651  if (! err.is_null ()) {
4652  err->popTab ();
4653  }
4654  if (debug) {
4655  *err << myRank << ": readDenseImpl: done" << endl;
4656  }
4657  if (! err.is_null ()) {
4658  err->popTab ();
4659  }
4660 
4661  // Y is distributed over all process(es) in the communicator.
4662  return Y;
4663  }
4664 
4665 
4666  template<class VectorScalarType>
4667  static Teuchos::RCP<Tpetra::Vector<VectorScalarType,
4670  node_type> >
4671  readVectorImpl (std::istream& in,
4672  const Teuchos::RCP<const comm_type>& comm,
4673  Teuchos::RCP<const map_type>& map,
4674  const Teuchos::RCP<Teuchos::FancyOStream>& err,
4675  const bool tolerant=false,
4676  const bool debug=false)
4677  {
4678  using Teuchos::MatrixMarket::Banner;
4679  using Teuchos::MatrixMarket::checkCommentLine;
4680  using Teuchos::as;
4681  using Teuchos::broadcast;
4682  using Teuchos::outArg;
4683  using Teuchos::RCP;
4684  using Teuchos::Tuple;
4685  using std::endl;
4686  typedef VectorScalarType ST;
4687  typedef local_ordinal_type LO;
4688  typedef global_ordinal_type GO;
4689  typedef node_type NT;
4690  typedef Teuchos::ScalarTraits<ST> STS;
4691  typedef typename STS::magnitudeType MT;
4692  typedef Teuchos::ScalarTraits<MT> STM;
4693  typedef Tpetra::Vector<ST, LO, GO, NT> MV;
4694 
4695  // Rank 0 is the only (MPI) process allowed to read from the
4696  // input stream.
4697  const int myRank = comm->getRank ();
4698 
4699  if (! err.is_null ()) {
4700  err->pushTab ();
4701  }
4702  if (debug) {
4703  *err << myRank << ": readVectorImpl" << endl;
4704  }
4705  if (! err.is_null ()) {
4706  err->pushTab ();
4707  }
4708 
4709  // mfh 17 Feb 2013: It's not strictly necessary that the Comm
4710  // instances be identical and that the Node instances be
4711  // identical. The essential condition is more complicated to
4712  // test and isn't the same for all Node types. Thus, we just
4713  // leave it up to the user.
4714 
4715  // // If map is nonnull, check the precondition that its
4716  // // communicator resp. node equal comm resp. node. Checking
4717  // // now avoids doing a lot of file reading before we detect the
4718  // // violated precondition.
4719  // TEUCHOS_TEST_FOR_EXCEPTION(
4720  // ! map.is_null() && (map->getComm() != comm || map->getNode () != node,
4721  // std::invalid_argument, "If you supply a nonnull Map, the Map's "
4722  // "communicator and node must equal the supplied communicator resp. "
4723  // "node.");
4724 
4725  // Process 0 will read in the matrix dimensions from the file,
4726  // and broadcast them to all ranks in the given communicator.
4727  // There are only 2 dimensions in the matrix, but we use the
4728  // third element of the Tuple to encode the banner's reported
4729  // data type: "real" == 0, "complex" == 1, and "integer" == 0
4730  // (same as "real"). We don't allow pattern matrices (i.e.,
4731  // graphs) since they only make sense for sparse data.
4732  Tuple<GO, 3> dims;
4733  dims[0] = 0;
4734  dims[1] = 0;
4735 
4736  // Current line number in the input stream. Only valid on
4737  // Proc 0. Various calls will modify this depending on the
4738  // number of lines that are read from the input stream.
4739  size_t lineNumber = 1;
4740 
4741  // Capture errors and their messages on Proc 0.
4742  std::ostringstream exMsg;
4743  int localBannerReadSuccess = 1;
4744  int localDimsReadSuccess = 1;
4745 
4746  // Only Proc 0 gets to read matrix data from the input stream.
4747  if (myRank == 0) {
4748  if (debug) {
4749  *err << myRank << ": readVectorImpl: Reading banner line (dense)" << endl;
4750  }
4751 
4752  // The "Banner" tells you whether the input stream
4753  // represents a dense matrix, the symmetry type of the
4754  // matrix, and the type of the data it contains.
4755  RCP<const Banner> pBanner;
4756  try {
4757  pBanner = readBanner (in, lineNumber, tolerant, debug);
4758  } catch (std::exception& e) {
4759  exMsg << e.what ();
4760  localBannerReadSuccess = 0;
4761  }
4762  // Make sure the input stream is the right kind of data.
4763  if (localBannerReadSuccess) {
4764  if (pBanner->matrixType () != "array") {
4765  exMsg << "The Matrix Market file does not contain dense matrix "
4766  "data. Its banner (first) line says that its matrix type is \""
4767  << pBanner->matrixType () << "\", rather that the required "
4768  "\"array\".";
4769  localBannerReadSuccess = 0;
4770  } else if (pBanner->dataType() == "pattern") {
4771  exMsg << "The Matrix Market file's banner (first) "
4772  "line claims that the matrix's data type is \"pattern\". This does "
4773  "not make sense for a dense matrix, yet the file reports the matrix "
4774  "as dense. The only valid data types for a dense matrix are "
4775  "\"real\", \"complex\", and \"integer\".";
4776  localBannerReadSuccess = 0;
4777  } else {
4778  // Encode the data type reported by the Banner as the
4779  // third element of the dimensions Tuple.
4780  dims[2] = encodeDataType (pBanner->dataType ());
4781  }
4782  } // if we successfully read the banner line
4783 
4784  // At this point, we've successfully read the banner line.
4785  // Now read the dimensions line.
4786  if (localBannerReadSuccess) {
4787  if (debug) {
4788  *err << myRank << ": readVectorImpl: Reading dimensions line (dense)" << endl;
4789  }
4790  // Keep reading lines from the input stream until we find
4791  // a non-comment line, or until we run out of lines. The
4792  // latter is an error, since every "array" format Matrix
4793  // Market file must have a dimensions line after the
4794  // banner (even if the matrix has zero rows or columns, or
4795  // zero entries).
4796  std::string line;
4797  bool commentLine = true;
4798 
4799  while (commentLine) {
4800  // Test whether it is even valid to read from the input
4801  // stream wrapping the line.
4802  if (in.eof () || in.fail ()) {
4803  exMsg << "Unable to get array dimensions line (at all) from line "
4804  << lineNumber << " of input stream. The input stream "
4805  << "claims that it is "
4806  << (in.eof() ? "at end-of-file." : "in a failed state.");
4807  localDimsReadSuccess = 0;
4808  } else {
4809  // Try to get the next line from the input stream.
4810  if (getline (in, line)) {
4811  ++lineNumber; // We did actually read a line.
4812  }
4813  // Is the current line a comment line? Ignore start
4814  // and size; they are only useful for reading the
4815  // actual matrix entries. (We could use them here as
4816  // an optimization, but we've chosen not to.)
4817  size_t start = 0, size = 0;
4818  commentLine = checkCommentLine (line, start, size, lineNumber, tolerant);
4819  } // whether we failed to read the line at all
4820  } // while the line we just read is a comment line
4821 
4822  //
4823  // Get <numRows> <numCols> from the line we just read.
4824  //
4825  std::istringstream istr (line);
4826 
4827  // Test whether it is even valid to read from the input
4828  // stream wrapping the line.
4829  if (istr.eof () || istr.fail ()) {
4830  exMsg << "Unable to read any data from line " << lineNumber
4831  << " of input; the line should contain the matrix dimensions "
4832  << "\"<numRows> <numCols>\".";
4833  localDimsReadSuccess = 0;
4834  } else { // It's valid to read from the line.
4835  GO theNumRows = 0;
4836  istr >> theNumRows; // Read in the number of rows.
4837  if (istr.fail ()) {
4838  exMsg << "Failed to get number of rows from line "
4839  << lineNumber << " of input; the line should contains the "
4840  << "matrix dimensions \"<numRows> <numCols>\".";
4841  localDimsReadSuccess = 0;
4842  } else { // We successfully read the number of rows
4843  dims[0] = theNumRows; // Save the number of rows
4844  if (istr.eof ()) { // Do we still have data to read?
4845  exMsg << "No more data after number of rows on line "
4846  << lineNumber << " of input; the line should contain the "
4847  << "matrix dimensions \"<numRows> <numCols>\".";
4848  localDimsReadSuccess = 0;
4849  } else { // Still data left to read; read in number of columns.
4850  GO theNumCols = 0;
4851  istr >> theNumCols; // Read in the number of columns
4852  if (istr.fail ()) {
4853  exMsg << "Failed to get number of columns from line "
4854  << lineNumber << " of input; the line should contain "
4855  << "the matrix dimensions \"<numRows> <numCols>\".";
4856  localDimsReadSuccess = 0;
4857  } else { // We successfully read the number of columns
4858  dims[1] = theNumCols; // Save the number of columns
4859  } // if istr.fail ()
4860  } // if istr.eof ()
4861  } // if we read the number of rows
4862  } // if the input stream wrapping the dims line was (in)valid
4863  } // if we successfully read the banner line
4864  } // if (myRank == 0)
4865 
4866  // Check if file has a Vector
4867  if (dims[1]!=1) {
4868  exMsg << "File does not contain a 1D Vector";
4869  localDimsReadSuccess = 0;
4870  }
4871 
4872  // Broadcast the matrix dimensions, the encoded data type, and
4873  // whether or not Proc 0 succeeded in reading the banner and
4874  // dimensions.
4875  Tuple<GO, 5> bannerDimsReadResult;
4876  if (myRank == 0) {
4877  bannerDimsReadResult[0] = dims[0]; // numRows
4878  bannerDimsReadResult[1] = dims[1]; // numCols
4879  bannerDimsReadResult[2] = dims[2]; // encoded data type
4880  bannerDimsReadResult[3] = localBannerReadSuccess;
4881  bannerDimsReadResult[4] = localDimsReadSuccess;
4882  }
4883 
4884  // Broadcast matrix dimensions and the encoded data type from
4885  // Proc 0 to all the MPI processes.
4886  broadcast (*comm, 0, bannerDimsReadResult);
4887 
4888  TEUCHOS_TEST_FOR_EXCEPTION(
4889  bannerDimsReadResult[3] == 0, std::runtime_error,
4890  "Failed to read banner line: " << exMsg.str ());
4891  TEUCHOS_TEST_FOR_EXCEPTION(
4892  bannerDimsReadResult[4] == 0, std::runtime_error,
4893  "Failed to read matrix dimensions line: " << exMsg.str ());
4894  if (myRank != 0) {
4895  dims[0] = bannerDimsReadResult[0];
4896  dims[1] = bannerDimsReadResult[1];
4897  dims[2] = bannerDimsReadResult[2];
4898  }
4899 
4900  // Tpetra objects want the matrix dimensions in these types.
4901  const global_size_t numRows = static_cast<global_size_t> (dims[0]);
4902  const size_t numCols = static_cast<size_t> (dims[1]);
4903 
4904  // Make a "Proc 0 owns everything" Map that we will use to
4905  // read in the multivector entries in the correct order on
4906  // Proc 0. This must be a collective
4907  RCP<const map_type> proc0Map; // "Proc 0 owns everything" Map
4908  if (map.is_null ()) {
4909  // The user didn't supply a Map. Make a contiguous
4910  // distributed Map for them, using the read-in multivector
4911  // dimensions.
4912  map = createUniformContigMapWithNode<LO, GO, NT> (numRows, comm);
4913  const size_t localNumRows = (myRank == 0) ? numRows : 0;
4914  // At this point, map exists and has a nonnull node.
4915  proc0Map = createContigMapWithNode<LO, GO, NT> (numRows, localNumRows,
4916  comm);
4917  }
4918  else { // The user supplied a Map.
4919  proc0Map = Details::computeGatherMap<map_type> (map, err, debug);
4920  }
4921 
4922  // Make a multivector X owned entirely by Proc 0.
4923  RCP<MV> X = createVector<ST, LO, GO, NT> (proc0Map);
4924 
4925  //
4926  // On Proc 0, read the Matrix Market data from the input
4927  // stream into the multivector X.
4928  //
4929  int localReadDataSuccess = 1;
4930  if (myRank == 0) {
4931  try {
4932  if (debug) {
4933  *err << myRank << ": readVectorImpl: Reading matrix data (dense)"
4934  << endl;
4935  }
4936 
4937  // Make sure that we can get a 1-D view of X.
4938  TEUCHOS_TEST_FOR_EXCEPTION(
4939  ! X->isConstantStride (), std::logic_error,
4940  "Can't get a 1-D view of the entries of the MultiVector X on "
4941  "Process 0, because the stride between the columns of X is not "
4942  "constant. This shouldn't happen because we just created X and "
4943  "haven't filled it in yet. Please report this bug to the Tpetra "
4944  "developers.");
4945 
4946  // Get a writeable 1-D view of the entries of X. Rank 0
4947  // owns all of them. The view will expire at the end of
4948  // scope, so (if necessary) it will be written back to X
4949  // at this time.
4950  Teuchos::ArrayRCP<ST> X_view = X->get1dViewNonConst ();
4951  TEUCHOS_TEST_FOR_EXCEPTION(
4952  as<global_size_t> (X_view.size ()) < numRows * numCols,
4953  std::logic_error,
4954  "The view of X has size " << X_view << " which is not enough to "
4955  "accommodate the expected number of entries numRows*numCols = "
4956  << numRows << "*" << numCols << " = " << numRows*numCols << ". "
4957  "Please report this bug to the Tpetra developers.");
4958  const size_t stride = X->getStride ();
4959 
4960  // The third element of the dimensions Tuple encodes the data
4961  // type reported by the Banner: "real" == 0, "complex" == 1,
4962  // "integer" == 0 (same as "real"), "pattern" == 2. We do not
4963  // allow dense matrices to be pattern matrices, so dims[2] ==
4964  // 0 or 1. We've already checked for this above.
4965  const bool isComplex = (dims[2] == 1);
4966  size_type count = 0, curRow = 0, curCol = 0;
4967 
4968  std::string line;
4969  while (getline (in, line)) {
4970  ++lineNumber;
4971  // Is the current line a comment line? If it's not,
4972  // line.substr(start,size) contains the data.
4973  size_t start = 0, size = 0;
4974  const bool commentLine =
4975  checkCommentLine (line, start, size, lineNumber, tolerant);
4976  if (! commentLine) {
4977  // Make sure we have room in which to put the new matrix
4978  // entry. We check this only after checking for a
4979  // comment line, because there may be one or more
4980  // comment lines at the end of the file. In tolerant
4981  // mode, we simply ignore any extra data.
4982  if (count >= X_view.size()) {
4983  if (tolerant) {
4984  break;
4985  }
4986  else {
4987  TEUCHOS_TEST_FOR_EXCEPTION(
4988  count >= X_view.size(),
4989  std::runtime_error,
4990  "The Matrix Market input stream has more data in it than "
4991  "its metadata reported. Current line number is "
4992  << lineNumber << ".");
4993  }
4994  }
4995 
4996  // mfh 19 Dec 2012: Ignore everything up to the initial
4997  // colon. writeDense() has the option to print out the
4998  // global row index in front of each entry, followed by
4999  // a colon and space.
5000  {
5001  const size_t pos = line.substr (start, size).find (':');
5002  if (pos != std::string::npos) {
5003  start = pos+1;
5004  }
5005  }
5006  std::istringstream istr (line.substr (start, size));
5007  // Does the line contain anything at all? Can we
5008  // safely read from the input stream wrapping the
5009  // line?
5010  if (istr.eof() || istr.fail()) {
5011  // In tolerant mode, simply ignore the line.
5012  if (tolerant) {
5013  break;
5014  }
5015  // We repeat the full test here so the exception
5016  // message is more informative.
5017  TEUCHOS_TEST_FOR_EXCEPTION(
5018  ! tolerant && (istr.eof() || istr.fail()),
5019  std::runtime_error,
5020  "Line " << lineNumber << " of the Matrix Market file is "
5021  "empty, or we cannot read from it for some other reason.");
5022  }
5023  // Current matrix entry to read in.
5024  ST val = STS::zero();
5025  // Real and imaginary parts of the current matrix entry.
5026  // The imaginary part is zero if the matrix is real-valued.
5027  MT real = STM::zero(), imag = STM::zero();
5028 
5029  // isComplex refers to the input stream's data, not to
5030  // the scalar type S. It's OK to read real-valued
5031  // data into a matrix storing complex-valued data; in
5032  // that case, all entries' imaginary parts are zero.
5033  if (isComplex) {
5034  // STS::real() and STS::imag() return a copy of
5035  // their respective components, not a writeable
5036  // reference. Otherwise we could just assign to
5037  // them using the istream extraction operator (>>).
5038  // That's why we have separate magnitude type "real"
5039  // and "imag" variables.
5040 
5041  // Attempt to read the real part of the current entry.
5042  istr >> real;
5043  if (istr.fail()) {
5044  TEUCHOS_TEST_FOR_EXCEPTION(
5045  ! tolerant && istr.eof(), std::runtime_error,
5046  "Failed to get the real part of a complex-valued matrix "
5047  "entry from line " << lineNumber << " of the Matrix Market "
5048  "file.");
5049  // In tolerant mode, just skip bad lines.
5050  if (tolerant) {
5051  break;
5052  }
5053  } else if (istr.eof()) {
5054  TEUCHOS_TEST_FOR_EXCEPTION(
5055  ! tolerant && istr.eof(), std::runtime_error,
5056  "Missing imaginary part of a complex-valued matrix entry "
5057  "on line " << lineNumber << " of the Matrix Market file.");
5058  // In tolerant mode, let any missing imaginary part be 0.
5059  } else {
5060  // Attempt to read the imaginary part of the current
5061  // matrix entry.
5062  istr >> imag;
5063  TEUCHOS_TEST_FOR_EXCEPTION(
5064  ! tolerant && istr.fail(), std::runtime_error,
5065  "Failed to get the imaginary part of a complex-valued "
5066  "matrix entry from line " << lineNumber << " of the "
5067  "Matrix Market file.");
5068  // In tolerant mode, let any missing or corrupted
5069  // imaginary part be 0.
5070  }
5071  } else { // Matrix Market file contains real-valued data.
5072  // Attempt to read the current matrix entry.
5073  istr >> real;
5074  TEUCHOS_TEST_FOR_EXCEPTION(
5075  ! tolerant && istr.fail(), std::runtime_error,
5076  "Failed to get a real-valued matrix entry from line "
5077  << lineNumber << " of the Matrix Market file.");
5078  // In tolerant mode, simply ignore the line if
5079  // we failed to read a matrix entry.
5080  if (istr.fail() && tolerant) {
5081  break;
5082  }
5083  }
5084  // In tolerant mode, we simply let pass through whatever
5085  // data we got.
5086  TEUCHOS_TEST_FOR_EXCEPTION(
5087  ! tolerant && istr.fail(), std::runtime_error,
5088  "Failed to read matrix data from line " << lineNumber
5089  << " of the Matrix Market file.");
5090 
5091  // Assign val = ST(real, imag).
5092  Teuchos::MatrixMarket::details::assignScalar<ST> (val, real, imag);
5093 
5094  curRow = count % numRows;
5095  curCol = count / numRows;
5096  X_view[curRow + curCol*stride] = val;
5097  ++count;
5098  } // if not a comment line
5099  } // while there are still lines in the file, get the next one
5100 
5101  TEUCHOS_TEST_FOR_EXCEPTION(
5102  ! tolerant && static_cast<global_size_t> (count) < numRows * numCols,
5103  std::runtime_error,
5104  "The Matrix Market metadata reports that the dense matrix is "
5105  << numRows << " x " << numCols << ", and thus has "
5106  << numRows*numCols << " total entries, but we only found " << count
5107  << " entr" << (count == 1 ? "y" : "ies") << " in the file.");
5108  } catch (std::exception& e) {
5109  exMsg << e.what ();
5110  localReadDataSuccess = 0;
5111  }
5112  } // if (myRank == 0)
5113 
5114  if (debug) {
5115  *err << myRank << ": readVectorImpl: done reading data" << endl;
5116  }
5117 
5118  // Synchronize on whether Proc 0 successfully read the data.
5119  int globalReadDataSuccess = localReadDataSuccess;
5120  broadcast (*comm, 0, outArg (globalReadDataSuccess));
5121  TEUCHOS_TEST_FOR_EXCEPTION(
5122  globalReadDataSuccess == 0, std::runtime_error,
5123  "Failed to read the multivector's data: " << exMsg.str ());
5124 
5125  // If there's only one MPI process and the user didn't supply
5126  // a Map (i.e., pMap is null), we're done. Set pMap to the
5127  // Map used to distribute X, and return X.
5128  if (comm->getSize () == 1 && map.is_null ()) {
5129  map = proc0Map;
5130  if (! err.is_null ()) {
5131  err->popTab ();
5132  }
5133  if (debug) {
5134  *err << myRank << ": readVectorImpl: done" << endl;
5135  }
5136  if (! err.is_null ()) {
5137  err->popTab ();
5138  }
5139  return X;
5140  }
5141 
5142  if (debug) {
5143  *err << myRank << ": readVectorImpl: Creating target MV" << endl;
5144  }
5145 
5146  // Make a multivector Y with the distributed map pMap.
5147  RCP<MV> Y = createVector<ST, LO, GO, NT> (map);
5148 
5149  if (debug) {
5150  *err << myRank << ": readVectorImpl: Creating Export" << endl;
5151  }
5152 
5153  // Make an Export object that will export X to Y. First
5154  // argument is the source map, second argument is the target
5155  // map.
5156  Export<LO, GO, NT> exporter (proc0Map, map, err);
5157 
5158  if (debug) {
5159  *err << myRank << ": readVectorImpl: Exporting" << endl;
5160  }
5161  // Export X into Y.
5162  Y->doExport (*X, exporter, INSERT);
5163 
5164  if (! err.is_null ()) {
5165  err->popTab ();
5166  }
5167  if (debug) {
5168  *err << myRank << ": readVectorImpl: done" << endl;
5169  }
5170  if (! err.is_null ()) {
5171  err->popTab ();
5172  }
5173 
5174  // Y is distributed over all process(es) in the communicator.
5175  return Y;
5176  }
5177 
5178  public:
5198  static Teuchos::RCP<const map_type>
5199  readMap (std::istream& in,
5200  const Teuchos::RCP<const comm_type>& comm,
5201  const bool tolerant=false,
5202  const bool debug=false)
5203  {
5204  Teuchos::RCP<Teuchos::FancyOStream> err =
5205  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
5206  return readMap (in, comm, err, tolerant, debug);
5207  }
5208 
5209 
5235  static Teuchos::RCP<const map_type>
5236  readMap (std::istream& in,
5237  const Teuchos::RCP<const comm_type>& comm,
5238  const Teuchos::RCP<Teuchos::FancyOStream>& err,
5239  const bool tolerant=false,
5240  const bool debug=false)
5241  {
5242  using Teuchos::arcp;
5243  using Teuchos::Array;
5244  using Teuchos::ArrayRCP;
5245  using Teuchos::as;
5246  using Teuchos::broadcast;
5247  using Teuchos::Comm;
5248  using Teuchos::CommRequest;
5249  using Teuchos::inOutArg;
5250  using Teuchos::ireceive;
5251  using Teuchos::outArg;
5252  using Teuchos::RCP;
5253  using Teuchos::receive;
5254  using Teuchos::reduceAll;
5255  using Teuchos::REDUCE_MIN;
5256  using Teuchos::isend;
5257  using Teuchos::SerialComm;
5258  using Teuchos::toString;
5259  using Teuchos::wait;
5260  using std::endl;
5261  typedef Tpetra::global_size_t GST;
5262  typedef ptrdiff_t int_type; // Can hold int and GO
5263  typedef local_ordinal_type LO;
5264  typedef global_ordinal_type GO;
5265  typedef node_type NT;
5267 
5268  const int numProcs = comm->getSize ();
5269  const int myRank = comm->getRank ();
5270 
5271  if (err.is_null ()) {
5272  err->pushTab ();
5273  }
5274  if (debug) {
5275  std::ostringstream os;
5276  os << myRank << ": readMap: " << endl;
5277  *err << os.str ();
5278  }
5279  if (err.is_null ()) {
5280  err->pushTab ();
5281  }
5282 
5283  // Tag for receive-size / send-size messages. writeMap used
5284  // tags 1337 and 1338; we count up from there.
5285  const int sizeTag = 1339;
5286  // Tag for receive-data / send-data messages.
5287  const int dataTag = 1340;
5288 
5289  // These are for sends on Process 0, and for receives on all
5290  // other processes. sizeReq is for the {receive,send}-size
5291  // message, and dataReq is for the message containing the
5292  // actual GIDs to belong to the receiving process.
5293  RCP<CommRequest<int> > sizeReq;
5294  RCP<CommRequest<int> > dataReq;
5295 
5296  // Each process will have to receive the number of GIDs to
5297  // expect. Thus, we can post the receives now, and cancel
5298  // them if something should go wrong in the meantime.
5299  ArrayRCP<int_type> numGidsToRecv (1);
5300  numGidsToRecv[0] = 0;
5301  if (myRank != 0) {
5302  sizeReq = ireceive<int, int_type> (numGidsToRecv, 0, sizeTag, *comm);
5303  }
5304 
5305  int readSuccess = 1;
5306  std::ostringstream exMsg;
5307  RCP<MV> data; // Will only be valid on Proc 0
5308  if (myRank == 0) {
5309  // If we want to reuse readDenseImpl, we have to make a
5310  // communicator that only contains Proc 0. Otherwise,
5311  // readDenseImpl will redistribute the data to all
5312  // processes. While we eventually want that, neither we nor
5313  // readDenseImpl know the correct Map to use at the moment.
5314  // That depends on the second column of the multivector.
5315  RCP<const Comm<int> > proc0Comm (new SerialComm<int> ());
5316  try {
5317  RCP<const map_type> dataMap;
5318  // This is currently the only place where we use the
5319  // 'tolerant' argument. Later, if we want to be clever,
5320  // we could have tolerant mode allow PIDs out of order.
5321  data = readDenseImpl<GO> (in, proc0Comm, dataMap, err, tolerant, debug);
5322  (void) dataMap; // Silence "unused" warnings
5323  if (data.is_null ()) {
5324  readSuccess = 0;
5325  exMsg << "readDenseImpl() returned null." << endl;
5326  }
5327  } catch (std::exception& e) {
5328  readSuccess = 0;
5329  exMsg << e.what () << endl;
5330  }
5331  }
5332 
5333  // Map from PID to all the GIDs for that PID.
5334  // Only populated on Process 0.
5335  std::map<int, Array<GO> > pid2gids;
5336 
5337  // The index base must be the global minimum GID.
5338  // We will compute this on Process 0 and broadcast,
5339  // so that all processes can set up the Map.
5340  int_type globalNumGIDs = 0;
5341 
5342  // The index base must be the global minimum GID.
5343  // We will compute this on Process 0 and broadcast,
5344  // so that all processes can set up the Map.
5345  GO indexBase = 0;
5346 
5347  // Process 0: If the above read of the MultiVector succeeded,
5348  // extract the GIDs and PIDs into pid2gids, and find the
5349  // global min GID.
5350  if (myRank == 0 && readSuccess == 1) {
5351  if (data->getNumVectors () == 2) { // Map format 1.0
5352  ArrayRCP<const GO> GIDs = data->getData (0);
5353  ArrayRCP<const GO> PIDs = data->getData (1); // convert to int
5354  globalNumGIDs = GIDs.size ();
5355 
5356  // Start computing the global min GID, while collecting
5357  // the GIDs for each PID.
5358  if (globalNumGIDs > 0) {
5359  const int pid = static_cast<int> (PIDs[0]);
5360 
5361  if (pid < 0 || pid >= numProcs) {
5362  readSuccess = 0;
5363  exMsg << "Tpetra::MatrixMarket::readMap: "
5364  << "Encountered invalid PID " << pid << "." << endl;
5365  }
5366  else {
5367  const GO gid = GIDs[0];
5368  pid2gids[pid].push_back (gid);
5369  indexBase = gid; // the current min GID
5370  }
5371  }
5372  if (readSuccess == 1) {
5373  // Collect the rest of the GIDs for each PID, and compute
5374  // the global min GID.
5375  for (size_type k = 1; k < globalNumGIDs; ++k) {
5376  const int pid = static_cast<int> (PIDs[k]);
5377  if (pid < 0 || pid >= numProcs) {
5378  readSuccess = 0;
5379  exMsg << "Tpetra::MatrixMarket::readMap: "
5380  << "Encountered invalid PID " << pid << "." << endl;
5381  }
5382  else {
5383  const int_type gid = GIDs[k];
5384  pid2gids[pid].push_back (gid);
5385  if (gid < indexBase) {
5386  indexBase = gid; // the current min GID
5387  }
5388  }
5389  }
5390  }
5391  }
5392  else if (data->getNumVectors () == 1) { // Map format 2.0
5393  if (data->getGlobalLength () % 2 != static_cast<GST> (0)) {
5394  readSuccess = 0;
5395  exMsg << "Tpetra::MatrixMarket::readMap: Input data has the "
5396  "wrong format (for Map format 2.0). The global number of rows "
5397  "in the MultiVector must be even (divisible by 2)." << endl;
5398  }
5399  else {
5400  ArrayRCP<const GO> theData = data->getData (0);
5401  globalNumGIDs = static_cast<GO> (data->getGlobalLength ()) /
5402  static_cast<GO> (2);
5403 
5404  // Start computing the global min GID, while
5405  // collecting the GIDs for each PID.
5406  if (globalNumGIDs > 0) {
5407  const int pid = static_cast<int> (theData[1]);
5408  if (pid < 0 || pid >= numProcs) {
5409  readSuccess = 0;
5410  exMsg << "Tpetra::MatrixMarket::readMap: "
5411  << "Encountered invalid PID " << pid << "." << endl;
5412  }
5413  else {
5414  const GO gid = theData[0];
5415  pid2gids[pid].push_back (gid);
5416  indexBase = gid; // the current min GID
5417  }
5418  }
5419  // Collect the rest of the GIDs for each PID, and
5420  // compute the global min GID.
5421  for (int_type k = 1; k < globalNumGIDs; ++k) {
5422  const int pid = static_cast<int> (theData[2*k + 1]);
5423  if (pid < 0 || pid >= numProcs) {
5424  readSuccess = 0;
5425  exMsg << "Tpetra::MatrixMarket::readMap: "
5426  << "Encountered invalid PID " << pid << "." << endl;
5427  }
5428  else {
5429  const GO gid = theData[2*k];
5430  pid2gids[pid].push_back (gid);
5431  if (gid < indexBase) {
5432  indexBase = gid; // the current min GID
5433  }
5434  }
5435  } // for each GID
5436  } // if the amount of data is correct
5437  }
5438  else {
5439  readSuccess = 0;
5440  exMsg << "Tpetra::MatrixMarket::readMap: Input data must have "
5441  "either 1 column (for the new Map format 2.0) or 2 columns (for "
5442  "the old Map format 1.0).";
5443  }
5444  } // myRank is zero
5445 
5446  // Broadcast the indexBase, the global number of GIDs, and the
5447  // current success status. Use int_type for all of these.
5448  {
5449  int_type readResults[3];
5450  readResults[0] = static_cast<int_type> (indexBase);
5451  readResults[1] = static_cast<int_type> (globalNumGIDs);
5452  readResults[2] = static_cast<int_type> (readSuccess);
5453  broadcast<int, int_type> (*comm, 0, 3, readResults);
5454 
5455  indexBase = static_cast<GO> (readResults[0]);
5456  globalNumGIDs = static_cast<int_type> (readResults[1]);
5457  readSuccess = static_cast<int> (readResults[2]);
5458  }
5459 
5460  // Unwinding the stack will invoke sizeReq's destructor, which
5461  // will cancel the receive-size request on all processes that
5462  // posted it.
5463  TEUCHOS_TEST_FOR_EXCEPTION(
5464  readSuccess != 1, std::runtime_error,
5465  "Tpetra::MatrixMarket::readMap: Reading the Map failed with the "
5466  "following exception message: " << exMsg.str ());
5467 
5468  if (myRank == 0) {
5469  // Proc 0: Send each process' number of GIDs to that process.
5470  for (int p = 1; p < numProcs; ++p) {
5471  ArrayRCP<int_type> numGidsToSend (1);
5472 
5473  auto it = pid2gids.find (p);
5474  if (it == pid2gids.end ()) {
5475  numGidsToSend[0] = 0;
5476  } else {
5477  numGidsToSend[0] = it->second.size ();
5478  }
5479  sizeReq = isend<int, int_type> (numGidsToSend, p, sizeTag, *comm);
5480  wait<int> (*comm, outArg (sizeReq));
5481  }
5482  }
5483  else {
5484  // Wait on the receive-size message to finish.
5485  wait<int> (*comm, outArg (sizeReq));
5486  }
5487 
5488  // Allocate / get the array for my GIDs.
5489  // Only Process 0 will have its actual GIDs at this point.
5490  ArrayRCP<GO> myGids;
5491  int_type myNumGids = 0;
5492  if (myRank == 0) {
5493  GO* myGidsRaw = NULL;
5494 
5495  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (0);
5496  if (it != pid2gids.end ()) {
5497  myGidsRaw = it->second.getRawPtr ();
5498  myNumGids = it->second.size ();
5499  // Nonowning ArrayRCP just views the Array.
5500  myGids = arcp<GO> (myGidsRaw, 0, myNumGids, false);
5501  }
5502  }
5503  else { // myRank != 0
5504  myNumGids = numGidsToRecv[0];
5505  myGids = arcp<GO> (myNumGids);
5506  }
5507 
5508  if (myRank != 0) {
5509  // Post receive for data, now that we know how much data we
5510  // will receive. Only post receive if my process actually
5511  // has nonzero GIDs.
5512  if (myNumGids > 0) {
5513  dataReq = ireceive<int, GO> (myGids, 0, dataTag, *comm);
5514  }
5515  }
5516 
5517  for (int p = 1; p < numProcs; ++p) {
5518  if (myRank == 0) {
5519  ArrayRCP<GO> sendGids; // to send to Process p
5520  GO* sendGidsRaw = NULL;
5521  int_type numSendGids = 0;
5522 
5523  typename std::map<int, Array<GO> >::iterator it = pid2gids.find (p);
5524  if (it != pid2gids.end ()) {
5525  numSendGids = it->second.size ();
5526  sendGidsRaw = it->second.getRawPtr ();
5527  sendGids = arcp<GO> (sendGidsRaw, 0, numSendGids, false);
5528  }
5529  // Only send if that process actually has nonzero GIDs.
5530  if (numSendGids > 0) {
5531  dataReq = isend<int, GO> (sendGids, p, dataTag, *comm);
5532  }
5533  wait<int> (*comm, outArg (dataReq));
5534  }
5535  else if (myRank == p) {
5536  // Wait on my receive of GIDs to finish.
5537  wait<int> (*comm, outArg (dataReq));
5538  }
5539  } // for each process rank p in 1, 2, ..., numProcs-1
5540 
5541  if (debug) {
5542  std::ostringstream os;
5543  os << myRank << ": readMap: creating Map" << endl;
5544  *err << os.str ();
5545  }
5546  const GST INVALID = Teuchos::OrdinalTraits<GST>::invalid ();
5547  RCP<const map_type> newMap;
5548 
5549  // Create the Map; test whether the constructor threw. This
5550  // avoids deadlock and makes error reporting more readable.
5551 
5552  int lclSuccess = 1;
5553  int gblSuccess = 0; // output argument
5554  std::ostringstream errStrm;
5555  try {
5556  newMap = rcp (new map_type (INVALID, myGids (), indexBase, comm));
5557  }
5558  catch (std::exception& e) {
5559  lclSuccess = 0;
5560  errStrm << "Process " << comm->getRank () << " threw an exception: "
5561  << e.what () << std::endl;
5562  }
5563  catch (...) {
5564  lclSuccess = 0;
5565  errStrm << "Process " << comm->getRank () << " threw an exception "
5566  "not a subclass of std::exception" << std::endl;
5567  }
5568  Teuchos::reduceAll<int, int> (*comm, Teuchos::REDUCE_MIN,
5569  lclSuccess, Teuchos::outArg (gblSuccess));
5570  if (gblSuccess != 1) {
5571  Tpetra::Details::gathervPrint (std::cerr, errStrm.str (), *comm);
5572  }
5573  TEUCHOS_TEST_FOR_EXCEPTION(gblSuccess != 1, std::runtime_error, "Map constructor failed!");
5574 
5575  if (err.is_null ()) {
5576  err->popTab ();
5577  }
5578  if (debug) {
5579  std::ostringstream os;
5580  os << myRank << ": readMap: done" << endl;
5581  *err << os.str ();
5582  }
5583  if (err.is_null ()) {
5584  err->popTab ();
5585  }
5586  return newMap;
5587  }
5588 
5589 
5590  private:
5591 
5602  static int
5603  encodeDataType (const std::string& dataType)
5604  {
5605  if (dataType == "real" || dataType == "integer") {
5606  return 0;
5607  } else if (dataType == "complex") {
5608  return 1;
5609  } else if (dataType == "pattern") {
5610  return 2;
5611  } else {
5612  // We should never get here, since Banner validates the
5613  // reported data type and ensures it is one of the accepted
5614  // values.
5615  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
5616  "Unrecognized Matrix Market data type \"" << dataType
5617  << "\". We should never get here. "
5618  "Please report this bug to the Tpetra developers.");
5619  }
5620  }
5621  }; // class Reader
5622 
5651  template<class SparseMatrixType>
5652  class Writer {
5653  public:
5655  typedef SparseMatrixType sparse_matrix_type;
5656  typedef Teuchos::RCP<sparse_matrix_type> sparse_matrix_ptr;
5657 
5659  typedef typename SparseMatrixType::scalar_type scalar_type;
5661  typedef typename SparseMatrixType::local_ordinal_type local_ordinal_type;
5667  typedef typename SparseMatrixType::global_ordinal_type global_ordinal_type;
5669  typedef typename SparseMatrixType::node_type node_type;
5670 
5672  typedef MultiVector<scalar_type,
5680 
5683 
5715  static void
5716  writeSparseFile (const std::string& filename,
5717  const sparse_matrix_type& matrix,
5718  const std::string& matrixName,
5719  const std::string& matrixDescription,
5720  const bool debug=false)
5721  {
5722  Teuchos::RCP<const Teuchos::Comm<int> > comm = matrix.getComm ();
5723  TEUCHOS_TEST_FOR_EXCEPTION
5724  (comm.is_null (), std::invalid_argument,
5725  "The input matrix's communicator (Teuchos::Comm object) is null.");
5726  const int myRank = comm->getRank ();
5727  std::ofstream out;
5728 
5729  // Only open the file on Rank 0.
5730  if (myRank == 0) {
5731  out.open (filename.c_str ());
5732  }
5733  writeSparse (out, matrix, matrixName, matrixDescription, debug);
5734  // We can rely on the destructor of the output stream to close
5735  // the file on scope exit, even if writeSparse() throws an
5736  // exception.
5737  }
5738 
5740  static void
5741  writeSparseFile (const std::string& filename,
5742  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5743  const std::string& matrixName,
5744  const std::string& matrixDescription,
5745  const bool debug=false)
5746  {
5747  TEUCHOS_TEST_FOR_EXCEPTION
5748  (pMatrix.is_null (), std::invalid_argument,
5749  "The input matrix is null.");
5750  writeSparseFile (filename, *pMatrix, matrixName,
5751  matrixDescription, debug);
5752  }
5753 
5773  static void
5774  writeSparseFile (const std::string& filename,
5775  const sparse_matrix_type& matrix,
5776  const bool debug=false)
5777  {
5778  writeSparseFile (filename, matrix, "", "", debug);
5779  }
5780 
5782  static void
5783  writeSparseFile (const std::string& filename,
5784  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
5785  const bool debug=false)
5786  {
5787  writeSparseFile (filename, *pMatrix, "", "", debug);
5788  }
5789 
5820  static void
5821  writeSparse (std::ostream& out,
5822  const sparse_matrix_type& matrix,
5823  const std::string& matrixName,
5824  const std::string& matrixDescription,
5825  const bool debug=false)
5826  {
5827  using Teuchos::ArrayView;
5828  using Teuchos::Comm;
5829  using Teuchos::FancyOStream;
5830  using Teuchos::getFancyOStream;
5831  using Teuchos::null;
5832  using Teuchos::RCP;
5833  using Teuchos::rcpFromRef;
5834  using std::cerr;
5835  using std::endl;
5836  using ST = scalar_type;
5837  using LO = local_ordinal_type;
5838  using GO = global_ordinal_type;
5839  using STS = typename Teuchos::ScalarTraits<ST>;
5840 
5841  // Make the output stream write floating-point numbers in
5842  // scientific notation. It will politely put the output
5843  // stream back to its state on input, when this scope
5844  // terminates.
5845  Teuchos::SetScientific<ST> sci (out);
5846 
5847  // Get the matrix's communicator.
5848  RCP<const Comm<int> > comm = matrix.getComm ();
5849  TEUCHOS_TEST_FOR_EXCEPTION(
5850  comm.is_null (), std::invalid_argument,
5851  "The input matrix's communicator (Teuchos::Comm object) is null.");
5852  const int myRank = comm->getRank ();
5853 
5854  // Optionally, make a stream for debugging output.
5855  RCP<FancyOStream> err =
5856  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
5857  if (debug) {
5858  std::ostringstream os;
5859  os << myRank << ": writeSparse" << endl;
5860  *err << os.str ();
5861  comm->barrier ();
5862  os << "-- " << myRank << ": past barrier" << endl;
5863  *err << os.str ();
5864  }
5865 
5866  // Whether to print debugging output to stderr.
5867  const bool debugPrint = debug && myRank == 0;
5868 
5869  RCP<const map_type> rowMap = matrix.getRowMap ();
5870  RCP<const map_type> colMap = matrix.getColMap ();
5871  RCP<const map_type> domainMap = matrix.getDomainMap ();
5872  RCP<const map_type> rangeMap = matrix.getRangeMap ();
5873 
5874  const global_size_t numRows = rangeMap->getGlobalNumElements ();
5875  const global_size_t numCols = domainMap->getGlobalNumElements ();
5876 
5877  if (debug && myRank == 0) {
5878  std::ostringstream os;
5879  os << "-- Input sparse matrix is:"
5880  << "---- " << numRows << " x " << numCols << endl
5881  << "---- "
5882  << (matrix.isGloballyIndexed() ? "Globally" : "Locally")
5883  << " indexed." << endl
5884  << "---- Its row map has " << rowMap->getGlobalNumElements ()
5885  << " elements." << endl
5886  << "---- Its col map has " << colMap->getGlobalNumElements ()
5887  << " elements." << endl;
5888  *err << os.str ();
5889  }
5890  // Make the "gather" row map, where Proc 0 owns all rows and
5891  // the other procs own no rows.
5892  const size_t localNumRows = (myRank == 0) ? numRows : 0;
5893  if (debug) {
5894  std::ostringstream os;
5895  os << "-- " << myRank << ": making gatherRowMap" << endl;
5896  *err << os.str ();
5897  }
5898  RCP<const map_type> gatherRowMap =
5899  Details::computeGatherMap (rowMap, err, debug);
5900 
5901  // Since the matrix may in general be non-square, we need to
5902  // make a column map as well. In this case, the column map
5903  // contains all the columns of the original matrix, because we
5904  // are gathering the whole matrix onto Proc 0. We call
5905  // computeGatherMap to preserve the original order of column
5906  // indices over all the processes.
5907  const size_t localNumCols = (myRank == 0) ? numCols : 0;
5908  RCP<const map_type> gatherColMap =
5909  Details::computeGatherMap (colMap, err, debug);
5910 
5911  // Current map is the source map, gather map is the target map.
5912  typedef Import<LO, GO, node_type> import_type;
5913  import_type importer (rowMap, gatherRowMap);
5914 
5915  // Create a new CrsMatrix to hold the result of the import.
5916  // The constructor needs a column map as well as a row map,
5917  // for the case that the matrix is not square.
5918  RCP<sparse_matrix_type> newMatrix =
5919  rcp (new sparse_matrix_type (gatherRowMap, gatherColMap,
5920  static_cast<size_t> (0)));
5921  // Import the sparse matrix onto Proc 0.
5922  newMatrix->doImport (matrix, importer, INSERT);
5923 
5924  // fillComplete() needs the domain and range maps for the case
5925  // that the matrix is not square.
5926  {
5927  RCP<const map_type> gatherDomainMap =
5928  rcp (new map_type (numCols, localNumCols,
5929  domainMap->getIndexBase (),
5930  comm));
5931  RCP<const map_type> gatherRangeMap =
5932  rcp (new map_type (numRows, localNumRows,
5933  rangeMap->getIndexBase (),
5934  comm));
5935  newMatrix->fillComplete (gatherDomainMap, gatherRangeMap);
5936  }
5937 
5938  if (debugPrint) {
5939  cerr << "-- Output sparse matrix is:"
5940  << "---- " << newMatrix->getRangeMap ()->getGlobalNumElements ()
5941  << " x "
5942  << newMatrix->getDomainMap ()->getGlobalNumElements ()
5943  << " with "
5944  << newMatrix->getGlobalNumEntries () << " entries;" << endl
5945  << "---- "
5946  << (newMatrix->isGloballyIndexed () ? "Globally" : "Locally")
5947  << " indexed." << endl
5948  << "---- Its row map has "
5949  << newMatrix->getRowMap ()->getGlobalNumElements ()
5950  << " elements, with index base "
5951  << newMatrix->getRowMap ()->getIndexBase () << "." << endl
5952  << "---- Its col map has "
5953  << newMatrix->getColMap ()->getGlobalNumElements ()
5954  << " elements, with index base "
5955  << newMatrix->getColMap ()->getIndexBase () << "." << endl
5956  << "---- Element count of output matrix's column Map may differ "
5957  << "from that of the input matrix's column Map, if some columns "
5958  << "of the matrix contain no entries." << endl;
5959  }
5960 
5961  //
5962  // Print the metadata and the matrix entries on Rank 0.
5963  //
5964  if (myRank == 0) {
5965  // Print the Matrix Market banner line. CrsMatrix stores
5966  // data nonsymmetrically ("general"). This implies that
5967  // readSparse() on a symmetrically stored input file,
5968  // followed by writeSparse() on the resulting sparse matrix,
5969  // will result in an output file with a different banner
5970  // line than the original input file.
5971  out << "%%MatrixMarket matrix coordinate "
5972  << (STS::isComplex ? "complex" : "real")
5973  << " general" << endl;
5974 
5975  // Print comments (the matrix name and / or description).
5976  if (matrixName != "") {
5977  printAsComment (out, matrixName);
5978  }
5979  if (matrixDescription != "") {
5980  printAsComment (out, matrixDescription);
5981  }
5982 
5983  // Print the Matrix Market header (# rows, # columns, #
5984  // nonzeros). Use the range resp. domain map for the number
5985  // of rows resp. columns, since Tpetra::CrsMatrix uses the
5986  // column map for the number of columns. That only
5987  // corresponds to the "linear-algebraic" number of columns
5988  // when the column map is uniquely owned (a.k.a. one-to-one),
5989  // which only happens if the matrix is (block) diagonal.
5990  out << newMatrix->getRangeMap ()->getGlobalNumElements () << " "
5991  << newMatrix->getDomainMap ()->getGlobalNumElements () << " "
5992  << newMatrix->getGlobalNumEntries () << endl;
5993 
5994  // The Matrix Market format expects one-based row and column
5995  // indices. We'll convert the indices on output from
5996  // whatever index base they use to one-based indices.
5997  const GO rowIndexBase = gatherRowMap->getIndexBase ();
5998  const GO colIndexBase = newMatrix->getColMap()->getIndexBase ();
5999  //
6000  // Print the entries of the matrix.
6001  //
6002  // newMatrix can never be globally indexed, since we called
6003  // fillComplete() on it. We include code for both cases
6004  // (globally or locally indexed) just in case that ever
6005  // changes.
6006  if (newMatrix->isGloballyIndexed()) {
6007  // We know that the "gather" row Map is contiguous, so we
6008  // don't need to get the list of GIDs.
6009  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6010  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6011  for (GO globalRowIndex = minAllGlobalIndex;
6012  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6013  ++globalRowIndex) {
6014  typename sparse_matrix_type::global_inds_host_view_type ind;
6015  typename sparse_matrix_type::values_host_view_type val;
6016  newMatrix->getGlobalRowView (globalRowIndex, ind, val);
6017  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6018  const GO globalColIndex = ind(ii);
6019  // Convert row and column indices to 1-based.
6020  // This works because the global index type is signed.
6021  out << (globalRowIndex + 1 - rowIndexBase) << " "
6022  << (globalColIndex + 1 - colIndexBase) << " ";
6023  if (STS::isComplex) {
6024  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6025  } else {
6026  out << val(ii);
6027  }
6028  out << endl;
6029  } // For each entry in the current row
6030  } // For each row of the "gather" matrix
6031  }
6032  else { // newMatrix is locally indexed
6033  using OTG = Teuchos::OrdinalTraits<GO>;
6034  for (LO localRowIndex = gatherRowMap->getMinLocalIndex();
6035  localRowIndex <= gatherRowMap->getMaxLocalIndex();
6036  ++localRowIndex) {
6037  // Convert from local to global row index.
6038  const GO globalRowIndex =
6039  gatherRowMap->getGlobalElement (localRowIndex);
6040  TEUCHOS_TEST_FOR_EXCEPTION(
6041  globalRowIndex == OTG::invalid(), std::logic_error,
6042  "Failed to convert the supposed local row index "
6043  << localRowIndex << " into a global row index. "
6044  "Please report this bug to the Tpetra developers.");
6045  typename sparse_matrix_type::local_inds_host_view_type ind;
6046  typename sparse_matrix_type::values_host_view_type val;
6047  newMatrix->getLocalRowView (localRowIndex, ind, val);
6048  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6049  // Convert the column index from local to global.
6050  const GO globalColIndex =
6051  newMatrix->getColMap()->getGlobalElement (ind(ii));
6052  TEUCHOS_TEST_FOR_EXCEPTION(
6053  globalColIndex == OTG::invalid(), std::logic_error,
6054  "On local row " << localRowIndex << " of the sparse matrix: "
6055  "Failed to convert the supposed local column index "
6056  << ind(ii) << " into a global column index. Please report "
6057  "this bug to the Tpetra developers.");
6058  // Convert row and column indices to 1-based.
6059  // This works because the global index type is signed.
6060  out << (globalRowIndex + 1 - rowIndexBase) << " "
6061  << (globalColIndex + 1 - colIndexBase) << " ";
6062  if (STS::isComplex) {
6063  out << STS::real (val(ii)) << " " << STS::imag (val(ii));
6064  } else {
6065  out << val(ii);
6066  }
6067  out << endl;
6068  } // For each entry in the current row
6069  } // For each row of the "gather" matrix
6070  } // Whether the "gather" matrix is locally or globally indexed
6071  } // If my process' rank is 0
6072  }
6073 
6075  static void
6076  writeSparse (std::ostream& out,
6077  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6078  const std::string& matrixName,
6079  const std::string& matrixDescription,
6080  const bool debug=false)
6081  {
6082  TEUCHOS_TEST_FOR_EXCEPTION
6083  (pMatrix.is_null (), std::invalid_argument,
6084  "The input matrix is null.");
6085  writeSparse (out, *pMatrix, matrixName, matrixDescription, debug);
6086  }
6087 
6118  static void
6119  writeSparseGraph (std::ostream& out,
6120  const crs_graph_type& graph,
6121  const std::string& graphName,
6122  const std::string& graphDescription,
6123  const bool debug=false)
6124  {
6125  using Teuchos::ArrayView;
6126  using Teuchos::Comm;
6127  using Teuchos::FancyOStream;
6128  using Teuchos::getFancyOStream;
6129  using Teuchos::null;
6130  using Teuchos::RCP;
6131  using Teuchos::rcpFromRef;
6132  using std::cerr;
6133  using std::endl;
6134  typedef local_ordinal_type LO;
6135  typedef global_ordinal_type GO;
6136 
6137  // Get the graph's communicator. Processes on which the
6138  // graph's Map or communicator is null don't participate in
6139  // this operation. This function shouldn't even be called on
6140  // those processes.
6141  auto rowMap = graph.getRowMap ();
6142  if (rowMap.is_null ()) {
6143  return;
6144  }
6145  auto comm = rowMap->getComm ();
6146  if (comm.is_null ()) {
6147  return;
6148  }
6149  const int myRank = comm->getRank ();
6150 
6151  // Optionally, make a stream for debugging output.
6152  RCP<FancyOStream> err =
6153  debug ? getFancyOStream (rcpFromRef (std::cerr)) : null;
6154  if (debug) {
6155  std::ostringstream os;
6156  os << myRank << ": writeSparseGraph" << endl;
6157  *err << os.str ();
6158  comm->barrier ();
6159  os << "-- " << myRank << ": past barrier" << endl;
6160  *err << os.str ();
6161  }
6162 
6163  // Whether to print debugging output to stderr.
6164  const bool debugPrint = debug && myRank == 0;
6165 
6166  // We've already gotten the rowMap above.
6167  auto colMap = graph.getColMap ();
6168  auto domainMap = graph.getDomainMap ();
6169  auto rangeMap = graph.getRangeMap ();
6170 
6171  const global_size_t numRows = rangeMap->getGlobalNumElements ();
6172  const global_size_t numCols = domainMap->getGlobalNumElements ();
6173 
6174  if (debug && myRank == 0) {
6175  std::ostringstream os;
6176  os << "-- Input sparse graph is:"
6177  << "---- " << numRows << " x " << numCols << " with "
6178  << graph.getGlobalNumEntries () << " entries;" << endl
6179  << "---- "
6180  << (graph.isGloballyIndexed () ? "Globally" : "Locally")
6181  << " indexed." << endl
6182  << "---- Its row Map has " << rowMap->getGlobalNumElements ()
6183  << " elements." << endl
6184  << "---- Its col Map has " << colMap->getGlobalNumElements ()
6185  << " elements." << endl;
6186  *err << os.str ();
6187  }
6188  // Make the "gather" row map, where Proc 0 owns all rows and
6189  // the other procs own no rows.
6190  const size_t localNumRows = (myRank == 0) ? numRows : 0;
6191  if (debug) {
6192  std::ostringstream os;
6193  os << "-- " << myRank << ": making gatherRowMap" << endl;
6194  *err << os.str ();
6195  }
6196  auto gatherRowMap = Details::computeGatherMap (rowMap, err, debug);
6197 
6198  // Since the graph may in general be non-square, we need to
6199  // make a column map as well. In this case, the column map
6200  // contains all the columns of the original graph, because we
6201  // are gathering the whole graph onto Proc 0. We call
6202  // computeGatherMap to preserve the original order of column
6203  // indices over all the processes.
6204  const size_t localNumCols = (myRank == 0) ? numCols : 0;
6205  auto gatherColMap = Details::computeGatherMap (colMap, err, debug);
6206 
6207  // Current map is the source map, gather map is the target map.
6208  Import<LO, GO, node_type> importer (rowMap, gatherRowMap);
6209 
6210  // Create a new CrsGraph to hold the result of the import.
6211  // The constructor needs a column map as well as a row map,
6212  // for the case that the graph is not square.
6213  crs_graph_type newGraph (gatherRowMap, gatherColMap,
6214  static_cast<size_t> (0));
6215  // Import the sparse graph onto Proc 0.
6216  newGraph.doImport (graph, importer, INSERT);
6217 
6218  // fillComplete() needs the domain and range maps for the case
6219  // that the graph is not square.
6220  {
6221  RCP<const map_type> gatherDomainMap =
6222  rcp (new map_type (numCols, localNumCols,
6223  domainMap->getIndexBase (),
6224  comm));
6225  RCP<const map_type> gatherRangeMap =
6226  rcp (new map_type (numRows, localNumRows,
6227  rangeMap->getIndexBase (),
6228  comm));
6229  newGraph.fillComplete (gatherDomainMap, gatherRangeMap);
6230  }
6231 
6232  if (debugPrint) {
6233  cerr << "-- Output sparse graph is:"
6234  << "---- " << newGraph.getRangeMap ()->getGlobalNumElements ()
6235  << " x "
6236  << newGraph.getDomainMap ()->getGlobalNumElements ()
6237  << " with "
6238  << newGraph.getGlobalNumEntries () << " entries;" << endl
6239  << "---- "
6240  << (newGraph.isGloballyIndexed () ? "Globally" : "Locally")
6241  << " indexed." << endl
6242  << "---- Its row map has "
6243  << newGraph.getRowMap ()->getGlobalNumElements ()
6244  << " elements, with index base "
6245  << newGraph.getRowMap ()->getIndexBase () << "." << endl
6246  << "---- Its col map has "
6247  << newGraph.getColMap ()->getGlobalNumElements ()
6248  << " elements, with index base "
6249  << newGraph.getColMap ()->getIndexBase () << "." << endl
6250  << "---- Element count of output graph's column Map may differ "
6251  << "from that of the input matrix's column Map, if some columns "
6252  << "of the matrix contain no entries." << endl;
6253  }
6254 
6255  //
6256  // Print the metadata and the graph entries on Process 0 of
6257  // the graph's communicator.
6258  //
6259  if (myRank == 0) {
6260  // Print the Matrix Market banner line. CrsGraph stores
6261  // data nonsymmetrically ("general"). This implies that
6262  // readSparseGraph() on a symmetrically stored input file,
6263  // followed by writeSparseGraph() on the resulting sparse
6264  // graph, will result in an output file with a different
6265  // banner line than the original input file.
6266  out << "%%MatrixMarket matrix coordinate pattern general" << endl;
6267 
6268  // Print comments (the graph name and / or description).
6269  if (graphName != "") {
6270  printAsComment (out, graphName);
6271  }
6272  if (graphDescription != "") {
6273  printAsComment (out, graphDescription);
6274  }
6275 
6276  // Print the Matrix Market header (# rows, # columns, #
6277  // stored entries). Use the range resp. domain map for the
6278  // number of rows resp. columns, since Tpetra::CrsGraph uses
6279  // the column map for the number of columns. That only
6280  // corresponds to the "linear-algebraic" number of columns
6281  // when the column map is uniquely owned
6282  // (a.k.a. one-to-one), which only happens if the graph is
6283  // block diagonal (one block per process).
6284  out << newGraph.getRangeMap ()->getGlobalNumElements () << " "
6285  << newGraph.getDomainMap ()->getGlobalNumElements () << " "
6286  << newGraph.getGlobalNumEntries () << endl;
6287 
6288  // The Matrix Market format expects one-based row and column
6289  // indices. We'll convert the indices on output from
6290  // whatever index base they use to one-based indices.
6291  const GO rowIndexBase = gatherRowMap->getIndexBase ();
6292  const GO colIndexBase = newGraph.getColMap()->getIndexBase ();
6293  //
6294  // Print the entries of the graph.
6295  //
6296  // newGraph can never be globally indexed, since we called
6297  // fillComplete() on it. We include code for both cases
6298  // (globally or locally indexed) just in case that ever
6299  // changes.
6300  if (newGraph.isGloballyIndexed ()) {
6301  // We know that the "gather" row Map is contiguous, so we
6302  // don't need to get the list of GIDs.
6303  const GO minAllGlobalIndex = gatherRowMap->getMinAllGlobalIndex ();
6304  const GO maxAllGlobalIndex = gatherRowMap->getMaxAllGlobalIndex ();
6305  for (GO globalRowIndex = minAllGlobalIndex;
6306  globalRowIndex <= maxAllGlobalIndex; // inclusive range
6307  ++globalRowIndex) {
6308  typename crs_graph_type::global_inds_host_view_type ind;
6309  newGraph.getGlobalRowView (globalRowIndex, ind);
6310  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6311  const GO globalColIndex = ind(ii);
6312  // Convert row and column indices to 1-based.
6313  // This works because the global index type is signed.
6314  out << (globalRowIndex + 1 - rowIndexBase) << " "
6315  << (globalColIndex + 1 - colIndexBase) << " ";
6316  out << endl;
6317  } // For each entry in the current row
6318  } // For each row of the "gather" graph
6319  }
6320  else { // newGraph is locally indexed
6321  typedef Teuchos::OrdinalTraits<GO> OTG;
6322  for (LO localRowIndex = gatherRowMap->getMinLocalIndex ();
6323  localRowIndex <= gatherRowMap->getMaxLocalIndex ();
6324  ++localRowIndex) {
6325  // Convert from local to global row index.
6326  const GO globalRowIndex =
6327  gatherRowMap->getGlobalElement (localRowIndex);
6328  TEUCHOS_TEST_FOR_EXCEPTION
6329  (globalRowIndex == OTG::invalid (), std::logic_error, "Failed "
6330  "to convert the supposed local row index " << localRowIndex <<
6331  " into a global row index. Please report this bug to the "
6332  "Tpetra developers.");
6333  typename crs_graph_type::local_inds_host_view_type ind;
6334  newGraph.getLocalRowView (localRowIndex, ind);
6335  for (size_t ii = 0; ii < ind.extent(0); ii++) {
6336  // Convert the column index from local to global.
6337  const GO globalColIndex =
6338  newGraph.getColMap ()->getGlobalElement (ind(ii));
6339  TEUCHOS_TEST_FOR_EXCEPTION(
6340  globalColIndex == OTG::invalid(), std::logic_error,
6341  "On local row " << localRowIndex << " of the sparse graph: "
6342  "Failed to convert the supposed local column index "
6343  << ind(ii) << " into a global column index. Please report "
6344  "this bug to the Tpetra developers.");
6345  // Convert row and column indices to 1-based.
6346  // This works because the global index type is signed.
6347  out << (globalRowIndex + 1 - rowIndexBase) << " "
6348  << (globalColIndex + 1 - colIndexBase) << " ";
6349  out << endl;
6350  } // For each entry in the current row
6351  } // For each row of the "gather" graph
6352  } // Whether the "gather" graph is locally or globally indexed
6353  } // If my process' rank is 0
6354  }
6355 
6361  static void
6362  writeSparseGraph (std::ostream& out,
6363  const crs_graph_type& graph,
6364  const bool debug=false)
6365  {
6366  writeSparseGraph (out, graph, "", "", debug);
6367  }
6368 
6403  static void
6404  writeSparseGraphFile (const std::string& filename,
6405  const crs_graph_type& graph,
6406  const std::string& graphName,
6407  const std::string& graphDescription,
6408  const bool debug=false)
6409  {
6410  auto comm = graph.getComm ();
6411  if (comm.is_null ()) {
6412  // Processes on which the communicator is null shouldn't
6413  // even call this function. The convention is that
6414  // processes on which the object's communicator is null do
6415  // not participate in collective operations involving the
6416  // object.
6417  return;
6418  }
6419  const int myRank = comm->getRank ();
6420  std::ofstream out;
6421 
6422  // Only open the file on Process 0.
6423  if (myRank == 0) {
6424  out.open (filename.c_str ());
6425  }
6426  writeSparseGraph (out, graph, graphName, graphDescription, debug);
6427  // We can rely on the destructor of the output stream to close
6428  // the file on scope exit, even if writeSparseGraph() throws
6429  // an exception.
6430  }
6431 
6436  static void
6437  writeSparseGraphFile (const std::string& filename,
6438  const crs_graph_type& graph,
6439  const bool debug=false)
6440  {
6441  writeSparseGraphFile (filename, graph, "", "", debug);
6442  }
6443 
6452  static void
6453  writeSparseGraphFile (const std::string& filename,
6454  const Teuchos::RCP<const crs_graph_type>& pGraph,
6455  const std::string& graphName,
6456  const std::string& graphDescription,
6457  const bool debug=false)
6458  {
6459  writeSparseGraphFile (filename, *pGraph, graphName, graphDescription, debug);
6460  }
6461 
6471  static void
6472  writeSparseGraphFile (const std::string& filename,
6473  const Teuchos::RCP<const crs_graph_type>& pGraph,
6474  const bool debug=false)
6475  {
6476  writeSparseGraphFile (filename, *pGraph, "", "", debug);
6477  }
6478 
6501  static void
6502  writeSparse (std::ostream& out,
6503  const sparse_matrix_type& matrix,
6504  const bool debug=false)
6505  {
6506  writeSparse (out, matrix, "", "", debug);
6507  }
6508 
6510  static void
6511  writeSparse (std::ostream& out,
6512  const Teuchos::RCP<const sparse_matrix_type>& pMatrix,
6513  const bool debug=false)
6514  {
6515  writeSparse (out, *pMatrix, "", "", debug);
6516  }
6517 
6546  static void
6547  writeDenseFile (const std::string& filename,
6548  const multivector_type& X,
6549  const std::string& matrixName,
6550  const std::string& matrixDescription,
6551  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6552  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6553  {
6554  const int myRank = X.getMap ().is_null () ? 0 :
6555  (X.getMap ()->getComm ().is_null () ? 0 :
6556  X.getMap ()->getComm ()->getRank ());
6557  std::ofstream out;
6558 
6559  if (myRank == 0) { // Only open the file on Process 0.
6560  out.open (filename.c_str());
6561  }
6562 
6563  writeDense (out, X, matrixName, matrixDescription, err, dbg);
6564  // We can rely on the destructor of the output stream to close
6565  // the file on scope exit, even if writeDense() throws an
6566  // exception.
6567  }
6568 
6574  static void
6575  writeDenseFile (const std::string& filename,
6576  const Teuchos::RCP<const multivector_type>& X,
6577  const std::string& matrixName,
6578  const std::string& matrixDescription,
6579  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6580  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6581  {
6582  TEUCHOS_TEST_FOR_EXCEPTION(
6583  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6584  "writeDenseFile: The input MultiVector X is null.");
6585  writeDenseFile (filename, *X, matrixName, matrixDescription, err, dbg);
6586  }
6587 
6593  static void
6594  writeDenseFile (const std::string& filename,
6595  const multivector_type& X,
6596  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6597  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6598  {
6599  writeDenseFile (filename, X, "", "", err, dbg);
6600  }
6601 
6607  static void
6608  writeDenseFile (const std::string& filename,
6609  const Teuchos::RCP<const multivector_type>& X,
6610  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6611  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6612  {
6613  TEUCHOS_TEST_FOR_EXCEPTION(
6614  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
6615  "writeDenseFile: The input MultiVector X is null.");
6616  writeDenseFile (filename, *X, err, dbg);
6617  }
6618 
6619 
6650  static void
6651  writeDense (std::ostream& out,
6652  const multivector_type& X,
6653  const std::string& matrixName,
6654  const std::string& matrixDescription,
6655  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6656  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6657  {
6658  using Teuchos::Comm;
6659  using Teuchos::outArg;
6660  using Teuchos::REDUCE_MAX;
6661  using Teuchos::reduceAll;
6662  using Teuchos::RCP;
6663  using std::endl;
6664 
6665  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6666  Teuchos::null : X.getMap ()->getComm ();
6667  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6668 
6669  // If the caller provides a nonnull debug output stream, we
6670  // print debugging output to it. This is a local thing; we
6671  // don't have to check across processes.
6672  const bool debug = ! dbg.is_null ();
6673  if (debug) {
6674  dbg->pushTab ();
6675  std::ostringstream os;
6676  os << myRank << ": writeDense" << endl;
6677  *dbg << os.str ();
6678  dbg->pushTab ();
6679  }
6680  // Print the Matrix Market header.
6681  writeDenseHeader (out, X, matrixName, matrixDescription, err, dbg);
6682 
6683  // Print each column one at a time. This is a (perhaps)
6684  // temporary fix for Bug 6288.
6685  const size_t numVecs = X.getNumVectors ();
6686  for (size_t j = 0; j < numVecs; ++j) {
6687  writeDenseColumn (out, * (X.getVector (j)), err, dbg);
6688  }
6689 
6690  if (debug) {
6691  dbg->popTab ();
6692  std::ostringstream os;
6693  os << myRank << ": writeDense: Done" << endl;
6694  *dbg << os.str ();
6695  dbg->popTab ();
6696  }
6697  }
6698 
6699  private:
6700 
6726  static void
6727  writeDenseHeader (std::ostream& out,
6728  const multivector_type& X,
6729  const std::string& matrixName,
6730  const std::string& matrixDescription,
6731  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6732  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6733  {
6734  using Teuchos::Comm;
6735  using Teuchos::outArg;
6736  using Teuchos::RCP;
6737  using Teuchos::REDUCE_MAX;
6738  using Teuchos::reduceAll;
6739  using std::endl;
6740  typedef Teuchos::ScalarTraits<scalar_type> STS;
6741  const char prefix[] = "Tpetra::MatrixMarket::writeDenseHeader: ";
6742 
6743  RCP<const Comm<int> > comm = X.getMap ().is_null () ?
6744  Teuchos::null : X.getMap ()->getComm ();
6745  const int myRank = comm.is_null () ? 0 : comm->getRank ();
6746  int lclErr = 0; // whether this MPI process has seen an error
6747  int gblErr = 0; // whether we know if some MPI process has seen an error
6748 
6749  // If the caller provides a nonnull debug output stream, we
6750  // print debugging output to it. This is a local thing; we
6751  // don't have to check across processes.
6752  const bool debug = ! dbg.is_null ();
6753 
6754  if (debug) {
6755  dbg->pushTab ();
6756  std::ostringstream os;
6757  os << myRank << ": writeDenseHeader" << endl;
6758  *dbg << os.str ();
6759  dbg->pushTab ();
6760  }
6761 
6762  //
6763  // Process 0: Write the MatrixMarket header.
6764  //
6765  if (myRank == 0) {
6766  try {
6767  // Print the Matrix Market header. MultiVector stores data
6768  // nonsymmetrically, hence "general" in the banner line.
6769  // Print first to a temporary string output stream, and then
6770  // write it to the main output stream, so that at least the
6771  // header output has transactional semantics. We can't
6772  // guarantee transactional semantics for the whole output,
6773  // since that would not be memory scalable. (This could be
6774  // done in the file system by using a temporary file; we
6775  // don't do this, but users could.)
6776  std::ostringstream hdr;
6777  {
6778  std::string dataType;
6779  if (STS::isComplex) {
6780  dataType = "complex";
6781  } else if (STS::isOrdinal) {
6782  dataType = "integer";
6783  } else {
6784  dataType = "real";
6785  }
6786  hdr << "%%MatrixMarket matrix array " << dataType << " general"
6787  << endl;
6788  }
6789 
6790  // Print comments (the matrix name and / or description).
6791  if (matrixName != "") {
6792  printAsComment (hdr, matrixName);
6793  }
6794  if (matrixDescription != "") {
6795  printAsComment (hdr, matrixDescription);
6796  }
6797  // Print the Matrix Market dimensions header for dense matrices.
6798  hdr << X.getGlobalLength () << " " << X.getNumVectors () << endl;
6799 
6800  // Write the MatrixMarket header to the output stream.
6801  out << hdr.str ();
6802  } catch (std::exception& e) {
6803  if (! err.is_null ()) {
6804  *err << prefix << "While writing the Matrix Market header, "
6805  "Process 0 threw an exception: " << e.what () << endl;
6806  }
6807  lclErr = 1;
6808  }
6809  } // if I am Process 0
6810 
6811  // Establish global agreement on the error state. It wouldn't
6812  // be good for other processes to keep going, if Process 0
6813  // finds out that it can't write to the given output stream.
6814  reduceAll<int, int> (*comm, REDUCE_MAX, lclErr, outArg (gblErr));
6815  TEUCHOS_TEST_FOR_EXCEPTION(
6816  gblErr == 1, std::runtime_error, prefix << "Some error occurred "
6817  "which prevented this method from completing.");
6818 
6819  if (debug) {
6820  dbg->popTab ();
6821  *dbg << myRank << ": writeDenseHeader: Done" << endl;
6822  dbg->popTab ();
6823  }
6824  }
6825 
6843  static void
6844  writeDenseColumn (std::ostream& out,
6845  const multivector_type& X,
6846  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
6847  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
6848  {
6849  using Teuchos::arcp;
6850  using Teuchos::Array;
6851  using Teuchos::ArrayRCP;
6852  using Teuchos::ArrayView;
6853  using Teuchos::Comm;
6854  using Teuchos::CommRequest;
6855  using Teuchos::ireceive;
6856  using Teuchos::isend;
6857  using Teuchos::outArg;
6858  using Teuchos::REDUCE_MAX;
6859  using Teuchos::reduceAll;
6860  using Teuchos::RCP;
6861  using Teuchos::TypeNameTraits;
6862  using Teuchos::wait;
6863  using std::endl;
6864  typedef Teuchos::ScalarTraits<scalar_type> STS;
6865 
6866  const Comm<int>& comm = * (X.getMap ()->getComm ());
6867  const int myRank = comm.getRank ();
6868  const int numProcs = comm.getSize ();
6869  int lclErr = 0; // whether this MPI process has seen an error
6870  int gblErr = 0; // whether we know if some MPI process has seen an error
6871 
6872  // If the caller provides a nonnull debug output stream, we
6873  // print debugging output to it. This is a local thing; we
6874  // don't have to check across processes.
6875  const bool debug = ! dbg.is_null ();
6876 
6877  if (debug) {
6878  dbg->pushTab ();
6879  std::ostringstream os;
6880  os << myRank << ": writeDenseColumn" << endl;
6881  *dbg << os.str ();
6882  dbg->pushTab ();
6883  }
6884 
6885  // Make the output stream write floating-point numbers in
6886  // scientific notation. It will politely put the output
6887  // stream back to its state on input, when this scope
6888  // terminates.
6889  Teuchos::SetScientific<scalar_type> sci (out);
6890 
6891  const size_t myNumRows = X.getLocalLength ();
6892  const size_t numCols = X.getNumVectors ();
6893  // Use a different tag for the "size" messages than for the
6894  // "data" messages, in order to help us debug any mix-ups.
6895  const int sizeTag = 1337;
6896  const int dataTag = 1338;
6897 
6898  // Process 0 pipelines nonblocking receives with file output.
6899  //
6900  // Constraints:
6901  // - Process 0 can't post a receive for another process'
6902  // actual data, until it posts and waits on the receive
6903  // from that process with the amount of data to receive.
6904  // (We could just post receives with a max data size, but
6905  // I feel uncomfortable about that.)
6906  // - The C++ standard library doesn't allow nonblocking
6907  // output to an std::ostream. (Thus, we have to start a
6908  // receive or send before starting the write, and hope
6909  // that MPI completes it in the background.)
6910  //
6911  // Process 0: Post receive-size receives from Processes 1 and 2.
6912  // Process 1: Post send-size send to Process 0.
6913  // Process 2: Post send-size send to Process 0.
6914  //
6915  // All processes: Pack my entries.
6916  //
6917  // Process 1:
6918  // - Post send-data send to Process 0.
6919  // - Wait on my send-size send to Process 0.
6920  //
6921  // Process 0:
6922  // - Print MatrixMarket header.
6923  // - Print my entries.
6924  // - Wait on receive-size receive from Process 1.
6925  // - Post receive-data receive from Process 1.
6926  //
6927  // For each process p = 1, 2, ... numProcs-1:
6928  // If I am Process 0:
6929  // - Post receive-size receive from Process p + 2
6930  // - Wait on receive-size receive from Process p + 1
6931  // - Post receive-data receive from Process p + 1
6932  // - Wait on receive-data receive from Process p
6933  // - Write data from Process p.
6934  // Else if I am Process p:
6935  // - Wait on my send-data send.
6936  // Else if I am Process p+1:
6937  // - Post send-data send to Process 0.
6938  // - Wait on my send-size send.
6939  // Else if I am Process p+2:
6940  // - Post send-size send to Process 0.
6941  //
6942  // Pipelining has three goals here:
6943  // 1. Overlap communication (the receives) with file I/O
6944  // 2. Give Process 0 a chance to prepost some receives,
6945  // before sends show up, by packing local data before
6946  // posting sends
6947  // 3. Don't post _all_ receives or _all_ sends, because that
6948  // wouldn't be memory scalable. (Just because we can't
6949  // see how much memory MPI consumes, doesn't mean that it
6950  // doesn't consume any!)
6951 
6952  // These are used on every process. sendReqSize[0] holds the
6953  // number of rows on this process, and sendReqBuf holds this
6954  // process' data. Process 0 packs into sendReqBuf, but
6955  // doesn't send; it only uses that for printing. All other
6956  // processes send both of these to Process 0.
6957  RCP<CommRequest<int> > sendReqSize, sendReqData;
6958 
6959  // These are used only on Process 0, for received data. Keep
6960  // 3 of each, and treat the arrays as circular buffers. When
6961  // receiving from Process p, the corresponding array index
6962  // here is p % 3.
6963  Array<ArrayRCP<size_t> > recvSizeBufs (3);
6964  Array<ArrayRCP<scalar_type> > recvDataBufs (3);
6965  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
6966  Array<RCP<CommRequest<int> > > recvDataReqs (3);
6967 
6968  // Buffer for nonblocking send of the "send size."
6969  ArrayRCP<size_t> sendDataSize (1);
6970  sendDataSize[0] = myNumRows;
6971 
6972  if (myRank == 0) {
6973  if (debug) {
6974  std::ostringstream os;
6975  os << myRank << ": Post receive-size receives from "
6976  "Procs 1 and 2: tag = " << sizeTag << endl;
6977  *dbg << os.str ();
6978  }
6979  // Process 0: Post receive-size receives from Processes 1 and 2.
6980  recvSizeBufs[0].resize (1);
6981  // Set these three to an invalid value as a flag. If we
6982  // don't get these messages, then the invalid value will
6983  // remain, so we can test for it.
6984  (recvSizeBufs[0])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6985  recvSizeBufs[1].resize (1);
6986  (recvSizeBufs[1])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6987  recvSizeBufs[2].resize (1);
6988  (recvSizeBufs[2])[0] = Teuchos::OrdinalTraits<size_t>::invalid ();
6989  if (numProcs > 1) {
6990  recvSizeReqs[1] =
6991  ireceive<int, size_t> (recvSizeBufs[1], 1, sizeTag, comm);
6992  }
6993  if (numProcs > 2) {
6994  recvSizeReqs[2] =
6995  ireceive<int, size_t> (recvSizeBufs[2], 2, sizeTag, comm);
6996  }
6997  }
6998  else if (myRank == 1 || myRank == 2) {
6999  if (debug) {
7000  std::ostringstream os;
7001  os << myRank << ": Post send-size send: size = "
7002  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7003  *dbg << os.str ();
7004  }
7005  // Prime the pipeline by having Processes 1 and 2 start
7006  // their send-size sends. We don't want _all_ the processes
7007  // to start their send-size sends, because that wouldn't be
7008  // memory scalable.
7009  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7010  }
7011  else {
7012  if (debug) {
7013  std::ostringstream os;
7014  os << myRank << ": Not posting my send-size send yet" << endl;
7015  *dbg << os.str ();
7016  }
7017  }
7018 
7019  //
7020  // Pack my entries, in column-major order.
7021  //
7022  if (debug) {
7023  std::ostringstream os;
7024  os << myRank << ": Pack my entries" << endl;
7025  *dbg << os.str ();
7026  }
7027  ArrayRCP<scalar_type> sendDataBuf;
7028  try {
7029  sendDataBuf = arcp<scalar_type> (myNumRows * numCols);
7030  X.get1dCopy (sendDataBuf (), myNumRows);
7031  }
7032  catch (std::exception& e) {
7033  lclErr = 1;
7034  if (! err.is_null ()) {
7035  std::ostringstream os;
7036  os << "Process " << myRank << ": Attempt to pack my MultiVector "
7037  "entries threw an exception: " << e.what () << endl;
7038  *err << os.str ();
7039  }
7040  }
7041  if (debug) {
7042  std::ostringstream os;
7043  os << myRank << ": Done packing my entries" << endl;
7044  *dbg << os.str ();
7045  }
7046 
7047  //
7048  // Process 1: post send-data send to Process 0.
7049  //
7050  if (myRank == 1) {
7051  if (debug) {
7052  *dbg << myRank << ": Post send-data send: tag = " << dataTag
7053  << endl;
7054  }
7055  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7056  }
7057 
7058  //
7059  // Process 0: Write my entries.
7060  //
7061  if (myRank == 0) {
7062  if (debug) {
7063  std::ostringstream os;
7064  os << myRank << ": Write my entries" << endl;
7065  *dbg << os.str ();
7066  }
7067 
7068  // Write Process 0's data to the output stream.
7069  // Matrix Market prints dense matrices in column-major order.
7070  const size_t printNumRows = myNumRows;
7071  ArrayView<const scalar_type> printData = sendDataBuf ();
7072  const size_t printStride = printNumRows;
7073  if (static_cast<size_t> (printData.size ()) < printStride * numCols) {
7074  lclErr = 1;
7075  if (! err.is_null ()) {
7076  std::ostringstream os;
7077  os << "Process " << myRank << ": My MultiVector data's size "
7078  << printData.size () << " does not match my local dimensions "
7079  << printStride << " x " << numCols << "." << endl;
7080  *err << os.str ();
7081  }
7082  }
7083  else {
7084  // Matrix Market dense format wants one number per line.
7085  // It wants each complex number as two real numbers (real
7086  // resp. imaginary parts) with a space between.
7087  for (size_t col = 0; col < numCols; ++col) {
7088  for (size_t row = 0; row < printNumRows; ++row) {
7089  if (STS::isComplex) {
7090  out << STS::real (printData[row + col * printStride]) << " "
7091  << STS::imag (printData[row + col * printStride]) << endl;
7092  } else {
7093  out << printData[row + col * printStride] << endl;
7094  }
7095  }
7096  }
7097  }
7098  }
7099 
7100  if (myRank == 0) {
7101  // Wait on receive-size receive from Process 1.
7102  const int recvRank = 1;
7103  const int circBufInd = recvRank % 3;
7104  if (debug) {
7105  std::ostringstream os;
7106  os << myRank << ": Wait on receive-size receive from Process "
7107  << recvRank << endl;
7108  *dbg << os.str ();
7109  }
7110  if (numProcs > 1) {
7111  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7112 
7113  // We received the number of rows of data. (The data
7114  // come in two columns.)
7115  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7116  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7117  lclErr = 1;
7118  if (! err.is_null ()) {
7119  std::ostringstream os;
7120  os << myRank << ": Result of receive-size receive from Process "
7121  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7122  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7123  "This should never happen, and suggests that the receive never "
7124  "got posted. Please report this bug to the Tpetra developers."
7125  << endl;
7126  *err << os.str ();
7127  }
7128 
7129  // If we're going to continue after error, set the
7130  // number of rows to receive to a reasonable size. This
7131  // may cause MPI_ERR_TRUNCATE if the sending process is
7132  // sending more than 0 rows, but that's better than MPI
7133  // overflowing due to the huge positive value that is
7134  // Teuchos::OrdinalTraits<size_t>::invalid().
7135  recvNumRows = 0;
7136  }
7137 
7138  // Post receive-data receive from Process 1.
7139  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7140  if (debug) {
7141  std::ostringstream os;
7142  os << myRank << ": Post receive-data receive from Process "
7143  << recvRank << ": tag = " << dataTag << ", buffer size = "
7144  << recvDataBufs[circBufInd].size () << endl;
7145  *dbg << os.str ();
7146  }
7147  if (! recvSizeReqs[circBufInd].is_null ()) {
7148  lclErr = 1;
7149  if (! err.is_null ()) {
7150  std::ostringstream os;
7151  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7152  "null, before posting the receive-data receive from Process "
7153  << recvRank << ". This should never happen. Please report "
7154  "this bug to the Tpetra developers." << endl;
7155  *err << os.str ();
7156  }
7157  }
7158  recvDataReqs[circBufInd] =
7159  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7160  recvRank, dataTag, comm);
7161  } // numProcs > 1
7162  }
7163  else if (myRank == 1) {
7164  // Wait on my send-size send.
7165  if (debug) {
7166  std::ostringstream os;
7167  os << myRank << ": Wait on my send-size send" << endl;
7168  *dbg << os.str ();
7169  }
7170  wait<int> (comm, outArg (sendReqSize));
7171  }
7172 
7173  //
7174  // Pipeline loop
7175  //
7176  for (int p = 1; p < numProcs; ++p) {
7177  if (myRank == 0) {
7178  if (p + 2 < numProcs) {
7179  // Post receive-size receive from Process p + 2.
7180  const int recvRank = p + 2;
7181  const int circBufInd = recvRank % 3;
7182  if (debug) {
7183  std::ostringstream os;
7184  os << myRank << ": Post receive-size receive from Process "
7185  << recvRank << ": tag = " << sizeTag << endl;
7186  *dbg << os.str ();
7187  }
7188  if (! recvSizeReqs[circBufInd].is_null ()) {
7189  lclErr = 1;
7190  if (! err.is_null ()) {
7191  std::ostringstream os;
7192  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7193  << "null, for the receive-size receive from Process "
7194  << recvRank << "! This may mean that this process never "
7195  << "finished waiting for the receive from Process "
7196  << (recvRank - 3) << "." << endl;
7197  *err << os.str ();
7198  }
7199  }
7200  recvSizeReqs[circBufInd] =
7201  ireceive<int, size_t> (recvSizeBufs[circBufInd],
7202  recvRank, sizeTag, comm);
7203  }
7204 
7205  if (p + 1 < numProcs) {
7206  const int recvRank = p + 1;
7207  const int circBufInd = recvRank % 3;
7208 
7209  // Wait on receive-size receive from Process p + 1.
7210  if (debug) {
7211  std::ostringstream os;
7212  os << myRank << ": Wait on receive-size receive from Process "
7213  << recvRank << endl;
7214  *dbg << os.str ();
7215  }
7216  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7217 
7218  // We received the number of rows of data. (The data
7219  // come in two columns.)
7220  size_t recvNumRows = (recvSizeBufs[circBufInd])[0];
7221  if (recvNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7222  lclErr = 1;
7223  if (! err.is_null ()) {
7224  std::ostringstream os;
7225  os << myRank << ": Result of receive-size receive from Process "
7226  << recvRank << " is Teuchos::OrdinalTraits<size_t>::invalid() "
7227  << "= " << Teuchos::OrdinalTraits<size_t>::invalid () << ". "
7228  "This should never happen, and suggests that the receive never "
7229  "got posted. Please report this bug to the Tpetra developers."
7230  << endl;
7231  *err << os.str ();
7232  }
7233  // If we're going to continue after error, set the
7234  // number of rows to receive to a reasonable size.
7235  // This may cause MPI_ERR_TRUNCATE if the sending
7236  // process sends more than 0 rows, but that's better
7237  // than MPI overflowing due to the huge positive value
7238  // Teuchos::OrdinalTraits<size_t>::invalid().
7239  recvNumRows = 0;
7240  }
7241 
7242  // Post receive-data receive from Process p + 1.
7243  recvDataBufs[circBufInd].resize (recvNumRows * numCols);
7244  if (debug) {
7245  std::ostringstream os;
7246  os << myRank << ": Post receive-data receive from Process "
7247  << recvRank << ": tag = " << dataTag << ", buffer size = "
7248  << recvDataBufs[circBufInd].size () << endl;
7249  *dbg << os.str ();
7250  }
7251  if (! recvDataReqs[circBufInd].is_null ()) {
7252  lclErr = 1;
7253  if (! err.is_null ()) {
7254  std::ostringstream os;
7255  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7256  << "null, for the receive-data receive from Process "
7257  << recvRank << "! This may mean that this process never "
7258  << "finished waiting for the receive from Process "
7259  << (recvRank - 3) << "." << endl;
7260  *err << os.str ();
7261  }
7262  }
7263  recvDataReqs[circBufInd] =
7264  ireceive<int, scalar_type> (recvDataBufs[circBufInd],
7265  recvRank, dataTag, comm);
7266  }
7267 
7268  // Wait on receive-data receive from Process p.
7269  const int recvRank = p;
7270  const int circBufInd = recvRank % 3;
7271  if (debug) {
7272  std::ostringstream os;
7273  os << myRank << ": Wait on receive-data receive from Process "
7274  << recvRank << endl;
7275  *dbg << os.str ();
7276  }
7277  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7278 
7279  // Write Process p's data. Number of rows lives in
7280  // recvSizeBufs[circBufInd], and the actual data live in
7281  // recvDataBufs[circBufInd]. Do this after posting receives,
7282  // in order to expose overlap of comm. with file I/O.
7283  if (debug) {
7284  std::ostringstream os;
7285  os << myRank << ": Write entries from Process " << recvRank
7286  << endl;
7287  *dbg << os.str () << endl;
7288  }
7289  size_t printNumRows = (recvSizeBufs[circBufInd])[0];
7290  if (printNumRows == Teuchos::OrdinalTraits<size_t>::invalid ()) {
7291  lclErr = 1;
7292  if (! err.is_null ()) {
7293  std::ostringstream os;
7294  os << myRank << ": Result of receive-size receive from Process "
7295  << recvRank << " was Teuchos::OrdinalTraits<size_t>::"
7296  "invalid() = " << Teuchos::OrdinalTraits<size_t>::invalid ()
7297  << ". This should never happen, and suggests that its "
7298  "receive-size receive was never posted. "
7299  "Please report this bug to the Tpetra developers." << endl;
7300  *err << os.str ();
7301  }
7302  // If we're going to continue after error, set the
7303  // number of rows to print to a reasonable size.
7304  printNumRows = 0;
7305  }
7306  if (printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7307  lclErr = 1;
7308  if (! err.is_null ()) {
7309  std::ostringstream os;
7310  os << myRank << ": Result of receive-size receive from Proc "
7311  << recvRank << " was " << printNumRows << " > 0, but "
7312  "recvDataBufs[" << circBufInd << "] is null. This should "
7313  "never happen. Please report this bug to the Tpetra "
7314  "developers." << endl;
7315  *err << os.str ();
7316  }
7317  // If we're going to continue after error, set the
7318  // number of rows to print to a reasonable size.
7319  printNumRows = 0;
7320  }
7321 
7322  // Write the received data to the output stream.
7323  // Matrix Market prints dense matrices in column-major order.
7324  ArrayView<const scalar_type> printData = (recvDataBufs[circBufInd]) ();
7325  const size_t printStride = printNumRows;
7326  // Matrix Market dense format wants one number per line.
7327  // It wants each complex number as two real numbers (real
7328  // resp. imaginary parts) with a space between.
7329  for (size_t col = 0; col < numCols; ++col) {
7330  for (size_t row = 0; row < printNumRows; ++row) {
7331  if (STS::isComplex) {
7332  out << STS::real (printData[row + col * printStride]) << " "
7333  << STS::imag (printData[row + col * printStride]) << endl;
7334  } else {
7335  out << printData[row + col * printStride] << endl;
7336  }
7337  }
7338  }
7339  }
7340  else if (myRank == p) { // Process p
7341  // Wait on my send-data send.
7342  if (debug) {
7343  std::ostringstream os;
7344  os << myRank << ": Wait on my send-data send" << endl;
7345  *dbg << os.str ();
7346  }
7347  wait<int> (comm, outArg (sendReqData));
7348  }
7349  else if (myRank == p + 1) { // Process p + 1
7350  // Post send-data send to Process 0.
7351  if (debug) {
7352  std::ostringstream os;
7353  os << myRank << ": Post send-data send: tag = " << dataTag
7354  << endl;
7355  *dbg << os.str ();
7356  }
7357  sendReqData = isend<int, scalar_type> (sendDataBuf, 0, dataTag, comm);
7358  // Wait on my send-size send.
7359  if (debug) {
7360  std::ostringstream os;
7361  os << myRank << ": Wait on my send-size send" << endl;
7362  *dbg << os.str ();
7363  }
7364  wait<int> (comm, outArg (sendReqSize));
7365  }
7366  else if (myRank == p + 2) { // Process p + 2
7367  // Post send-size send to Process 0.
7368  if (debug) {
7369  std::ostringstream os;
7370  os << myRank << ": Post send-size send: size = "
7371  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7372  *dbg << os.str ();
7373  }
7374  sendReqSize = isend<int, size_t> (sendDataSize, 0, sizeTag, comm);
7375  }
7376  }
7377 
7378  // Establish global agreement on the error state.
7379  reduceAll<int, int> (comm, REDUCE_MAX, lclErr, outArg (gblErr));
7380  TEUCHOS_TEST_FOR_EXCEPTION(
7381  gblErr == 1, std::runtime_error, "Tpetra::MatrixMarket::writeDense "
7382  "experienced some kind of error and was unable to complete.");
7383 
7384  if (debug) {
7385  dbg->popTab ();
7386  *dbg << myRank << ": writeDenseColumn: Done" << endl;
7387  dbg->popTab ();
7388  }
7389  }
7390 
7391  public:
7392 
7398  static void
7399  writeDense (std::ostream& out,
7400  const Teuchos::RCP<const multivector_type>& X,
7401  const std::string& matrixName,
7402  const std::string& matrixDescription,
7403  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7404  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7405  {
7406  TEUCHOS_TEST_FOR_EXCEPTION(
7407  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7408  "writeDense: The input MultiVector X is null.");
7409  writeDense (out, *X, matrixName, matrixDescription, err, dbg);
7410  }
7411 
7417  static void
7418  writeDense (std::ostream& out,
7419  const multivector_type& X,
7420  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7421  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7422  {
7423  writeDense (out, X, "", "", err, dbg);
7424  }
7425 
7431  static void
7432  writeDense (std::ostream& out,
7433  const Teuchos::RCP<const multivector_type>& X,
7434  const Teuchos::RCP<Teuchos::FancyOStream>& err = Teuchos::null,
7435  const Teuchos::RCP<Teuchos::FancyOStream>& dbg = Teuchos::null)
7436  {
7437  TEUCHOS_TEST_FOR_EXCEPTION(
7438  X.is_null (), std::invalid_argument, "Tpetra::MatrixMarket::"
7439  "writeDense: The input MultiVector X is null.");
7440  writeDense (out, *X, "", "", err, dbg);
7441  }
7442 
7462  static void
7463  writeMap (std::ostream& out, const map_type& map, const bool debug=false)
7464  {
7465  Teuchos::RCP<Teuchos::FancyOStream> err =
7466  Teuchos::getFancyOStream (Teuchos::rcpFromRef (std::cerr));
7467  writeMap (out, map, err, debug);
7468  }
7469 
7478  static void
7479  writeMap (std::ostream& out,
7480  const map_type& map,
7481  const Teuchos::RCP<Teuchos::FancyOStream>& err,
7482  const bool debug=false)
7483  {
7484  using Teuchos::Array;
7485  using Teuchos::ArrayRCP;
7486  using Teuchos::ArrayView;
7487  using Teuchos::Comm;
7488  using Teuchos::CommRequest;
7489  using Teuchos::ireceive;
7490  using Teuchos::isend;
7491  using Teuchos::RCP;
7492  using Teuchos::TypeNameTraits;
7493  using Teuchos::wait;
7494  using std::endl;
7495  typedef global_ordinal_type GO;
7496  typedef int pid_type;
7497 
7498  // Treat the Map as a 1-column "multivector." This differs
7499  // from the previous two-column format, in which column 0 held
7500  // the GIDs, and column 1 held the corresponding PIDs. It
7501  // differs because printing that format requires knowing the
7502  // entire first column -- that is, all the GIDs -- in advance.
7503  // Sending messages from each process one at a time saves
7504  // memory, but it means that Process 0 doesn't ever have all
7505  // the GIDs at once.
7506  //
7507  // We pack the entries as ptrdiff_t, since this should be the
7508  // biggest signed built-in integer type that can hold any GO
7509  // or pid_type (= int) quantity without overflow. Test this
7510  // assumption at run time.
7511  typedef ptrdiff_t int_type;
7512  TEUCHOS_TEST_FOR_EXCEPTION(
7513  sizeof (GO) > sizeof (int_type), std::logic_error,
7514  "The global ordinal type GO=" << TypeNameTraits<GO>::name ()
7515  << " is too big for ptrdiff_t. sizeof(GO) = " << sizeof (GO)
7516  << " > sizeof(ptrdiff_t) = " << sizeof (ptrdiff_t) << ".");
7517  TEUCHOS_TEST_FOR_EXCEPTION(
7518  sizeof (pid_type) > sizeof (int_type), std::logic_error,
7519  "The (MPI) process rank type pid_type=" <<
7520  TypeNameTraits<pid_type>::name () << " is too big for ptrdiff_t. "
7521  "sizeof(pid_type) = " << sizeof (pid_type) << " > sizeof(ptrdiff_t)"
7522  " = " << sizeof (ptrdiff_t) << ".");
7523 
7524  const Comm<int>& comm = * (map.getComm ());
7525  const int myRank = comm.getRank ();
7526  const int numProcs = comm.getSize ();
7527 
7528  if (! err.is_null ()) {
7529  err->pushTab ();
7530  }
7531  if (debug) {
7532  std::ostringstream os;
7533  os << myRank << ": writeMap" << endl;
7534  *err << os.str ();
7535  }
7536  if (! err.is_null ()) {
7537  err->pushTab ();
7538  }
7539 
7540  const size_t myNumRows = map.getNodeNumElements ();
7541  // Use a different tag for the "size" messages than for the
7542  // "data" messages, in order to help us debug any mix-ups.
7543  const int sizeTag = 1337;
7544  const int dataTag = 1338;
7545 
7546  // Process 0 pipelines nonblocking receives with file output.
7547  //
7548  // Constraints:
7549  // - Process 0 can't post a receive for another process'
7550  // actual data, until it posts and waits on the receive
7551  // from that process with the amount of data to receive.
7552  // (We could just post receives with a max data size, but
7553  // I feel uncomfortable about that.)
7554  // - The C++ standard library doesn't allow nonblocking
7555  // output to an std::ostream.
7556  //
7557  // Process 0: Post receive-size receives from Processes 1 and 2.
7558  // Process 1: Post send-size send to Process 0.
7559  // Process 2: Post send-size send to Process 0.
7560  //
7561  // All processes: Pack my GIDs and PIDs.
7562  //
7563  // Process 1:
7564  // - Post send-data send to Process 0.
7565  // - Wait on my send-size send to Process 0.
7566  //
7567  // Process 0:
7568  // - Print MatrixMarket header.
7569  // - Print my GIDs and PIDs.
7570  // - Wait on receive-size receive from Process 1.
7571  // - Post receive-data receive from Process 1.
7572  //
7573  // For each process p = 1, 2, ... numProcs-1:
7574  // If I am Process 0:
7575  // - Post receive-size receive from Process p + 2
7576  // - Wait on receive-size receive from Process p + 1
7577  // - Post receive-data receive from Process p + 1
7578  // - Wait on receive-data receive from Process p
7579  // - Write data from Process p.
7580  // Else if I am Process p:
7581  // - Wait on my send-data send.
7582  // Else if I am Process p+1:
7583  // - Post send-data send to Process 0.
7584  // - Wait on my send-size send.
7585  // Else if I am Process p+2:
7586  // - Post send-size send to Process 0.
7587  //
7588  // Pipelining has three goals here:
7589  // 1. Overlap communication (the receives) with file I/O
7590  // 2. Give Process 0 a chance to prepost some receives,
7591  // before sends show up, by packing local data before
7592  // posting sends
7593  // 3. Don't post _all_ receives or _all_ sends, because that
7594  // wouldn't be memory scalable. (Just because we can't
7595  // see how much memory MPI consumes, doesn't mean that it
7596  // doesn't consume any!)
7597 
7598  // These are used on every process. sendReqSize[0] holds the
7599  // number of rows on this process, and sendReqBuf holds this
7600  // process' data. Process 0 packs into sendReqBuf, but
7601  // doesn't send; it only uses that for printing. All other
7602  // processes send both of these to Process 0.
7603  RCP<CommRequest<int> > sendReqSize, sendReqData;
7604 
7605  // These are used only on Process 0, for received data. Keep
7606  // 3 of each, and treat the arrays as circular buffers. When
7607  // receiving from Process p, the corresponding array index
7608  // here is p % 3.
7609  Array<ArrayRCP<int_type> > recvSizeBufs (3);
7610  Array<ArrayRCP<int_type> > recvDataBufs (3);
7611  Array<RCP<CommRequest<int> > > recvSizeReqs (3);
7612  Array<RCP<CommRequest<int> > > recvDataReqs (3);
7613 
7614  // Buffer for nonblocking send of the "send size."
7615  ArrayRCP<int_type> sendDataSize (1);
7616  sendDataSize[0] = myNumRows;
7617 
7618  if (myRank == 0) {
7619  if (debug) {
7620  std::ostringstream os;
7621  os << myRank << ": Post receive-size receives from "
7622  "Procs 1 and 2: tag = " << sizeTag << endl;
7623  *err << os.str ();
7624  }
7625  // Process 0: Post receive-size receives from Processes 1 and 2.
7626  recvSizeBufs[0].resize (1);
7627  (recvSizeBufs[0])[0] = -1; // error flag
7628  recvSizeBufs[1].resize (1);
7629  (recvSizeBufs[1])[0] = -1; // error flag
7630  recvSizeBufs[2].resize (1);
7631  (recvSizeBufs[2])[0] = -1; // error flag
7632  if (numProcs > 1) {
7633  recvSizeReqs[1] =
7634  ireceive<int, int_type> (recvSizeBufs[1], 1, sizeTag, comm);
7635  }
7636  if (numProcs > 2) {
7637  recvSizeReqs[2] =
7638  ireceive<int, int_type> (recvSizeBufs[2], 2, sizeTag, comm);
7639  }
7640  }
7641  else if (myRank == 1 || myRank == 2) {
7642  if (debug) {
7643  std::ostringstream os;
7644  os << myRank << ": Post send-size send: size = "
7645  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7646  *err << os.str ();
7647  }
7648  // Prime the pipeline by having Processes 1 and 2 start
7649  // their send-size sends. We don't want _all_ the processes
7650  // to start their send-size sends, because that wouldn't be
7651  // memory scalable.
7652  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7653  }
7654  else {
7655  if (debug) {
7656  std::ostringstream os;
7657  os << myRank << ": Not posting my send-size send yet" << endl;
7658  *err << os.str ();
7659  }
7660  }
7661 
7662  //
7663  // Pack my GIDs and PIDs. Each (GID,PID) pair gets packed
7664  // consecutively, for better locality.
7665  //
7666 
7667  if (debug) {
7668  std::ostringstream os;
7669  os << myRank << ": Pack my GIDs and PIDs" << endl;
7670  *err << os.str ();
7671  }
7672 
7673  ArrayRCP<int_type> sendDataBuf (myNumRows * 2);
7674 
7675  if (map.isContiguous ()) {
7676  const int_type myMinGblIdx =
7677  static_cast<int_type> (map.getMinGlobalIndex ());
7678  for (size_t k = 0; k < myNumRows; ++k) {
7679  const int_type gid = myMinGblIdx + static_cast<int_type> (k);
7680  const int_type pid = static_cast<int_type> (myRank);
7681  sendDataBuf[2*k] = gid;
7682  sendDataBuf[2*k+1] = pid;
7683  }
7684  }
7685  else {
7686  ArrayView<const GO> myGblInds = map.getNodeElementList ();
7687  for (size_t k = 0; k < myNumRows; ++k) {
7688  const int_type gid = static_cast<int_type> (myGblInds[k]);
7689  const int_type pid = static_cast<int_type> (myRank);
7690  sendDataBuf[2*k] = gid;
7691  sendDataBuf[2*k+1] = pid;
7692  }
7693  }
7694 
7695  if (debug) {
7696  std::ostringstream os;
7697  os << myRank << ": Done packing my GIDs and PIDs" << endl;
7698  *err << os.str ();
7699  }
7700 
7701  if (myRank == 1) {
7702  // Process 1: post send-data send to Process 0.
7703  if (debug) {
7704  *err << myRank << ": Post send-data send: tag = " << dataTag
7705  << endl;
7706  }
7707  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7708  }
7709 
7710  if (myRank == 0) {
7711  if (debug) {
7712  *err << myRank << ": Write MatrixMarket header" << endl;
7713  }
7714 
7715  // Process 0: Write the MatrixMarket header.
7716  // Description section explains each column.
7717  std::ostringstream hdr;
7718 
7719  // Print the Matrix Market header. MultiVector stores data
7720  // nonsymmetrically, hence "general" in the banner line.
7721  hdr << "%%MatrixMarket matrix array integer general" << endl
7722  << "% Format: Version 2.0" << endl
7723  << "%" << endl
7724  << "% This file encodes a Tpetra::Map." << endl
7725  << "% It is stored as a dense vector, with twice as many " << endl
7726  << "% entries as the global number of GIDs (global indices)." << endl
7727  << "% (GID, PID) pairs are stored contiguously, where the PID " << endl
7728  << "% is the rank of the process owning that GID." << endl
7729  << (2 * map.getGlobalNumElements ()) << " " << 1 << endl;
7730  out << hdr.str ();
7731 
7732  if (debug) {
7733  std::ostringstream os;
7734  os << myRank << ": Write my GIDs and PIDs" << endl;
7735  *err << os.str ();
7736  }
7737 
7738  // Write Process 0's data to the output stream.
7739  // Matrix Market prints dense matrices in column-major order.
7740  const int_type printNumRows = myNumRows;
7741  ArrayView<const int_type> printData = sendDataBuf ();
7742  for (int_type k = 0; k < printNumRows; ++k) {
7743  const int_type gid = printData[2*k];
7744  const int_type pid = printData[2*k+1];
7745  out << gid << endl << pid << endl;
7746  }
7747  }
7748 
7749  if (myRank == 0) {
7750  // Wait on receive-size receive from Process 1.
7751  const int recvRank = 1;
7752  const int circBufInd = recvRank % 3;
7753  if (debug) {
7754  std::ostringstream os;
7755  os << myRank << ": Wait on receive-size receive from Process "
7756  << recvRank << endl;
7757  *err << os.str ();
7758  }
7759  if (numProcs > 1) {
7760  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7761 
7762  // We received the number of rows of data. (The data
7763  // come in two columns.)
7764  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7765  if (debug && recvNumRows == -1) {
7766  std::ostringstream os;
7767  os << myRank << ": Result of receive-size receive from Process "
7768  << recvRank << " is -1. This should never happen, and "
7769  "suggests that the receive never got posted. Please report "
7770  "this bug to the Tpetra developers." << endl;
7771  *err << os.str ();
7772  }
7773 
7774  // Post receive-data receive from Process 1.
7775  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7776  if (debug) {
7777  std::ostringstream os;
7778  os << myRank << ": Post receive-data receive from Process "
7779  << recvRank << ": tag = " << dataTag << ", buffer size = "
7780  << recvDataBufs[circBufInd].size () << endl;
7781  *err << os.str ();
7782  }
7783  if (! recvSizeReqs[circBufInd].is_null ()) {
7784  std::ostringstream os;
7785  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7786  "null, before posting the receive-data receive from Process "
7787  << recvRank << ". This should never happen. Please report "
7788  "this bug to the Tpetra developers." << endl;
7789  *err << os.str ();
7790  }
7791  recvDataReqs[circBufInd] =
7792  ireceive<int, int_type> (recvDataBufs[circBufInd],
7793  recvRank, dataTag, comm);
7794  } // numProcs > 1
7795  }
7796  else if (myRank == 1) {
7797  // Wait on my send-size send.
7798  if (debug) {
7799  std::ostringstream os;
7800  os << myRank << ": Wait on my send-size send" << endl;
7801  *err << os.str ();
7802  }
7803  wait<int> (comm, outArg (sendReqSize));
7804  }
7805 
7806  //
7807  // Pipeline loop
7808  //
7809  for (int p = 1; p < numProcs; ++p) {
7810  if (myRank == 0) {
7811  if (p + 2 < numProcs) {
7812  // Post receive-size receive from Process p + 2.
7813  const int recvRank = p + 2;
7814  const int circBufInd = recvRank % 3;
7815  if (debug) {
7816  std::ostringstream os;
7817  os << myRank << ": Post receive-size receive from Process "
7818  << recvRank << ": tag = " << sizeTag << endl;
7819  *err << os.str ();
7820  }
7821  if (! recvSizeReqs[circBufInd].is_null ()) {
7822  std::ostringstream os;
7823  os << myRank << ": recvSizeReqs[" << circBufInd << "] is not "
7824  << "null, for the receive-size receive from Process "
7825  << recvRank << "! This may mean that this process never "
7826  << "finished waiting for the receive from Process "
7827  << (recvRank - 3) << "." << endl;
7828  *err << os.str ();
7829  }
7830  recvSizeReqs[circBufInd] =
7831  ireceive<int, int_type> (recvSizeBufs[circBufInd],
7832  recvRank, sizeTag, comm);
7833  }
7834 
7835  if (p + 1 < numProcs) {
7836  const int recvRank = p + 1;
7837  const int circBufInd = recvRank % 3;
7838 
7839  // Wait on receive-size receive from Process p + 1.
7840  if (debug) {
7841  std::ostringstream os;
7842  os << myRank << ": Wait on receive-size receive from Process "
7843  << recvRank << endl;
7844  *err << os.str ();
7845  }
7846  wait<int> (comm, outArg (recvSizeReqs[circBufInd]));
7847 
7848  // We received the number of rows of data. (The data
7849  // come in two columns.)
7850  const int_type recvNumRows = (recvSizeBufs[circBufInd])[0];
7851  if (debug && recvNumRows == -1) {
7852  std::ostringstream os;
7853  os << myRank << ": Result of receive-size receive from Process "
7854  << recvRank << " is -1. This should never happen, and "
7855  "suggests that the receive never got posted. Please report "
7856  "this bug to the Tpetra developers." << endl;
7857  *err << os.str ();
7858  }
7859 
7860  // Post receive-data receive from Process p + 1.
7861  recvDataBufs[circBufInd].resize (recvNumRows * 2);
7862  if (debug) {
7863  std::ostringstream os;
7864  os << myRank << ": Post receive-data receive from Process "
7865  << recvRank << ": tag = " << dataTag << ", buffer size = "
7866  << recvDataBufs[circBufInd].size () << endl;
7867  *err << os.str ();
7868  }
7869  if (! recvDataReqs[circBufInd].is_null ()) {
7870  std::ostringstream os;
7871  os << myRank << ": recvDataReqs[" << circBufInd << "] is not "
7872  << "null, for the receive-data receive from Process "
7873  << recvRank << "! This may mean that this process never "
7874  << "finished waiting for the receive from Process "
7875  << (recvRank - 3) << "." << endl;
7876  *err << os.str ();
7877  }
7878  recvDataReqs[circBufInd] =
7879  ireceive<int, int_type> (recvDataBufs[circBufInd],
7880  recvRank, dataTag, comm);
7881  }
7882 
7883  // Wait on receive-data receive from Process p.
7884  const int recvRank = p;
7885  const int circBufInd = recvRank % 3;
7886  if (debug) {
7887  std::ostringstream os;
7888  os << myRank << ": Wait on receive-data receive from Process "
7889  << recvRank << endl;
7890  *err << os.str ();
7891  }
7892  wait<int> (comm, outArg (recvDataReqs[circBufInd]));
7893 
7894  // Write Process p's data. Number of rows lives in
7895  // recvSizeBufs[circBufInd], and the actual data live in
7896  // recvDataBufs[circBufInd]. Do this after posting receives,
7897  // in order to expose overlap of comm. with file I/O.
7898  if (debug) {
7899  std::ostringstream os;
7900  os << myRank << ": Write GIDs and PIDs from Process "
7901  << recvRank << endl;
7902  *err << os.str () << endl;
7903  }
7904  const int_type printNumRows = (recvSizeBufs[circBufInd])[0];
7905  if (debug && printNumRows == -1) {
7906  std::ostringstream os;
7907  os << myRank << ": Result of receive-size receive from Process "
7908  << recvRank << " was -1. This should never happen, and "
7909  "suggests that its receive-size receive was never posted. "
7910  "Please report this bug to the Tpetra developers." << endl;
7911  *err << os.str ();
7912  }
7913  if (debug && printNumRows > 0 && recvDataBufs[circBufInd].is_null ()) {
7914  std::ostringstream os;
7915  os << myRank << ": Result of receive-size receive from Proc "
7916  << recvRank << " was " << printNumRows << " > 0, but "
7917  "recvDataBufs[" << circBufInd << "] is null. This should "
7918  "never happen. Please report this bug to the Tpetra "
7919  "developers." << endl;
7920  *err << os.str ();
7921  }
7922  ArrayView<const int_type> printData = (recvDataBufs[circBufInd]) ();
7923  for (int_type k = 0; k < printNumRows; ++k) {
7924  const int_type gid = printData[2*k];
7925  const int_type pid = printData[2*k+1];
7926  out << gid << endl << pid << endl;
7927  }
7928  }
7929  else if (myRank == p) { // Process p
7930  // Wait on my send-data send.
7931  if (debug) {
7932  std::ostringstream os;
7933  os << myRank << ": Wait on my send-data send" << endl;
7934  *err << os.str ();
7935  }
7936  wait<int> (comm, outArg (sendReqData));
7937  }
7938  else if (myRank == p + 1) { // Process p + 1
7939  // Post send-data send to Process 0.
7940  if (debug) {
7941  std::ostringstream os;
7942  os << myRank << ": Post send-data send: tag = " << dataTag
7943  << endl;
7944  *err << os.str ();
7945  }
7946  sendReqData = isend<int, int_type> (sendDataBuf, 0, dataTag, comm);
7947  // Wait on my send-size send.
7948  if (debug) {
7949  std::ostringstream os;
7950  os << myRank << ": Wait on my send-size send" << endl;
7951  *err << os.str ();
7952  }
7953  wait<int> (comm, outArg (sendReqSize));
7954  }
7955  else if (myRank == p + 2) { // Process p + 2
7956  // Post send-size send to Process 0.
7957  if (debug) {
7958  std::ostringstream os;
7959  os << myRank << ": Post send-size send: size = "
7960  << sendDataSize[0] << ", tag = " << sizeTag << endl;
7961  *err << os.str ();
7962  }
7963  sendReqSize = isend<int, int_type> (sendDataSize, 0, sizeTag, comm);
7964  }
7965  }
7966 
7967  if (! err.is_null ()) {
7968  err->popTab ();
7969  }
7970  if (debug) {
7971  *err << myRank << ": writeMap: Done" << endl;
7972  }
7973  if (! err.is_null ()) {
7974  err->popTab ();
7975  }
7976  }
7977 
7979  static void
7980  writeMapFile (const std::string& filename,
7981  const map_type& map)
7982  {
7983  const int myRank = map.getComm ()->getRank ();
7984  std::ofstream out;
7985  if (myRank == 0) { // Only open the file on Proc 0.
7986  out.open (filename.c_str());
7987  }
7988  writeMap (out, map);
7989  // We can rely on the destructor of the output stream to close
7990  // the file on scope exit, even if writeDense() throws an
7991  // exception.
7992  }
7993 
7994  private:
8018  static void
8019  printAsComment (std::ostream& out, const std::string& str)
8020  {
8021  using std::endl;
8022  std::istringstream inpstream (str);
8023  std::string line;
8024 
8025  while (getline (inpstream, line)) {
8026  if (! line.empty()) {
8027  // Note that getline() doesn't store '\n', so we have to
8028  // append the endline ourselves.
8029  if (line[0] == '%') { // Line starts with a comment character.
8030  out << line << endl;
8031  }
8032  else { // Line doesn't start with a comment character.
8033  out << "%% " << line << endl;
8034  }
8035  }
8036  }
8037  }
8038 
8039  public:
8040 
8059  static void
8060  writeOperator(const std::string& fileName, operator_type const &A) {
8061  Teuchos::ParameterList pl;
8062  writeOperator(fileName, A, pl);
8063  }
8064 
8085  static void
8086  writeOperator (std::ostream& out, const operator_type& A) {
8087  Teuchos::ParameterList pl;
8088  writeOperator (out, A, pl);
8089  }
8090 
8127  static void
8128  writeOperator (const std::string& fileName,
8129  const operator_type& A,
8130  const Teuchos::ParameterList& params)
8131  {
8132  std::ofstream out;
8133  std::string tmpFile = "__TMP__" + fileName;
8134  const int myRank = A.getDomainMap()->getComm()->getRank();
8135  bool precisionChanged=false;
8136  int oldPrecision;
8137  // The number of nonzero entries in a Tpetra::Operator is
8138  // unknown until probing is completed. In order to write a
8139  // MatrixMarket header, we write the matrix to a temporary
8140  // file.
8141  //
8142  // FIXME (mfh 23 May 2015) IT WASN'T MY IDEA TO WRITE TO A
8143  // TEMPORARY FILE.
8144  if (myRank==0) {
8145  if (std::ifstream(tmpFile))
8146  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
8147  "writeOperator: temporary file " << tmpFile << " already exists");
8148  out.open(tmpFile.c_str());
8149  if (params.isParameter("precision")) {
8150  oldPrecision = out.precision(params.get<int>("precision"));
8151  precisionChanged=true;
8152  }
8153  }
8154 
8155  const std::string header = writeOperatorImpl(out, A, params);
8156 
8157  if (myRank==0) {
8158  if (precisionChanged)
8159  out.precision(oldPrecision);
8160  out.close();
8161  out.open(fileName.c_str(), std::ios::binary);
8162  bool printMatrixMarketHeader = true;
8163  if (params.isParameter("print MatrixMarket header"))
8164  printMatrixMarketHeader = params.get<bool>("print MatrixMarket header");
8165  if (printMatrixMarketHeader && myRank == 0) {
8166  // Write header to final file.
8167  out << header;
8168  }
8169  // Append matrix from temporary to final file.
8170  std::ifstream src(tmpFile, std::ios_base::binary);
8171  out << src.rdbuf();
8172  src.close();
8173  // Delete the temporary file.
8174  remove(tmpFile.c_str());
8175  }
8176  }
8177 
8216  static void
8217  writeOperator (std::ostream& out,
8218  const operator_type& A,
8219  const Teuchos::ParameterList& params)
8220  {
8221  const int myRank = A.getDomainMap ()->getComm ()->getRank ();
8222 
8223  // The number of nonzero entries in a Tpetra::Operator is
8224  // unknown until probing is completed. In order to write a
8225  // MatrixMarket header, we write the matrix to a temporary
8226  // output stream.
8227  //
8228  // NOTE (mfh 23 May 2015): Writing to a temporary output
8229  // stream may double the memory usage, depending on whether
8230  // 'out' is a file stream or an in-memory output stream (e.g.,
8231  // std::ostringstream). It might be wise to use a temporary
8232  // file instead. However, please look carefully at POSIX
8233  // functions for safe creation of temporary files. Don't just
8234  // prepend "__TMP__" to the filename and hope for the best.
8235  // Furthermore, it should be valid to call the std::ostream
8236  // overload of this method even when Process 0 does not have
8237  // access to a file system.
8238  std::ostringstream tmpOut;
8239  if (myRank == 0) {
8240  if (params.isParameter ("precision") && params.isType<int> ("precision")) {
8241  (void) tmpOut.precision (params.get<int> ("precision"));
8242  }
8243  }
8244 
8245  const std::string header = writeOperatorImpl (tmpOut, A, params);
8246 
8247  if (myRank == 0) {
8248  bool printMatrixMarketHeader = true;
8249  if (params.isParameter ("print MatrixMarket header") &&
8250  params.isType<bool> ("print MatrixMarket header")) {
8251  printMatrixMarketHeader = params.get<bool> ("print MatrixMarket header");
8252  }
8253  if (printMatrixMarketHeader && myRank == 0) {
8254  out << header; // write header to final output stream
8255  }
8256  // Append matrix from temporary output stream to final output stream.
8257  //
8258  // NOTE (mfh 23 May 2015) This might use a lot of memory.
8259  // However, we should not use temporary files in this
8260  // method. Since it does not access the file system (unlike
8261  // the overload that takes a file name), it should not
8262  // require the file system at all.
8263  //
8264  // If memory usage becomes a problem, one thing we could do
8265  // is write the entries of the Operator one column (or a few
8266  // columns) at a time. The Matrix Market sparse format does
8267  // not impose an order on its entries, so it would be OK to
8268  // write them in that order.
8269  out << tmpOut.str ();
8270  }
8271  }
8272 
8273  private:
8274 
8282  static std::string
8283  writeOperatorImpl (std::ostream& os,
8284  const operator_type& A,
8285  const Teuchos::ParameterList& params)
8286  {
8287  using Teuchos::RCP;
8288  using Teuchos::rcp;
8289  using Teuchos::ArrayRCP;
8290  using Teuchos::Array;
8291 
8292  typedef local_ordinal_type LO;
8293  typedef global_ordinal_type GO;
8294  typedef scalar_type Scalar;
8295  typedef Teuchos::OrdinalTraits<LO> TLOT;
8296  typedef Teuchos::OrdinalTraits<GO> TGOT;
8297  typedef Tpetra::Import<LO, GO, node_type> import_type;
8298  typedef Tpetra::MultiVector<GO, LO, GO, node_type> mv_type_go;
8299 
8300  const map_type& domainMap = *(A.getDomainMap());
8301  RCP<const map_type> rangeMap = A.getRangeMap();
8302  RCP<const Teuchos::Comm<int> > comm = rangeMap->getComm();
8303  const int myRank = comm->getRank();
8304  const size_t numProcs = comm->getSize();
8305 
8306  size_t numMVs = 10;
8307  if (params.isParameter("probing size"))
8308  numMVs = params.get<int>("probing size");
8309 
8310  GO globalNnz = 0;
8311  GO minColGid = domainMap.getMinAllGlobalIndex();
8312  GO maxColGid = domainMap.getMaxAllGlobalIndex();
8313  // Rather than replicating the domainMap on all processors, we instead
8314  // iterate from the min GID to the max GID. If the map is gappy,
8315  // there will be invalid GIDs, i.e., GIDs no one has. This will require
8316  // unnecessary matvecs against potentially zero vectors.
8317  GO numGlobElts = maxColGid - minColGid + TGOT::one();
8318  GO numChunks = numGlobElts / numMVs;
8319  GO rem = numGlobElts % numMVs;
8320  GO indexBase = rangeMap->getIndexBase();
8321 
8322  int offsetToUseInPrinting = 1 - indexBase; // default is 1-based indexing
8323  if (params.isParameter("zero-based indexing")) {
8324  if (params.get<bool>("zero-based indexing") == true)
8325  offsetToUseInPrinting = -indexBase; // If 0-based, use as-is. If 1-based, subtract 1.
8326  }
8327 
8328  // Create map that replicates the range map on pid 0 and is empty for all other pids
8329  size_t numLocalRangeEntries = rangeMap->getNodeNumElements();
8330 
8331  // Create contiguous source map
8332  RCP<const map_type> allGidsMap = rcp(new map_type(TGOT::invalid(), numLocalRangeEntries,
8333  indexBase, comm));
8334  // Create vector based on above map. Populate it with GIDs corresponding to this pid's GIDs in rangeMap.
8335  mv_type_go allGids(allGidsMap,1);
8336  Teuchos::ArrayRCP<GO> allGidsData = allGids.getDataNonConst(0);
8337 
8338  for (size_t i=0; i<numLocalRangeEntries; i++)
8339  allGidsData[i] = rangeMap->getGlobalElement(i);
8340  allGidsData = Teuchos::null;
8341 
8342  // Create target map that is nontrivial only on pid 0
8343  GO numTargetMapEntries=TGOT::zero();
8344  Teuchos::Array<GO> importGidList;
8345  if (myRank==0) {
8346  numTargetMapEntries = rangeMap->getGlobalNumElements();
8347  importGidList.reserve(numTargetMapEntries);
8348  for (GO j=0; j<numTargetMapEntries; ++j) importGidList.push_back(j + indexBase);
8349  } else {
8350  importGidList.reserve(numTargetMapEntries);
8351  }
8352  RCP<map_type> importGidMap = rcp(new map_type(TGOT::invalid(), importGidList(), indexBase, comm));
8353 
8354  // Import all rangeMap GIDs to pid 0
8355  import_type gidImporter(allGidsMap, importGidMap);
8356  mv_type_go importedGids(importGidMap, 1);
8357  importedGids.doImport(allGids, gidImporter, INSERT);
8358 
8359  // The following import map will be non-trivial only on pid 0.
8360  ArrayRCP<const GO> importedGidsData = importedGids.getData(0);
8361  RCP<const map_type> importMap = rcp(new map_type(TGOT::invalid(), importedGidsData(), indexBase, comm) );
8362 
8363  // Importer from original range map to pid 0
8364  import_type importer(rangeMap, importMap);
8365  // Target vector on pid 0
8366  RCP<mv_type> colsOnPid0 = rcp(new mv_type(importMap,numMVs));
8367 
8368  RCP<mv_type> ei = rcp(new mv_type(A.getDomainMap(),numMVs)); //probing vector
8369  RCP<mv_type> colsA = rcp(new mv_type(A.getRangeMap(),numMVs)); //columns of A revealed by probing
8370 
8371  Array<GO> globalColsArray, localColsArray;
8372  globalColsArray.reserve(numMVs);
8373  localColsArray.reserve(numMVs);
8374 
8375  ArrayRCP<ArrayRCP<Scalar> > eiData(numMVs);
8376  for (size_t i=0; i<numMVs; ++i)
8377  eiData[i] = ei->getDataNonConst(i);
8378 
8379  // //////////////////////////////////////
8380  // Discover A by chunks
8381  // //////////////////////////////////////
8382  for (GO k=0; k<numChunks; ++k) {
8383  for (size_t j=0; j<numMVs; ++j ) {
8384  //GO curGlobalCol = maxColGid - numMVs + j + TGOT::one();
8385  GO curGlobalCol = minColGid + k*numMVs + j;
8386  globalColsArray.push_back(curGlobalCol);
8387  //TODO extract the g2l map outside of this loop loop
8388  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8389  if (curLocalCol != TLOT::invalid()) {
8390  eiData[j][curLocalCol] = TGOT::one();
8391  localColsArray.push_back(curLocalCol);
8392  }
8393  }
8394  //TODO Do the views eiData need to be released prior to the matvec?
8395 
8396  // probe
8397  A.apply(*ei,*colsA);
8398 
8399  colsOnPid0->doImport(*colsA,importer,INSERT);
8400 
8401  if (myRank==0)
8402  globalNnz += writeColumns(os,*colsOnPid0, numMVs, importedGidsData(),
8403  globalColsArray, offsetToUseInPrinting);
8404 
8405  //zero out the ei's
8406  for (size_t j=0; j<numMVs; ++j ) {
8407  for (int i=0; i<localColsArray.size(); ++i)
8408  eiData[j][localColsArray[i]] = TGOT::zero();
8409  }
8410  globalColsArray.clear();
8411  localColsArray.clear();
8412 
8413  }
8414 
8415  // //////////////////////////////////////
8416  // Handle leftover part of A
8417  // //////////////////////////////////////
8418  if (rem > 0) {
8419  for (int j=0; j<rem; ++j ) {
8420  GO curGlobalCol = maxColGid - rem + j + TGOT::one();
8421  globalColsArray.push_back(curGlobalCol);
8422  //TODO extract the g2l map outside of this loop loop
8423  LO curLocalCol = domainMap.getLocalElement(curGlobalCol);
8424  if (curLocalCol != TLOT::invalid()) {
8425  eiData[j][curLocalCol] = TGOT::one();
8426  localColsArray.push_back(curLocalCol);
8427  }
8428  }
8429  //TODO Do the views eiData need to be released prior to the matvec?
8430 
8431  // probe
8432  A.apply(*ei,*colsA);
8433 
8434  colsOnPid0->doImport(*colsA,importer,INSERT);
8435  if (myRank==0)
8436  globalNnz += writeColumns(os,*colsOnPid0, rem, importedGidsData(),
8437  globalColsArray, offsetToUseInPrinting);
8438 
8439  //zero out the ei's
8440  for (int j=0; j<rem; ++j ) {
8441  for (int i=0; i<localColsArray.size(); ++i)
8442  eiData[j][localColsArray[i]] = TGOT::zero();
8443  }
8444  globalColsArray.clear();
8445  localColsArray.clear();
8446 
8447  }
8448 
8449  // Return the Matrix Market header. It includes the header
8450  // line (that starts with "%%"), some comments, and the triple
8451  // of matrix dimensions and number of nonzero entries. We
8452  // don't actually print this here, because we don't know the
8453  // number of nonzero entries until after probing.
8454  std::ostringstream oss;
8455  if (myRank == 0) {
8456  oss << "%%MatrixMarket matrix coordinate ";
8457  if (Teuchos::ScalarTraits<typename operator_type::scalar_type>::isComplex) {
8458  oss << "complex";
8459  } else {
8460  oss << "real";
8461  }
8462  oss << " general" << std::endl;
8463  oss << "% Tpetra::Operator" << std::endl;
8464  std::time_t now = std::time(NULL);
8465  oss << "% time stamp: " << ctime(&now);
8466  oss << "% written from " << numProcs << " processes" << std::endl;
8467  size_t numRows = rangeMap->getGlobalNumElements();
8468  size_t numCols = domainMap.getGlobalNumElements();
8469  oss << numRows << " " << numCols << " " << globalNnz << std::endl;
8470  }
8471 
8472  return oss.str ();
8473  }
8474 
8475  static global_ordinal_type
8476  writeColumns(std::ostream& os, mv_type const &colsA, size_t const &numCols,
8477  Teuchos::ArrayView<const global_ordinal_type> const &rowGids,
8478  Teuchos::Array<global_ordinal_type> const &colsArray,
8479  global_ordinal_type const & indexBase) {
8480 
8481  typedef global_ordinal_type GO;
8482  typedef scalar_type Scalar;
8483  typedef Teuchos::ScalarTraits<Scalar> STS;
8484 
8485  GO nnz=0;
8486  const Scalar zero = STS::zero();
8487  const size_t numRows = colsA.getGlobalLength();
8488  for (size_t j=0; j<numCols; ++j) {
8489  Teuchos::ArrayRCP<const Scalar> const curCol = colsA.getData(j);
8490  const GO J = colsArray[j];
8491  for (size_t i=0; i<numRows; ++i) {
8492  const Scalar val = curCol[i];
8493  if (val!=zero) {
8494  os << rowGids[i]+indexBase << " " << J+indexBase << " " << val << std::endl;
8495  ++nnz;
8496  }
8497  }
8498  }
8499 
8500  return nnz;
8501 
8502  }
8503 
8504  public:
8505 
8506  }; // class Writer
8507 
8508  } // namespace MatrixMarket
8509 } // namespace Tpetra
8510 
8511 #endif // __MatrixMarket_Tpetra_hpp
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments...
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Import data into this object using an Import object ("forward mode").
Declaration of a function that prints strings from each process.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType::global_ordinal_type global_ordinal_type
One or more distributed dense vectors.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
SparseMatrixType::scalar_type scalar_type
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file, with provided Maps.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
bool isGloballyIndexed() const override
Whether the graph&#39;s column indices are stored as global indices.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps. ...
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator, in rank order.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments...
size_t global_size_t
Global size_t object.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
Insert new values that don&#39;t currently exist.
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
Abstract interface for operators (e.g., matrices and preconditioners).
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
From a distributed map build a map with all GIDs on the root node.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
size_t getNumVectors() const
Number of columns in the multivector.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream...
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments...
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
Teuchos::ArrayView< const global_ordinal_type > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
A parallel distribution of indices over processes.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
void getLocalRowView(const LocalOrdinal lclRow, local_inds_host_view_type &lclColInds) const override
Get a const view of the given local row&#39;s local column indices.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
A distributed dense vector.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
SparseMatrixType sparse_matrix_type
This class&#39; template parameter; a specialization of CrsMatrix.
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps. ...
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Matrix Market file reader for CrsMatrix and MultiVector.
Matrix Market file writer for CrsMatrix and MultiVector.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
void getGlobalRowView(const global_ordinal_type gblRow, global_inds_host_view_type &gblColInds) const override
Get a const view of the given global row&#39;s global column indices.
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp...
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.