Amesos2 - Direct Sparse Solver Interfaces Version of the Day
Amesos2_MatrixAdapter_def.hpp
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
11#ifndef AMESOS2_MATRIXADAPTER_DEF_HPP
12#define AMESOS2_MATRIXADAPTER_DEF_HPP
13#include <Tpetra_Util.hpp>
14#include "Amesos2_MatrixAdapter_decl.hpp"
15#include "Amesos2_ConcreteMatrixAdapter_def.hpp"
16//#include "Amesos2_ConcreteMatrixAdapter.hpp"
17
18#define TESTING_AMESOS2_WITH_TPETRA_REMOVE_UVM
19#if defined(TESTING_AMESOS2_WITH_TPETRA_REMOVE_UVM)
20#include "KokkosSparse_Utils.hpp"
21#include "KokkosSparse_SortCrs.hpp"
22#include "KokkosKernels_Sorting.hpp"
23#endif
24
25namespace Amesos2 {
26
27
28 template < class Matrix >
29 MatrixAdapter<Matrix>::MatrixAdapter(const Teuchos::RCP<Matrix> m)
30 : mat_(m)
31 {
32 comm_ = static_cast<const adapter_t*>(this)->getComm_impl();
33 col_map_ = static_cast<const adapter_t*>(this)->getColMap_impl();
34 row_map_ = static_cast<const adapter_t*>(this)->getRowMap_impl();
35 }
36
37 template < class Matrix >
38 template<typename KV_S, typename KV_GO, typename KV_GS>
39 void
40 MatrixAdapter<Matrix>::getCrs_kokkos_view(KV_S & nzval,
41 KV_GO & colind,
42 KV_GS & rowptr,
43 typename MatrixAdapter<Matrix>::global_size_t& nnz,
44 const Teuchos::Ptr<const map_t> rowmap,
45 EStorage_Ordering ordering,
46 EDistribution distribution) const
47 {
48 help_getCrs_kokkos_view(nzval, colind, rowptr,
49 nnz, rowmap, distribution, ordering,
50 typename adapter_t::get_crs_spec());
51 }
52
53 template < class Matrix >
54 template<typename KV_S, typename KV_GO, typename KV_GS>
55 void
56 MatrixAdapter<Matrix>::getCrs_kokkos_view(KV_S & nzval,
57 KV_GO & colind,
58 KV_GS & rowptr,
59 typename MatrixAdapter<Matrix>::global_size_t& nnz,
60 EDistribution distribution,
61 EStorage_Ordering ordering) const
62 {
63 const Teuchos::RCP<const map_t> rowmap
64 = Util::getDistributionMap<local_ordinal_t,global_ordinal_t,global_size_t,node_t>(distribution,
65 this->getGlobalNumRows(),
66 this->getComm());
67 this->getCrs_kokkos_view(nzval, colind, rowptr, nnz, Teuchos::ptrInArg(*rowmap), ordering, distribution);
68 }
69
70 template < class Matrix >
71 template<typename KV_S, typename KV_GO, typename KV_GS>
72 void
73 MatrixAdapter<Matrix>::getCcs_kokkos_view(KV_S & nzval,
74 KV_GO & rowind,
75 KV_GS & colptr,
76 typename MatrixAdapter<Matrix>::global_size_t& nnz,
77 const Teuchos::Ptr<const map_t> colmap,
78 EStorage_Ordering ordering,
79 EDistribution distribution) const
80 {
81 help_getCcs_kokkos_view(nzval, rowind, colptr,
82 nnz, colmap, distribution, ordering,
83 typename adapter_t::get_ccs_spec());
84 }
85
86 template < class Matrix >
87 template<typename KV_S, typename KV_GO, typename KV_GS>
88 void
89 MatrixAdapter<Matrix>::getCcs_kokkos_view(KV_S & nzval,
90 KV_GO & rowind,
91 KV_GS & colptr,
92 typename MatrixAdapter<Matrix>::global_size_t& nnz,
93 EDistribution distribution,
94 EStorage_Ordering ordering) const
95 {
96 const Teuchos::RCP<const map_t> colmap
97 = Util::getDistributionMap<local_ordinal_t,global_ordinal_t,global_size_t,node_t>(distribution,
98 this->getGlobalNumCols(),
99 this->getComm());
100 this->getCcs_kokkos_view(nzval, rowind, colptr, nnz, Teuchos::ptrInArg(*colmap), ordering, distribution);
101 }
102
103
104 template < class Matrix >
105 typename MatrixAdapter<Matrix>::global_size_t
107 {
108 return static_cast<const adapter_t*>(this)->getGlobalNumRows_impl();
109 }
110
111 template < class Matrix >
112 typename MatrixAdapter<Matrix>::global_size_t
114 {
115 return static_cast<const adapter_t*>(this)->getGlobalNumCols_impl();
116 }
117
118 template < class Matrix >
119 typename MatrixAdapter<Matrix>::global_size_t
121 {
122 // Kokkos adapter is for serial only testing right now and will not
123 // create row_map_
124 return (row_map_ != Teuchos::null) ? row_map_->getIndexBase() : 0;
125 }
126
127 template < class Matrix >
128 typename MatrixAdapter<Matrix>::global_size_t
130 {
131 // Kokkos adapter is for serial only testing right now and will not
132 // create col_map_
133 return (col_map_ != Teuchos::null) ? col_map_->getIndexBase() : 0;
134 }
135
136 template < class Matrix >
137 typename MatrixAdapter<Matrix>::global_size_t
139 {
140 return static_cast<const adapter_t*>(this)->getGlobalNNZ_impl();
141 }
142
143 template < class Matrix >
144 size_t
146 {
147 return row_map_->getLocalNumElements(); // TODO: verify
148 }
149
150 template < class Matrix >
151 size_t
153 {
154 return col_map_->getLocalNumElements();
155 }
156
157 template < class Matrix >
158 size_t
160 {
161 return static_cast<const adapter_t*>(this)->getLocalNNZ_impl();
162 }
163
164 // NDE: This is broken for Epetra_CrsMatrix
165 template < class Matrix >
166 std::string
168 {
169 std::ostringstream oss;
170 oss << "Amesos2::MatrixAdapter wrapping: ";
171 oss << mat_->description(); // NDE: This is not defined in Epetra_CrsMatrix, only in Tpetra::CrsMatrix
172 return oss.str();
173 }
174
175 template < class Matrix >
176 void
177 MatrixAdapter<Matrix>::describe(Teuchos::FancyOStream &out,
178 const Teuchos::EVerbosityLevel verbLevel) const
179 {
180 // (implemented for Epetra::CrsMatrix & Tpetra::CrsMatrix)
181 return static_cast<const adapter_t*>(this)->describe(out, verbLevel);
182 }
184 template < class Matrix >
185 template < class KV >
187 {
188 return static_cast<const adapter_t*>(this)->getSparseRowPtr_kokkos_view(view);
190
191 template < class Matrix >
192 template < class KV >
194 {
195 return static_cast<const adapter_t*>(this)->getSparseColInd_kokkos_view(view);
196 }
197
198 template < class Matrix >
199 template < class KV >
202 return static_cast<const adapter_t*>(this)->getSparseValues_kokkos_view(view);
203 }
204
205 /******************************
206 * Private method definitions *
207 ******************************/
208 template < class Matrix >
209 template<typename KV_S, typename KV_GO, typename KV_GS>
210 void
212 KV_GO & colind,
213 KV_GS & rowptr,
214 typename MatrixAdapter<Matrix>::global_size_t& nnz,
215 const Teuchos::Ptr<const map_t> rowmap,
216 EDistribution distribution,
217 EStorage_Ordering ordering,
218 no_special_impl nsi) const
219 {
220
221 //Added void to remove parameter not used warning
222 ((void)nsi);
223 do_getCrs_kokkos_view(nzval, colind, rowptr,
224 nnz, rowmap, distribution, ordering,
225 typename adapter_t::major_access());
227
228 template < class Matrix >
229 template<typename KV_S, typename KV_GO, typename KV_GS>
230 void
232 KV_GO & colind,
233 KV_GS & rowptr,
234 typename MatrixAdapter<Matrix>::global_size_t& nnz,
235 const Teuchos::Ptr<const map_t> rowmap,
236 EDistribution distribution,
238 row_access ra) const
239 {
240 // Kokkos adapter will be serial and won't have the rowmap.
241 // Tacho for example wouldn't ever call this in serial but Cholmod will
242 // call ccs and want to convert using this.
243 // If the kokkos adapter is extended to multiple ranks then this will
244 // need to change.
245 if(this->row_map_ == Teuchos::null) {
246 this->returnValues_kokkos_view(nzval);
247 this->returnRowPtr_kokkos_view(rowptr);
248 this->returnColInd_kokkos_view(colind);
249 size_t m = rowptr.extent(0)-1;
250 nnz = rowptr(m); //nzval.size(); // in case there are extra space in nzval or colind
251 return;
252 }
253
254 using Teuchos::rcp;
255 using Teuchos::RCP;
256 using Teuchos::ArrayView;
257 using Teuchos::OrdinalTraits;
258
259 ((void) ra);
260
261 RCP<const type> get_mat;
262 if( *rowmap == *this->row_map_ && distribution != CONTIGUOUS_AND_ROOTED ){
263 // No need to redistribute
264 get_mat = rcp(this,false); // non-owning
265 } else {
266 get_mat = get(rowmap, distribution);
267 }
268 // RCP<const type> get_mat = get(rowmap);
269
270 // rmap may not necessarily check same as rowmap because rmap may
271 // have been constructued with Tpetra's "expert" constructor,
272 // which assumes that the map points are non-contiguous.
273 //
274 // TODO: There may be some more checking between the row map
275 // compatibility, but things are working fine now.
276
277 RCP<const map_t> rmap = get_mat->getRowMap();
278 ArrayView<const global_ordinal_t> node_elements = rmap->getLocalElementList();
279 //if( node_elements.size() == 0 ) return; // no more contribution
280 typename ArrayView<const global_ordinal_t>::iterator row_it, row_end;
281 row_end = node_elements.end();
282
283 size_t rowptr_ind = OrdinalTraits<size_t>::zero();
284 global_ordinal_t rowInd = OrdinalTraits<global_ordinal_t>::zero();
285
286 // For rowptr we can just make a mirror and deep_copy at the end
287 typename KV_GS::host_mirror_type host_rowptr = Kokkos::create_mirror_view(rowptr);
288
289 #if !defined(TESTING_AMESOS2_WITH_TPETRA_REMOVE_UVM)
290 // Note nzval, colind, and rowptr will not all be in the same memory space.
291 // Currently only Cholmod exercises this code which has all the arrays on host,
292 // so this will need extension and testing when we have a solver using device here.
293 Kokkos::View<scalar_t*, Kokkos::HostSpace>
294 mat_nzval(Kokkos::ViewAllocateWithoutInitializing("mat_nzval"), nzval.size());
295
296 Kokkos::View<global_ordinal_t*, Kokkos::HostSpace>
297 mat_colind(Kokkos::ViewAllocateWithoutInitializing("mat_colind"), colind.size());
298
299 ArrayView<scalar_t> nzval_arrayview(mat_nzval.data(), nzval.size());
300 ArrayView<global_ordinal_t> colind_arrayview(mat_colind.data(), colind.size());
301
302 for( row_it = node_elements.begin(); row_it != row_end; ++row_it ){
303 host_rowptr(rowptr_ind++) = rowInd;
304 size_t rowNNZ = get_mat->getGlobalRowNNZ(*row_it);
305 size_t nnzRet = OrdinalTraits<size_t>::zero();
306 ArrayView<global_ordinal_t> colind_view = colind_arrayview.view(rowInd,rowNNZ);
307 ArrayView<scalar_t> nzval_view = nzval_arrayview.view(rowInd,rowNNZ);
308
309 get_mat->getGlobalRowCopy(*row_it, colind_view, nzval_view, nnzRet);
310
311 for (size_t rr = 0; rr < nnzRet ; rr++) {
312 colind_view[rr] -= rmap->getIndexBase();
313 }
314
315 // It was suggested that instead of sorting each row's indices
316 // individually, that we instead do a double-transpose at the
317 // end, which would also lead to the indices being sorted.
318 if( ordering == SORTED_INDICES ) {
319 Tpetra::sort2(colind_view.begin(), colind_view.end(), nzval_view.begin());
320 }
321
322 TEUCHOS_TEST_FOR_EXCEPTION( rowNNZ != nnzRet,
323 std::runtime_error,
324 "Number of values returned different from "
325 "number of values reported");
326 rowInd += rowNNZ;
327 }
328 host_rowptr(rowptr_ind) = nnz = rowInd;
329
330 deep_copy_or_assign_view(nzval, mat_nzval);
331 deep_copy_or_assign_view(colind, mat_colind);
332 deep_copy_or_assign_view(rowptr, host_rowptr);
333 #else
334 // create temporary views to hold colind and nvals (TODO: allocate as much as needed, also for rowptr)
335 global_host_idx_t mat_colind(Kokkos::ViewAllocateWithoutInitializing("mat_colind"), nzval.size());
336 global_host_val_t mat_nzvals(Kokkos::ViewAllocateWithoutInitializing("mat_nzvals"), colind.size());
337
338 auto host_colind = Kokkos::create_mirror_view(colind);
339 auto host_nzval = Kokkos::create_mirror_view(nzval);
340
341 // load crs (on host)
342 for( row_it = node_elements.begin(); row_it != row_end; ++row_it ){
343 size_t rowNNZ = get_mat->getGlobalRowNNZ(*row_it);
344 size_t nnzRet = OrdinalTraits<size_t>::zero();
345 //using range_type = Kokkos::pair<int, int>;
346 //auto colind_view = Kokkos::subview(mat_colind, range_type(rowInd, rowInd+rowNNZ));
347 //auto nzval_view = Kokkos::subview(mat_nzvals, range_type(rowInd, rowInd+rowNNZ));
348 global_host_idx_t colind_view (&(mat_colind(rowInd)), rowNNZ);
349 global_host_val_t nzvals_view (&(mat_nzvals(rowInd)), rowNNZ);
350
351 global_ordinal_t row_id = *row_it;
352 get_mat->getGlobalRowCopy_kokkos_view(row_id, colind_view, nzvals_view, nnzRet);
353
354 TEUCHOS_TEST_FOR_EXCEPTION( rowNNZ != nnzRet,
355 std::runtime_error,
356 "Number of values returned different from "
357 "number of values reported");
358 host_rowptr(rowptr_ind++) = rowInd;
359 rowInd += rowNNZ;
360 }
361 host_rowptr(rowptr_ind) = nnz = rowInd;
362
363 // fix index-base
364 if (rmap->getIndexBase() != 0) {
365 for (size_t k = 0; k < mat_colind.extent(0); k++) {
366 mat_colind(k) -= rmap->getIndexBase();
367 }
368 }
369
370 // copy to device (note: everything in the vectors are copied, though they may not be used)
371 deep_copy_or_assign_view(nzval, mat_nzvals);
372 deep_copy_or_assign_view(colind, mat_colind);
373 deep_copy_or_assign_view(rowptr, host_rowptr);
374
375 // sort
376 if( ordering == SORTED_INDICES ) {
377 using execution_space = typename KV_GS::execution_space;
378 KokkosSparse::sort_crs_matrix <execution_space, KV_GS, KV_GO, KV_S>
379 (rowptr, colind, nzval);
380 }
381 #endif
382 }
383
384 template < class Matrix >
385 template<typename KV_S, typename KV_GO, typename KV_GS>
386 void
387 MatrixAdapter<Matrix>::help_getCcs_kokkos_view(KV_S & nzval,
388 KV_GO & rowind,
389 KV_GS & colptr,
390 typename MatrixAdapter<Matrix>::global_size_t& nnz,
391 const Teuchos::Ptr<const map_t> colmap,
392 EDistribution distribution,
393 EStorage_Ordering ordering,
394 no_special_impl nsi) const
395 {
396
397 //Added void to remove parameter not used warning
398 ((void)nsi);
399 do_getCcs_kokkos_view(nzval, rowind, colptr,
400 nnz, colmap, distribution, ordering,
401 typename adapter_t::major_access());
402 }
403
404 template < class Matrix >
405 template<typename KV_S, typename KV_GO, typename KV_GS>
406 void
407 MatrixAdapter<Matrix>::do_getCcs_kokkos_view(KV_S & nzval,
408 KV_GO & rowind,
409 KV_GS & colptr,
410 typename MatrixAdapter<Matrix>::global_size_t& nnz,
411 const Teuchos::Ptr<const map_t> colmap,
412 EDistribution distribution,
413 EStorage_Ordering ordering,
414 row_access ra) const
415 {
416 using Teuchos::ArrayView;
417 // get the crs and transpose
418
419 ((void) ra);
420
421 KV_S nzval_tmp(Kokkos::ViewAllocateWithoutInitializing("nzval_tmp"), nzval.size());
422 KV_GO colind(Kokkos::ViewAllocateWithoutInitializing("colind"), rowind.size());
423 KV_GS rowptr(Kokkos::ViewAllocateWithoutInitializing("rowptr"), this->getGlobalNumRows() + 1);
424
425 this->getCrs_kokkos_view(nzval_tmp, colind, rowptr, nnz, colmap, ordering, distribution);
426
427 if(nnz > 0) {
428 // This is currently just used by Cholmod in which case the views will be
429 // host, even if Cholmod is using GPU. Will need to upgrade this section
430 // to properly handle device when we have a solver that needs it.
431 ArrayView<typename KV_S::value_type> av_nzval_tmp(nzval_tmp.data(), nzval_tmp.size());
432 ArrayView<typename KV_GO::value_type> av_colind(colind.data(), colind.size());
433 ArrayView<typename KV_GS::value_type> av_rowptr(rowptr.data(), rowptr.size());
434 ArrayView<typename KV_S::value_type> av_nzval(nzval.data(), nzval.size());
435 ArrayView<typename KV_GO::value_type> av_rowind(rowind.data(), rowind.size());
436 ArrayView<typename KV_GS::value_type> av_colptr(colptr.data(), colptr.size());
437 Util::transpose(av_nzval_tmp, av_colind, av_rowptr, av_nzval, av_rowind, av_colptr);
438 }
439 }
440
441 // These will link to concrete implementations
442 template < class Matrix >
443 template<typename KV_GO, typename KV_S>
444 void
446 KV_GO & indices,
447 KV_S & vals,
448 size_t& nnz) const
449 {
450 static_cast<const adapter_t*>(this)->getGlobalRowCopy_kokkos_view_impl(row, indices, vals, nnz);
451 }
452
453 template < class Matrix >
454 size_t
456 {
457 return static_cast<const adapter_t*>(this)->getMaxRowNNZ_impl();
458 }
459
460 template < class Matrix >
461 size_t
462 MatrixAdapter<Matrix>::getMaxColNNZ() const
463 {
464 return static_cast<const adapter_t*>(this)->getMaxColNNZ_impl();
465 }
466
467 template < class Matrix >
468 size_t
469 MatrixAdapter<Matrix>::getGlobalRowNNZ(global_ordinal_t row) const
470 {
471 return static_cast<const adapter_t*>(this)->getGlobalRowNNZ_impl(row);
472 }
473
474 template < class Matrix >
475 size_t
476 MatrixAdapter<Matrix>::getLocalRowNNZ(local_ordinal_t row) const
477 {
478 return static_cast<const adapter_t*>(this)->getLocalRowNNZ_impl(row);
479 }
480
481 template < class Matrix >
482 size_t
483 MatrixAdapter<Matrix>::getGlobalColNNZ(global_ordinal_t col) const
484 {
485 return static_cast<const adapter_t*>(this)->getGlobalColNNZ_impl(col);
486 }
487
488 template < class Matrix >
489 size_t
490 MatrixAdapter<Matrix>::getLocalColNNZ(local_ordinal_t col) const
491 {
492 return static_cast<const adapter_t*>(this)->getLocalColNNZ_impl(col);
493 }
494
495 template < class Matrix >
496 bool
497 MatrixAdapter<Matrix>::isLocallyIndexed() const
498 {
499 return static_cast<const adapter_t*>(this)->isLocallyIndexed_impl();
500 }
501
502 template < class Matrix >
503 bool
504 MatrixAdapter<Matrix>::isGloballyIndexed() const
505 {
506 return static_cast<const adapter_t*>(this)->isGloballyIndexed_impl();
507 }
508
509
510 template < class Matrix >
511 Teuchos::RCP<const MatrixAdapter<Matrix> >
512 MatrixAdapter<Matrix>::get(const Teuchos::Ptr<const map_t> map, EDistribution distribution) const
513 {
514 return static_cast<const adapter_t*>(this)->get_impl(map, distribution);
515 }
516
517
518 template < class Matrix >
519 Teuchos::RCP<const MatrixAdapter<Matrix> >
520 MatrixAdapter<Matrix>::reindex(Teuchos::RCP<const map_t> &contigRowMap, Teuchos::RCP<const map_t> &contigColMap, const EPhase current_phase) const
521 {
522 return static_cast<const adapter_t*>(this)->reindex_impl(contigRowMap, contigColMap, current_phase);
523 }
524
525 template < class Matrix >
526 template<typename KV_S, typename KV_GO, typename KV_GS, typename host_ordinal_type_array, typename host_scalar_type_array>
527 typename MatrixAdapter<Matrix>::local_ordinal_t
528 MatrixAdapter<Matrix>::gather(KV_S& nzvals, KV_GO& indices, KV_GS& pointers,
529 host_ordinal_type_array &perm_g2l,
530 host_ordinal_type_array &recvCountRows, host_ordinal_type_array &recvDisplRows,
531 host_ordinal_type_array &recvCounts, host_ordinal_type_array &recvDispls,
532 host_ordinal_type_array &transpose_map, host_scalar_type_array &nzvals_t,
533 bool column_major, EPhase current_phase) const
534 {
535 return static_cast<const adapter_t*>(this)->gather_impl(nzvals, indices, pointers, perm_g2l, recvCountRows, recvDisplRows, recvCounts, recvDispls,
536 transpose_map, nzvals_t, column_major, current_phase);
537 }
538
539 template <class Matrix>
540 Teuchos::RCP<MatrixAdapter<Matrix> >
541 createMatrixAdapter(Teuchos::RCP<Matrix> m){
542 using Teuchos::rcp;
543 using Teuchos::rcp_const_cast;
544
545 if(m.is_null()) return Teuchos::null;
546 return( rcp(new ConcreteMatrixAdapter<Matrix>(m)) );
547 }
548
549 template <class Matrix>
550 Teuchos::RCP<const MatrixAdapter<Matrix> >
551 createConstMatrixAdapter(Teuchos::RCP<const Matrix> m){
552 using Teuchos::rcp;
553 using Teuchos::rcp_const_cast;
554
555 if(m.is_null()) return Teuchos::null;
556 return( rcp(new ConcreteMatrixAdapter<Matrix>(rcp_const_cast<Matrix,const Matrix>(m))).getConst() );
557 }
558
559} // end namespace Amesos2
560
561#endif // AMESOS2_MATRIXADAPTER_DEF_HPP
EDistribution
Definition Amesos2_TypeDecl.hpp:89
EStorage_Ordering
Definition Amesos2_TypeDecl.hpp:107
A Matrix adapter interface for Amesos2.
Definition Amesos2_MatrixAdapter_decl.hpp:42
std::string description() const
Returns a short description of this Solver.
Definition Amesos2_MatrixAdapter_def.hpp:167
EPhase
Used to indicate a phase in the direct solution.
Definition Amesos2_TypeDecl.hpp:31
Indicates that the concrete class can use the generic getC{c|r}s methods implemented in MatrixAdapter...
Definition Amesos2_TypeDecl.hpp:57
Indicates that the object of an adapter provides row access to its data.
Definition Amesos2_TypeDecl.hpp:66