Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Tpetra_MatrixIO_def.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Tpetra: Templated Linear Algebra Services Package
4 //
5 // Copyright 2008 NTESS and the Tpetra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef TPETRA_MATRIX_IO_DEF
11 #define TPETRA_MATRIX_IO_DEF
12 
13 #include "Tpetra_CrsMatrix.hpp"
14 #include "Tpetra_MatrixIO.hpp"
15 #include <iostream>
16 
17 namespace Tpetra {
18 namespace Utils {
19 
20 
21 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
22 void
23 readHBMatrix (const std::string &filename,
24  const Teuchos::RCP<const Teuchos::Comm<int> > &comm,
26  Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > rowMap,
27  const Teuchos::RCP<Teuchos::ParameterList> &params)
28 {
30 
31  const int myRank = comm->getRank();
32  int numRows,numCols,numNZ;
33  Teuchos::ArrayRCP<Scalar> svals;
34  Teuchos::ArrayRCP<GlobalOrdinal> colinds;
35  Teuchos::ArrayRCP<int> rowptrs;
36  Teuchos::ArrayRCP<size_t> nnzPerRow;
37  int fail = 0;
38  if (myRank == 0) {
39  bool isSymmetric=false;
40  Teuchos::ArrayRCP<double> dvals;
41  Teuchos::ArrayRCP<int> colptrs, rowinds;
42  std::string type;
43  Tpetra::Utils::readHBMatDouble(filename,numRows,numCols,numNZ,type,colptrs,rowinds,dvals);
44  TEUCHOS_TEST_FOR_EXCEPT(type.size() != 3);
45  if (type[0] != 'R' && type[0] != 'r') {
46  // only real matrices right now
47  fail = 1;
48  }
49  if (fail == 0 && numNZ > 0) {
50  if (type[1] == 'S' || type[1] == 's') {
51  isSymmetric = true;
52  }
53  else {
54  isSymmetric = false;
55  }
56  }
57  if (fail == 0 && numNZ > 0) {
58  // find num non-zero per row
59  nnzPerRow = Teuchos::arcp<size_t>(numRows);
60  std::fill(nnzPerRow.begin(), nnzPerRow.end(), 0);
61  for (Teuchos::ArrayRCP<int>::const_iterator ri=rowinds.begin(); ri != rowinds.end(); ++ri) {
62  // count each row index towards its row
63  ++nnzPerRow[*ri-1];
64  }
65  if (isSymmetric) {
66  // count each column toward the corresponding row as well
67  for (int c=0; c < numCols; ++c) {
68  // the diagonal was already counted; neglect it, if it exists
69  for (int i=colptrs[c]-1; i != colptrs[c+1]-1; ++i) {
70  if (rowinds[i] != c+1) {
71  ++nnzPerRow[c];
72  ++numNZ;
73  }
74  }
75  }
76  }
77  // allocate/set new matrix data
78  svals = Teuchos::arcp<Scalar>(numNZ);
79  colinds = Teuchos::arcp<GlobalOrdinal>(numNZ);
80  rowptrs = Teuchos::arcp<int>(numRows+1);
81  rowptrs[0] = 0;
82 #ifdef HAVE_TPETRA_DEBUG
83  Teuchos::ArrayRCP<size_t> nnzPerRow_debug(nnzPerRow.size());
84  std::copy(nnzPerRow.begin(), nnzPerRow.end(), nnzPerRow_debug.begin());
85 #endif
86  for (int j=1; j <= numRows; ++j) {
87  rowptrs[j] = rowptrs[j-1] + nnzPerRow[j-1];
88  nnzPerRow[j-1] = 0;
89  }
90  // translate from column-oriented to row-oriented
91  for (int col=0; col<numCols; ++col) {
92  for (int i=colptrs[col]-1; i != colptrs[col+1]-1; ++i) {
93  const int row = rowinds[i]-1;
94  // add entry to (row,col), with value dvals[i]
95  const size_t entry = rowptrs[row] + nnzPerRow[row];
96  svals[entry] = Teuchos::as<Scalar>(dvals[i]);
97  colinds[entry] = Teuchos::as<GlobalOrdinal>(col);
98  ++nnzPerRow[row];
99  if (isSymmetric && row != col) {
100  // add entry to (col,row), with value dvals[i]
101  const size_t symentry = rowptrs[col] + nnzPerRow[col];
102  svals[symentry] = Teuchos::as<Scalar>(dvals[i]);
103  colinds[symentry] = Teuchos::as<GlobalOrdinal>(row);
104  ++nnzPerRow[col];
105  }
106  }
107  }
108 #ifdef HAVE_TPETRA_DEBUG
109  {
110  bool isequal = true;
111  typename Teuchos::ArrayRCP<size_t>::const_iterator it1, it2;
112  for (it1 = nnzPerRow.begin(), it2 = nnzPerRow_debug.begin(); it1 != nnzPerRow.end(); ++it1, ++it2) {
113  if (*it1 != *it2) {
114  isequal = false;
115  break;
116  }
117  }
118  TEUCHOS_TEST_FOR_EXCEPTION(!isequal || nnzPerRow.size() != nnzPerRow_debug.size(), std::logic_error,
119  "Tpetra::Utils::readHBMatrix(): Logic error.");
120  }
121 #endif
122  }
123  // std::cout << "Matrix " << filename << " of type " << type << ": " << numRows << " by " << numCols << ", " << numNZ << " nonzeros" << std::endl;
124  }
125  // check for read errors
126  broadcast(*comm,0,&fail);
127  TEUCHOS_TEST_FOR_EXCEPTION(fail == 1, std::runtime_error, "Tpetra::Utils::readHBMatrix() can only read Real matrices.");
128  // distribute global matrix info
129  broadcast(*comm,0,&numRows);
130  broadcast(*comm,0,&numCols);
131  // create map with uniform partitioning
132  if (rowMap == Teuchos::null) {
133  rowMap = Teuchos::rcp (new map_type (static_cast<global_size_t> (numRows),
134  static_cast<GlobalOrdinal> (0),
135  comm, GloballyDistributed));
136  }
137  else {
138  TEUCHOS_TEST_FOR_EXCEPTION( rowMap->getGlobalNumElements() != (global_size_t)numRows, std::runtime_error,
139  "Tpetra::Utils::readHBMatrix(): specified map has incorrect number of elements.");
140  TEUCHOS_TEST_FOR_EXCEPTION( rowMap->isDistributed() == false && comm->getSize() > 1, std::runtime_error,
141  "Tpetra::Utils::readHBMatrix(): specified map is not distributed.");
142  }
143  Teuchos::Array<size_t> myNNZ (rowMap->getLocalNumElements ());
144  if (myRank == 0) {
145  LocalOrdinal numRowsAlreadyDistributed = rowMap->getLocalNumElements();
146  std::copy(nnzPerRow.begin(), nnzPerRow.begin()+numRowsAlreadyDistributed, myNNZ.begin());
147  for (int p=1; p < Teuchos::size(*comm); ++p) {
148  size_t numRowsForP;
149  Teuchos::receive(*comm,p,&numRowsForP);
150  if (numRowsForP) {
151  Teuchos::send<int,size_t>(*comm,numRowsForP,nnzPerRow(numRowsAlreadyDistributed,numRowsForP).getRawPtr(),p);
152  numRowsAlreadyDistributed += numRowsForP;
153  }
154  }
155  }
156  else {
157  const size_t numMyRows = rowMap->getLocalNumElements();
158  Teuchos::send(*comm,numMyRows,0);
159  if (numMyRows) {
160  Teuchos::receive<int,size_t>(*comm,0,numMyRows,myNNZ(0,numMyRows).getRawPtr());
161  }
162  }
163  nnzPerRow = Teuchos::null;
164  // create column map
165  Teuchos::RCP<const map_type> domMap;
166  if (numRows == numCols) {
167  domMap = rowMap;
168  }
169  else {
170  domMap = createUniformContigMapWithNode<LocalOrdinal,GlobalOrdinal,Node>(numCols,comm);
171  }
172  A = rcp(new Tpetra::CrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>(rowMap, myNNZ ()));
173  // free this locally, A will keep it allocated as long as it is needed by A (up until allocation of nonzeros)
174  {
175  // Classic idiom for freeing an std::vector; resize doesn't
176  // promise deallocation.
177  Teuchos::Array<size_t> empty;
178  std::swap (myNNZ, empty);
179  }
180  if (myRank == 0 && numNZ > 0) {
181  for (int r=0; r < numRows; ++r) {
182  const LocalOrdinal nnz = rowptrs[r+1] - rowptrs[r];
183  if (nnz > 0) {
184  Teuchos::ArrayView<const GlobalOrdinal> inds = colinds(rowptrs[r],nnz);
185  Teuchos::ArrayView<const Scalar> vals = svals( rowptrs[r],nnz);
186  A->insertGlobalValues(r, inds, vals);
187  }
188  }
189  }
190  // don't need these anymore
191  colinds = Teuchos::null;
192  svals = Teuchos::null;
193  rowptrs = Teuchos::null;
194  A->fillComplete(domMap,rowMap,params);
195 }
196 
197 
198 } // namespace Utils
199 } // namespace Tpetra
200 
201 //
202 // Explicit instantiation macro
203 //
204 // Must be expanded from within the Tpetra::Utils namespace!
205 //
206 
207 
208 #define TPETRA_MATRIXIO_INSTANT(SCALAR,LO,GO,NODE) \
209  template void \
210  readHBMatrix< SCALAR, LO, GO, NODE > (const std::string&, \
211  const Teuchos::RCP<const Teuchos::Comm<int> > &, \
212  Teuchos::RCP<CrsMatrix< SCALAR, LO, GO, NODE > >&, \
213  Teuchos::RCP<const Tpetra::Map< LO, GO, NODE> >, \
214  const Teuchos::RCP<Teuchos::ParameterList>& );
215 
216 
217 
218 #endif
Sparse matrix that presents a row-oriented interface that lets users read or modify entries...
size_t global_size_t
Global size_t object.
A parallel distribution of indices over processes.