Amesos2 - Direct Sparse Solver Interfaces  Version of the Day
Amesos2_EpetraCrsMatrix_MatrixAdapter_decl.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Amesos2: Templated Direct Sparse Solver Package
4 //
5 // Copyright 2011 NTESS and the Amesos2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 
21 #ifndef AMESOS2_EPETRACRSMATRIX_MATRIXADAPTER_DECL_HPP
22 #define AMESOS2_EPETRACRSMATRIX_MATRIXADAPTER_DECL_HPP
23 
24 #include "Amesos2_config.h"
25 
26 #include <Epetra_CrsMatrix.h>
27 #ifdef HAVE_AMESOS2_EPETRAEXT
28 #include <EpetraExt_Reindex_CrsMatrix.h>
29 #endif
30 #include <Epetra_Comm.h>
31 #include <Epetra_SerialComm.h>
32 #ifdef HAVE_MPI
33 # include <Epetra_MpiComm.h>
34 #endif
35 
37 #include "Amesos2_MatrixAdapter_decl.hpp"
38 
39 namespace Amesos2 {
40 
41  // template <class M, class D> class AbstractConcreteMatrixAdapter;
42 
55  template <>
56  class ConcreteMatrixAdapter< Epetra_CrsMatrix >
57  : public AbstractConcreteMatrixAdapter< Epetra_RowMatrix, Epetra_CrsMatrix >
58  {
59  // Give our matrix adapter class access to our private
60  // implementation functions
61  friend class MatrixAdapter< Epetra_RowMatrix >;
62  public:
63  typedef Epetra_CrsMatrix matrix_t;
64  private:
65  typedef AbstractConcreteMatrixAdapter<Epetra_RowMatrix,
66  Epetra_CrsMatrix> super_t;
67  public:
68  // 'import' superclass types
69  typedef super_t::scalar_t scalar_t;
70  typedef super_t::local_ordinal_t local_ordinal_t;
71  typedef super_t::global_ordinal_t global_ordinal_t;
72  typedef super_t::node_t node_t;
73  typedef super_t::global_size_t global_size_t;
74 
75  typedef Tpetra::Map<local_ordinal_t,global_ordinal_t,node_t> map_t;
76  typedef ConcreteMatrixAdapter<matrix_t> type;
77 
78  ConcreteMatrixAdapter(RCP<matrix_t> m);
79 
80  // get & reindex
81  RCP<const MatrixAdapter<matrix_t> > get_impl(const Teuchos::Ptr<const map_t> map, EDistribution distribution = ROOTED) const;
82  RCP<const MatrixAdapter<matrix_t> > reindex_impl(Teuchos::RCP<const map_t> &contigRowMap,
83  Teuchos::RCP<const map_t> &contigColMap,
84  const EPhase current_phase) const;
85 
86  // gather
87  template<typename KV_S, typename KV_GO, typename KV_GS, typename host_ordinal_type_array, typename host_scalar_type_array>
88  local_ordinal_t gather_impl(KV_S& nzvals, KV_GO& indices, KV_GS& pointers,
89  host_ordinal_type_array &perm_g2l,
90  host_ordinal_type_array &recvCountRows, host_ordinal_type_array &recvDisplRows,
91  host_ordinal_type_array &recvCounts, host_ordinal_type_array &recvDispls,
92  host_ordinal_type_array &transpose_map, host_scalar_type_array &nzvals_t,
93  bool column_major, EPhase current_phase) const
94  {
95  local_ordinal_t ret = -1;
96  {
97  auto rowMap = this->getRowMap();
98  auto colMap = this->getColMap();
99 #ifdef HAVE_MPI
100  auto comm = rowMap->getComm();
101  auto nRanks = comm->getSize();
102  auto myRank = comm->getRank();
103 #else
104  RCP<Teuchos::Comm<int>> comm = Teuchos::createSerialComm<int>();
105  int nRanks = 1;
106  int myRank = 0;
107 #endif // HAVE_MPI
108 
109  int *lclRowptr = nullptr;
110  int *lclColind = nullptr;
111  double *lclNzvals = nullptr;
112  this->mat_->ExtractCrsDataPointers(lclRowptr, lclColind, lclNzvals);
113 
114  int nRows = this->mat_->NumGlobalRows();
115  int myNRows = this->mat_->NumMyRows();
116  int myNnz = this->mat_->NumMyNonzeros();
117  if(current_phase == PREORDERING || current_phase == SYMBFACT) {
118  // gether rowptr
119  Kokkos::resize(recvCounts, nRanks);
120  Kokkos::resize(recvDispls, nRanks+1);
121 
122  // index-bases
123  global_ordinal_t rowIndexBase = rowMap->getIndexBase();
124  global_ordinal_t colIndexBase = colMap->getIndexBase();
125  // map from global to local
126  host_ordinal_type_array perm_l2g;
127  // workspace for column major
128  KV_GS pointers_t;
129  KV_GO indices_t;
130  bool need_to_perm = false;
131  {
132 #ifdef HAVE_AMESOS2_TIMERS
133  Teuchos::RCP< Teuchos::Time > gatherTime = Teuchos::TimeMonitor::getNewCounter ("Amesos2::gather(rowptr)");
134  Teuchos::TimeMonitor GatherTimer(*gatherTime);
135 #endif
136  Teuchos::gather<int, int> (&myNRows, 1, recvCounts.data(), 1, 0, *comm);
137  if (myRank == 0) {
138  Kokkos::resize(recvDispls, nRanks+1);
139  recvDispls(0) = 0;
140  for (int p = 1; p <= nRanks; p++) {
141  recvDispls(p) = recvDispls(p-1) + recvCounts(p-1);
142  }
143  if (recvDispls(nRanks) != nRows) {
144  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Amesos2_TpetraCrsMatrix_MatrixAdapter::gather_impl : mismatch between gathered(local nrows) and global nrows.");
145  }
146  } else {
147  for (int p = 0; p < nRanks; p++) {
148  recvCounts(p) = 0;
149  recvDispls(p) = 0;
150  }
151  recvDispls(nRanks) = 0;
152  }
153  // gether g2l perm (convert to 0-base)
154  {
155  host_ordinal_type_array lclMap;
156  Kokkos::resize(lclMap, myNRows);
157  if (myRank == 0) {
158  Kokkos::resize(perm_g2l, nRows);
159  Kokkos::resize(perm_l2g, nRows);
160  } else {
161  Kokkos::resize(perm_g2l, 1);
162  }
163  for (int i=0; i < myNRows; i++) {
164  lclMap(i) = rowMap->getGlobalElement(i);
165  }
166  Teuchos::gatherv<int, local_ordinal_t> (lclMap.data(), myNRows, perm_g2l.data(),
167  recvCounts.data(), recvDispls.data(),
168  0, *comm);
169  if (myRank == 0) {
170  for (int i=0; i < nRows; i++) {
171  perm_g2l(i) -= rowIndexBase;
172  perm_l2g(perm_g2l(i)) = i;
173  if (i != perm_g2l(i)) need_to_perm = true;
174  }
175  }
176  }
177  if (myRank == 0 && (column_major || need_to_perm)) {
178  Kokkos::resize(pointers_t, nRows+1);
179  } else if (myRank != 0) {
180  Kokkos::resize(pointers_t, 2);
181  }
182  local_ordinal_t sendIdx = (myNRows > 0 ? 1 : 0); // To skip sending the first rowptr entry (note: 0, if local matrix is empty)
183  local_ordinal_t *pointers_ = ((myRank != 0 || (column_major || need_to_perm)) ? pointers_t.data() : pointers.data());
184  Teuchos::gatherv<int, local_ordinal_t> (&lclRowptr[sendIdx], myNRows, &pointers_[1],
185  recvCounts.data(), recvDispls.data(),
186  0, *comm);
187  // save row counts/displs
188  Kokkos::resize(recvCountRows, nRanks);
189  Kokkos::resize(recvDisplRows, nRanks+1);
190  Kokkos::deep_copy(recvCountRows, recvCounts);
191  Kokkos::deep_copy(recvDisplRows, recvDispls);
192  if (myRank == 0) {
193  // shift to global pointers
194  pointers_[0] = 0;
195  recvCounts(0) = pointers_[recvDispls(1)];
196  local_ordinal_t displs = recvCounts(0);
197  for (int p = 1; p < nRanks; p++) {
198  // skip "Empty" submatrix (no rows)
199  // recvCounts(p) is zero, while pointers_[recvDispls(p+1)] now contains nnz from p-1
200  if (recvDispls(p+1) > recvDispls(p)) {
201  // save recvCounts from pth MPI
202  recvCounts(p) = pointers_[recvDispls(p+1)];
203  // shift pointers for pth MPI to global
204  for (int i = 1+recvDispls(p); i <= recvDispls(p+1); i++) {
205  pointers_[i] += displs;
206  }
207  displs += recvCounts(p);
208  }
209  }
210  ret = pointers_[nRows];
211  }
212  }
213  {
214 #ifdef HAVE_AMESOS2_TIMERS
215  Teuchos::RCP< Teuchos::Time > gatherTime = Teuchos::TimeMonitor::getNewCounter ("Amesos2::gather(colind)");
216  Teuchos::TimeMonitor GatherTimer(*gatherTime);
217 #endif
218  // gather colinds & nzvals
219  if (myRank == 0) {
220  recvDispls(0) = 0;
221  for (int p = 0; p < nRanks; p++) {
222  recvDispls(p+1) = recvDispls(p) + recvCounts(p);
223  }
224  }
225  // -- convert to global colids
226  KV_GO lclColind_ ("localColind_", myNnz);
227  for (int i = 0; i < int(myNnz); i++) lclColind_(i) = (colMap->getGlobalElement((lclColind[i])) - colIndexBase);
228  if (column_major || need_to_perm) {
229  Kokkos::resize(indices_t, indices.extent(0));
230  Teuchos::gatherv<int, local_ordinal_t> (lclColind_.data(), myNnz, indices_t.data(),
231  recvCounts.data(), recvDispls.data(),
232  0, *comm);
233  } else {
234  Teuchos::gatherv<int, local_ordinal_t> (lclColind_.data(), myNnz, indices.data(),
235  recvCounts.data(), recvDispls.data(),
236  0, *comm);
237  }
238  }
239  if (myRank == 0) {
240 #ifdef HAVE_AMESOS2_TIMERS
241  Teuchos::RCP< Teuchos::Time > gatherTime = Teuchos::TimeMonitor::getNewCounter ("Amesos2::gather(transpose index)");
242  Teuchos::TimeMonitor GatherTimer(*gatherTime);
243 #endif
244  if (column_major) {
245  // Map to transpose
246  Kokkos::resize(transpose_map, ret);
247  // Transopose to convert to CSC
248  for (int i=0; i<=nRows; i++) {
249  pointers(i) = 0;
250  }
251  for (int k=0; k<ret; k++) {
252  int col = indices_t(k);
253  if (col < nRows-1) {
254  pointers(col+2) ++;
255  }
256  }
257  for (int i=1; i < nRows; i++) {
258  pointers(i+1) += pointers(i);
259  }
260  // nonzeroes in each column are sorted in ascending row
261  for (int row=0; row<nRows; row++) {
262  int i = perm_g2l(row);
263  for (int k=pointers_t(i); k<pointers_t(i+1); k++) {
264  int col = indices_t(k);
265  transpose_map(k) = pointers(1+col);
266  indices(pointers(1+col)) = row;
267  pointers(1+col) ++;
268  }
269  }
270  } else if (need_to_perm) {
271  // Map to permute
272  Kokkos::resize(transpose_map, ret);
273  for (int i=0; i<nRows; i++) {
274  int row = perm_g2l(i);
275  pointers(row+2) = pointers_t(i+1)-pointers_t(i);
276  }
277  for (int i=1; i < nRows; i++) {
278  pointers(i+1) += pointers(i);
279  }
280  for (int i=0; i<nRows; i++) {
281  int row = perm_g2l(i);
282  for (int k=pointers_t(i); k<pointers_t(i+1); k++) {
283  int col = indices_t(k);
284  transpose_map(k) = pointers(1+row);
285  indices(pointers(1+row)) = col;
286  pointers(1+row) ++;
287  }
288  }
289  } else {
290  Kokkos::resize(transpose_map, 0);
291  }
292  }
293  }
294  //if(current_phase == NUMFACT) // Numerical values may be used in symbolic (e.g, MWM)
295  {
296  {
297 #ifdef HAVE_AMESOS2_TIMERS
298  Teuchos::RCP< Teuchos::Time > gatherTime = Teuchos::TimeMonitor::getNewCounter ("Amesos2::gather(nzvals)");
299  Teuchos::TimeMonitor GatherTimer(*gatherTime);
300 #endif
301  // gather nzvals
302  if (transpose_map.extent(0) > 0) {
303  Kokkos::resize(nzvals_t, nzvals.extent(0));
304  Teuchos::gatherv<int, scalar_t> (lclNzvals, myNnz, nzvals_t.data(),
305  recvCounts.data(), recvDispls.data(),
306  0, *comm);
307  } else {
308  Teuchos::gatherv<int, scalar_t> (lclNzvals, myNnz, nzvals.data(),
309  recvCounts.data(), recvDispls.data(),
310  0, *comm);
311  }
312  }
313  if (myRank == 0) {
314  // Insert Numerical values to transopose matrix
315  ret = pointers(nRows);
316  if (transpose_map.extent(0) > 0) {
317  for (int k=0; k<ret; k++) {
318  nzvals(transpose_map(k)) = nzvals_t(k);
319  }
320  }
321  }
322  }
323  // broadcast return value
324  Teuchos::broadcast<int, local_ordinal_t>(*comm, 0, 1, &ret);
325  }
326  return ret;
327  }
328 
330  void
331  describe (Teuchos::FancyOStream& os,
332  const Teuchos::EVerbosityLevel verbLevel =
333  Teuchos::Describable::verbLevel_default) const;
334 #ifdef HAVE_AMESOS2_EPETRAEXT
335  private:
336  mutable RCP<EpetraExt::CrsMatrix_Reindex> StdIndex_;
337  mutable RCP<Epetra_CrsMatrix> ContigMat_;
338 #endif
339  };
340 
341 } // end namespace Amesos2
342 
343 #endif // AMESOS2_EPETRACRSMATRIX_MATRIXADAPTER_DECL_HPP
EPhase
Used to indicate a phase in the direct solution.
Definition: Amesos2_TypeDecl.hpp:31
A Matrix adapter interface for Amesos2.
Definition: Amesos2_MatrixAdapter_decl.hpp:42
Provides the Epetra_RowMatrix abstraction for the concrete Epetra row matric adapters.
Definition: Amesos2_AbstractConcreteMatrixAdapter.hpp:55
EDistribution
Definition: Amesos2_TypeDecl.hpp:89