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
From a distributed map build a map with all GIDs on the root node.
Declaration of a function that prints strings from each process.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Teuchos::RCP< const map_type > getColMap() const override
Returns the Map that describes the column distribution in this graph.
global_size_t getGlobalNumEntries() const override
Returns the global number of entries in the graph.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
Returns the communicator.
void fillComplete(const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const Teuchos::RCP< Teuchos::ParameterList > &params=Teuchos::null)
Tell the graph that you are done changing its structure.
Teuchos::RCP< const map_type > getDomainMap() const override
Returns the Map associated with the domain of this graph.
void getGlobalRowView(const global_ordinal_type gblRow, global_inds_host_view_type &gblColInds) const override
Get a const view of the given global row's global column indices.
Teuchos::RCP< const map_type > getRangeMap() const override
Returns the Map associated with the domain of this graph.
Teuchos::RCP< const map_type > getRowMap() const override
Returns the Map that describes the row distribution in this graph.
void getLocalRowView(const LocalOrdinal lclRow, local_inds_host_view_type &lclColInds) const override
Get a const view of the given local row's local column indices.
bool isGloballyIndexed() const override
Whether the graph's column indices are stored as global indices.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Import data into this object using an Import object ("forward mode").
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
A parallel distribution of indices over processes.
Teuchos::ArrayView< const global_ordinal_type > getNodeElementList() const
Return a NONOWNING view of the global indices owned by this process.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
Accessors for the Teuchos::Comm and Kokkos Node objects.
global_ordinal_type getMinGlobalIndex() const
The minimum global index owned by the calling process.
global_size_t getGlobalNumElements() const
The number of elements in this Map.
bool isContiguous() const
True if this Map is distributed contiguously, else false.
size_t getNodeNumElements() const
The number of elements belonging to the calling process.
Matrix Market file reader for CrsMatrix and MultiVector.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
The MultiVector specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
SparseMatrixType::global_ordinal_type global_ordinal_type
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
Vector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > vector_type
The Vector specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file, with provided Maps.
SparseMatrixType::node_type node_type
The fourth template parameter of CrsMatrix and MultiVector.
static Teuchos::RCP< multivector_type > readDense(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market input stream.
static Teuchos::RCP< sparse_graph_type > readSparseGraph(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market input stream.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream.
SparseMatrixType::local_ordinal_type local_ordinal_type
SparseMatrixType sparse_matrix_type
This class' template parameter; a specialization of CrsMatrix.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream, with provided Maps.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
static Teuchos::RCP< vector_type > readVector(std::istream &in, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read Vector from the given Matrix Market input stream.
static Teuchos::RCP< vector_type > readVectorFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read a Vector from the given Matrix Market file.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const Teuchos::RCP< Teuchos::ParameterList > &constructorParams, const Teuchos::RCP< Teuchos::ParameterList > &fillCompleteParams, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
static Teuchos::RCP< sparse_graph_type > readSparseGraphFile(const std::string &filename, const Teuchos::RCP< const map_type > &rowMap, Teuchos::RCP< const map_type > &colMap, const Teuchos::RCP< const map_type > &domainMap, const Teuchos::RCP< const map_type > &rangeMap, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse graph from the given Matrix Market file, with provided Maps.
static Teuchos::RCP< const map_type > readMapFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< multivector_type > readDenseFile(const std::string &filename, const Teuchos::RCP< const comm_type > &comm, Teuchos::RCP< const map_type > &map, const bool tolerant=false, const bool debug=false)
Read dense matrix (as a MultiVector) from the given Matrix Market file.
static Teuchos::RCP< const map_type > readMap(std::istream &in, const Teuchos::RCP< const comm_type > &comm, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool tolerant=false, const bool debug=false)
Read Map (as a MultiVector) from the given input stream, with optional debugging output stream.
static Teuchos::RCP< sparse_matrix_type > readSparse(std::istream &in, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market input stream.
SparseMatrixType::scalar_type scalar_type
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > sparse_graph_type
The CrsGraph specialization associated with SparseMatrixType.
static Teuchos::RCP< sparse_matrix_type > readSparseFile(const std::string &filename, const Teuchos::RCP< const Teuchos::Comm< int > > &pComm, const bool callFillComplete=true, const bool tolerant=false, const bool debug=false)
Read sparse matrix from the given Matrix Market file.
Matrix Market file writer for CrsMatrix and MultiVector.
static void writeMap(std::ostream &out, const map_type &map, const bool debug=false)
Print the Map to the given output stream.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and or description.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Specialization of Tpetra::CrsGraph that matches SparseMatrixType.
static void writeSparseFile(const std::string &filename, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments.
static void writeDense(std::ostream &out, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), with no comments,...
SparseMatrixType sparse_matrix_type
Template parameter of this class; specialization of CrsMatrix.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
SparseMatrixType::scalar_type scalar_type
Type of the entries of the sparse matrix.
static void writeSparseGraphFile(const std::string &filename, const Teuchos::RCP< const crs_graph_type > &pGraph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename), taking the graph by T...
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeDense(std::ostream &out, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
SparseMatrixType::global_ordinal_type global_ordinal_type
Type of indices as read from the Matrix Market file.
SparseMatrixType::node_type node_type
The Kokkos Node type; fourth template parameter of Tpetra::CrsMatrix.
static void writeDense(std::ostream &out, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeOperator(std::ostream &out, const operator_type &A)
Write a Tpetra::Operator to an output stream.
static void writeOperator(const std::string &fileName, operator_type const &A)
Write a Tpetra::Operator to a file.
static void writeOperator(std::ostream &out, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to an output stream, with options.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const std::string &matrixName, const std::string &matrixDescription, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with matrix name and description.
static void writeDenseFile(const std::string &filename, const multivector_type &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream, with no comments.
static void writeOperator(const std::string &fileName, const operator_type &A, const Teuchos::ParameterList &params)
Write a Tpetra::Operator to a file, with options.
MultiVector< scalar_type, local_ordinal_type, global_ordinal_type, node_type > multivector_type
Specialization of Tpetra::MultiVector that matches SparseMatrixType.
static void writeSparse(std::ostream &out, const Teuchos::RCP< const sparse_matrix_type > &pMatrix, const bool debug=false)
Only for backwards compatibility; prefer the overload above.
static void writeMapFile(const std::string &filename, const map_type &map)
Write the Map to the given file.
static void writeDenseFile(const std::string &filename, const Teuchos::RCP< const multivector_type > &X, const Teuchos::RCP< Teuchos::FancyOStream > &err=Teuchos::null, const Teuchos::RCP< Teuchos::FancyOStream > &dbg=Teuchos::null)
Print the multivector in Matrix Market format, with no matrix name or description.
Map< local_ordinal_type, global_ordinal_type, node_type > map_type
Specialization of Tpetra::Map that matches SparseMatrixType.
SparseMatrixType::local_ordinal_type local_ordinal_type
Type of the local indices of the sparse matrix.
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const std::string &matrixName, const std::string &matrixDescription, const bool debug=false)
Print the sparse matrix in Matrix Market format, with comments.
static void writeSparseGraph(std::ostream &out, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given output stream.
static void writeSparseGraphFile(const std::string &filename, const crs_graph_type &graph, const std::string &graphName, const std::string &graphDescription, const bool debug=false)
Print the sparse graph in Matrix Market format to the given file (by filename).
static void writeMap(std::ostream &out, const map_type &map, const Teuchos::RCP< Teuchos::FancyOStream > &err, const bool debug=false)
Print the Map to the given output stream out.
static void writeSparseFile(const std::string &filename, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
static void writeSparse(std::ostream &out, const sparse_matrix_type &matrix, const bool debug=false)
Print the sparse matrix in Matrix Market format.
One or more distributed dense vectors.
Teuchos::RCP< const Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > getVector(const size_t j) const
Return a Vector which is a const view of column j.
size_t getNumVectors() const
Number of columns in the multivector.
Abstract interface for operators (e.g., matrices and preconditioners).
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X....
A distributed dense vector.
Matrix Market file readers and writers for sparse and dense matrices (as CrsMatrix resp....
void gathervPrint(std::ostream &out, const std::string &s, const Teuchos::Comm< int > &comm)
On Process 0 in the given communicator, print strings from each process in that communicator,...
Namespace Tpetra contains the class and methods constituting the Tpetra library.
size_t global_size_t
Global size_t object.
@ INSERT
Insert new values that don't currently exist.