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
39namespace 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
Provides the Epetra_RowMatrix abstraction for the concrete Epetra row matric adapters.
EDistribution
Definition Amesos2_TypeDecl.hpp:89
@ ROOTED
Definition Amesos2_TypeDecl.hpp:93
Definition Amesos2_AbstractConcreteMatrixAdapter.hpp:55
A Matrix adapter interface for Amesos2.
Definition Amesos2_MatrixAdapter_decl.hpp:42
EPhase
Used to indicate a phase in the direct solution.
Definition Amesos2_TypeDecl.hpp:31