MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_MatrixConstruction.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_MATRIXCONSTRUCTION_HPP
11 #define MUELU_MATRIXCONSTRUCTION_HPP
12 
13 #include "Kokkos_Core.hpp"
14 #include "Kokkos_ArithTraits.hpp"
15 
16 #include "MueLu_DroppingCommon.hpp"
17 
18 #ifdef MUELU_COALESCE_DROP_DEBUG
19 // For demangling function names
20 #include <cxxabi.h>
21 #endif
22 
23 namespace MueLu::MatrixConstruction {
34 template <class local_matrix_type, class functor_type, class... remaining_functor_types>
36  private:
37  using scalar_type = typename local_matrix_type::value_type;
38  using local_ordinal_type = typename local_matrix_type::ordinal_type;
39  using memory_space = typename local_matrix_type::memory_space;
40  using results_view = Kokkos::View<DecisionType*, memory_space>;
41 
42  using rowptr_type = typename local_matrix_type::row_map_type::non_const_type;
43 
44  local_matrix_type A;
47  functor_type functor;
48  PointwiseCountingFunctor<local_matrix_type, remaining_functor_types...> remainingFunctors;
50 
51 #ifdef MUELU_COALESCE_DROP_DEBUG
52  std::string functorName;
53 #endif
54 
55  public:
56  PointwiseCountingFunctor(local_matrix_type& A_, results_view& results_, rowptr_type& rowptr_, functor_type& functor_, remaining_functor_types&... remainingFunctors_)
57  : A(A_)
58  , results(results_)
59  , rowptr(rowptr_)
60  , functor(functor_)
61  , remainingFunctors(A_, results_, rowptr_, false, remainingFunctors_...)
62  , firstFunctor(true) {
63 #ifdef MUELU_COALESCE_DROP_DEBUG
64  std::string mangledFunctorName = typeid(decltype(functor)).name();
65  int status = 0;
66  char* demangledFunctorName = 0;
67  demangledFunctorName = abi::__cxa_demangle(functorName.c_str(), 0, 0, &status);
68  functorName = demangledFunctorName;
69 #endif
70  }
71 
72  PointwiseCountingFunctor(local_matrix_type& A_, results_view& results_, rowptr_type& rowptr_, bool firstFunctor_, functor_type& functor_, remaining_functor_types&... remainingFunctors_)
73  : A(A_)
74  , results(results_)
75  , rowptr(rowptr_)
76  , functor(functor_)
77  , remainingFunctors(A_, results_, rowptr_, false, remainingFunctors_...)
78  , firstFunctor(firstFunctor_) {
79 #ifdef MUELU_COALESCE_DROP_DEBUG
80  std::string mangledFunctorName = typeid(decltype(functor)).name();
81  int status = 0;
82  char* demangledFunctorName = 0;
83  demangledFunctorName = abi::__cxa_demangle(functorName.c_str(), 0, 0, &status);
84  functorName = demangledFunctorName;
85 #endif
86  }
87 
88  KOKKOS_INLINE_FUNCTION
89  void operator()(const local_ordinal_type rlid, local_ordinal_type& nnz, const bool& final) const {
90 #ifdef MUELU_COALESCE_DROP_DEBUG
91  if (firstFunctor) {
92  Kokkos::printf("\nStarting on row %d\n", rlid);
93 
94  auto row = A.rowConst(rlid);
95 
96  Kokkos::printf("indices: ");
97  for (local_ordinal_type k = 0; k < row.length; ++k) {
98  auto clid = row.colidx(k);
99  Kokkos::printf("%5d ", clid);
100  }
101  Kokkos::printf("\n");
102 
103  Kokkos::printf("values: ");
104  for (local_ordinal_type k = 0; k < row.length; ++k) {
105  auto val = row.value(k);
106  Kokkos::printf("%5f ", val);
107  }
108  Kokkos::printf("\n");
109  }
110 #endif
111 
112  functor(rlid);
113 
114 #ifdef MUELU_COALESCE_DROP_DEBUG
115  {
116  Kokkos::printf("%s\n", functorName.c_str());
117 
118  auto row = A.rowConst(rlid);
119  const size_t offset = A.graph.row_map(rlid);
120 
121  Kokkos::printf("decisions: ");
122  for (local_ordinal_type k = 0; k < row.length; ++k) {
123  Kokkos::printf("%5d ", results(offset + k));
124  }
125  Kokkos::printf("\n");
126  }
127 #endif
128 
129  remainingFunctors(rlid, nnz, final);
130  }
131 };
132 
133 template <class local_matrix_type, class functor_type>
134 class PointwiseCountingFunctor<local_matrix_type, functor_type> {
135  private:
136  using scalar_type = typename local_matrix_type::value_type;
137  using local_ordinal_type = typename local_matrix_type::ordinal_type;
138  using memory_space = typename local_matrix_type::memory_space;
139  using results_view = Kokkos::View<DecisionType*, memory_space>;
140 
141  using rowptr_type = typename local_matrix_type::row_map_type::non_const_type;
142 
143  local_matrix_type A;
146  functor_type functor;
148 
149 #ifdef MUELU_COALESCE_DROP_DEBUG
150  std::string functorName;
151 #endif
152 
153  public:
154  PointwiseCountingFunctor(local_matrix_type& A_, results_view& results_, rowptr_type& rowptr_, functor_type& functor_)
155  : A(A_)
156  , results(results_)
157  , rowptr(rowptr_)
158  , functor(functor_)
159  , firstFunctor(true) {
160 #ifdef MUELU_COALESCE_DROP_DEBUG
161  std::string mangledFunctorName = typeid(decltype(functor)).name();
162  int status = 0;
163  char* demangledFunctorName = 0;
164  demangledFunctorName = abi::__cxa_demangle(functorName.c_str(), 0, 0, &status);
165  functorName = demangledFunctorName;
166 #endif
167  }
168 
169  PointwiseCountingFunctor(local_matrix_type& A_, results_view& results_, rowptr_type& rowptr_, bool firstFunctor_, functor_type& functor_)
170  : A(A_)
171  , results(results_)
172  , rowptr(rowptr_)
173  , functor(functor_)
174  , firstFunctor(firstFunctor_) {
175 #ifdef MUELU_COALESCE_DROP_DEBUG
176  std::string mangledFunctorName = typeid(decltype(functor)).name();
177  int status = 0;
178  char* demangledFunctorName = 0;
179  demangledFunctorName = abi::__cxa_demangle(functorName.c_str(), 0, 0, &status);
180  functorName = demangledFunctorName;
181 #endif
182  }
183 
184  KOKKOS_INLINE_FUNCTION
185  void operator()(const local_ordinal_type rlid, local_ordinal_type& nnz, const bool& final) const {
186 #ifdef MUELU_COALESCE_DROP_DEBUG
187  if (firstFunctor) {
188  Kokkos::printf("\nStarting on row %d\n", rlid);
189 
190  auto row = A.rowConst(rlid);
191 
192  Kokkos::printf("indices: ");
193  for (local_ordinal_type k = 0; k < row.length; ++k) {
194  auto clid = row.colidx(k);
195  Kokkos::printf("%5d ", clid);
196  }
197  Kokkos::printf("\n");
198 
199  Kokkos::printf("values: ");
200  for (local_ordinal_type k = 0; k < row.length; ++k) {
201  auto val = row.value(k);
202  Kokkos::printf("%5f ", val);
203  }
204  Kokkos::printf("\n");
205  }
206 #endif
207 
208  functor(rlid);
209 
210 #ifdef MUELU_COALESCE_DROP_DEBUG
211  Kokkos::printf("%s\n", functorName);
212 
213  auto row = A.rowConst(rlid);
214  const size_t offset = A.graph.row_map(rlid);
215 
216  Kokkos::printf("decisions: ");
217  for (local_ordinal_type k = 0; k < row.length; ++k) {
218  Kokkos::printf("%5d ", results(offset + k));
219  }
220 
221  Kokkos::printf("\n");
222  Kokkos::printf("Done with row %d\n", rlid);
223 #endif
224 
225  size_t start = A.graph.row_map(rlid);
226  size_t end = A.graph.row_map(rlid + 1);
227  for (size_t i = start; i < end; ++i) {
228  if (results(i) == KEEP) {
229  ++nnz;
230  }
231  }
232  if (final)
233  rowptr(rlid + 1) = nnz;
234  }
235 };
236 
245 template <class local_matrix_type, class local_graph_type, bool lumping>
247  private:
248  using scalar_type = typename local_matrix_type::value_type;
249  using local_ordinal_type = typename local_matrix_type::ordinal_type;
250  using memory_space = typename local_matrix_type::memory_space;
251  using results_view = Kokkos::View<DecisionType*, memory_space>;
252  using ATS = Kokkos::ArithTraits<scalar_type>;
253  using magnitudeType = typename ATS::magnitudeType;
254 
255  local_matrix_type A;
257  local_matrix_type filteredA;
258  local_graph_type graph;
260  const scalar_type zero = ATS::zero();
261  const scalar_type one = ATS::one();
262 
263  public:
264  PointwiseFillReuseFunctor(local_matrix_type& A_, results_view& results_, local_matrix_type& filteredA_, local_graph_type& graph_, magnitudeType dirichletThreshold_)
265  : A(A_)
266  , results(results_)
267  , filteredA(filteredA_)
268  , graph(graph_)
269  , dirichletThreshold(dirichletThreshold_) {}
270 
271  KOKKOS_INLINE_FUNCTION
272  void operator()(const local_ordinal_type rlid) const {
273  auto rowA = A.row(rlid);
274  size_t row_start = A.graph.row_map(rlid);
275  auto rowFilteredA = filteredA.row(rlid);
276  local_ordinal_type j = 0;
277  local_ordinal_type jj = 0;
278  local_ordinal_type graph_offset = graph.row_map(rlid);
279  scalar_type diagCorrection = zero;
280  local_ordinal_type diagOffset = -1;
281  for (local_ordinal_type k = 0; k < rowA.length; ++k) {
282  if constexpr (lumping) {
283  local_ordinal_type clid = rowA.colidx(k);
284  if (rlid == clid) {
285  diagOffset = j;
286  }
287  }
288  if (results(row_start + k) == KEEP) {
289  rowFilteredA.colidx(j) = rowA.colidx(k);
290  rowFilteredA.value(j) = rowA.value(k);
291  ++j;
292  graph.entries(graph_offset + jj) = rowA.colidx(k);
293  ++jj;
294  } else if constexpr (lumping) {
295  diagCorrection += rowA.value(k);
296  rowFilteredA.colidx(j) = rowA.colidx(k);
297  rowFilteredA.value(j) = zero;
298  ++j;
299  } else {
300  rowFilteredA.colidx(j) = rowA.colidx(k);
301  rowFilteredA.value(j) = zero;
302  ++j;
303  }
304  }
305  if constexpr (lumping) {
306  rowFilteredA.value(diagOffset) += diagCorrection;
307  if ((dirichletThreshold >= 0.0) && (ATS::real(rowFilteredA.value(diagOffset)) <= dirichletThreshold))
308  rowFilteredA.value(diagOffset) = one;
309  }
310  }
311 };
312 
320 template <class local_matrix_type, bool lumping>
322  private:
323  using scalar_type = typename local_matrix_type::value_type;
324  using local_ordinal_type = typename local_matrix_type::ordinal_type;
325  using memory_space = typename local_matrix_type::memory_space;
326  using results_view = Kokkos::View<DecisionType*, memory_space>;
327  using ATS = Kokkos::ArithTraits<scalar_type>;
328  using magnitudeType = typename ATS::magnitudeType;
329 
330  local_matrix_type A;
332  local_matrix_type filteredA;
334  const scalar_type zero = ATS::zero();
335  const scalar_type one = ATS::one();
336 
337  public:
338  PointwiseFillNoReuseFunctor(local_matrix_type& A_, results_view& results_, local_matrix_type& filteredA_, magnitudeType dirichletThreshold_)
339  : A(A_)
340  , results(results_)
341  , filteredA(filteredA_)
342  , dirichletThreshold(dirichletThreshold_) {}
343 
344  KOKKOS_INLINE_FUNCTION
345  void operator()(const local_ordinal_type rlid) const {
346  auto rowA = A.row(rlid);
347  size_t K = A.graph.row_map(rlid);
348  auto rowFilteredA = filteredA.row(rlid);
349  local_ordinal_type j = 0;
350  scalar_type diagCorrection = zero;
351  local_ordinal_type diagOffset = -1;
352  for (local_ordinal_type k = 0; k < rowA.length; ++k) {
353  if constexpr (lumping) {
354  local_ordinal_type clid = rowA.colidx(k);
355  if (rlid == clid) {
356  diagOffset = j;
357  }
358  }
359  if (results(K + k) == KEEP) {
360  rowFilteredA.colidx(j) = rowA.colidx(k);
361  rowFilteredA.value(j) = rowA.value(k);
362  ++j;
363  } else if constexpr (lumping) {
364  diagCorrection += rowA.value(k);
365  }
366  }
367  if constexpr (lumping) {
368  rowFilteredA.value(diagOffset) += diagCorrection;
369  if ((dirichletThreshold >= 0.0) && (ATS::real(rowFilteredA.value(diagOffset)) <= dirichletThreshold))
370  rowFilteredA.value(diagOffset) = one;
371  }
372  }
373 };
374 
375 template <class local_matrix_type>
377  public:
378  using local_ordinal_type = typename local_matrix_type::ordinal_type;
379  using memory_space = typename local_matrix_type::memory_space;
380  using block_indices_view_type = Kokkos::View<local_ordinal_type*, memory_space>;
381 
382  local_matrix_type A;
385 
386  public:
387  BlockRowComparison(local_matrix_type& A_, local_ordinal_type bsize_, block_indices_view_type ghosted_point_to_block_)
388  : A(A_)
389  , bsize(bsize_)
390  , ghosted_point_to_block(ghosted_point_to_block_) {}
391 
392  template <class local_matrix_type2>
393  struct Comparator {
394  private:
395  using local_ordinal_type = typename local_matrix_type2::ordinal_type;
396  using memory_space = typename local_matrix_type2::memory_space;
397  using block_indices_view_type = Kokkos::View<local_ordinal_type*, memory_space>;
398 
399  const local_matrix_type2 A;
402 
403  public:
404  KOKKOS_INLINE_FUNCTION
405  Comparator(const local_matrix_type2& A_, local_ordinal_type bsize_, local_ordinal_type brlid_, block_indices_view_type ghosted_point_to_block_)
406  : A(A_)
407  , offset(A_.graph.row_map(bsize_ * brlid_))
408  , ghosted_point_to_block(ghosted_point_to_block_) {}
409 
410  KOKKOS_INLINE_FUNCTION
411  bool operator()(size_t x, size_t y) const {
412  return ghosted_point_to_block(A.graph.entries(offset + x)) < ghosted_point_to_block(A.graph.entries(offset + y));
413  }
414  };
415 
417 
418  KOKKOS_INLINE_FUNCTION
421  }
422 };
423 
434 template <class local_matrix_type,
435  class functor_type,
436  class... remaining_functor_types>
438  private:
439  using scalar_type = typename local_matrix_type::value_type;
440  using local_ordinal_type = typename local_matrix_type::ordinal_type;
441  using memory_space = typename local_matrix_type::memory_space;
442  using results_view = Kokkos::View<DecisionType*, memory_space>;
443  using block_indices_view_type = Kokkos::View<local_ordinal_type*, memory_space>;
444  using permutation_type = Kokkos::View<local_ordinal_type*, memory_space>;
445 
446  using rowptr_type = typename local_matrix_type::row_map_type::non_const_type;
447  using ATS = Kokkos::ArithTraits<local_ordinal_type>;
448 
449  local_matrix_type A;
455 
456  functor_type functor;
457 
460 
461  VectorCountingFunctor<local_matrix_type, remaining_functor_types...> remainingFunctors;
462 
463  std::vector<std::string> functorNames;
464 
465  public:
466  VectorCountingFunctor(local_matrix_type& A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view& results_, rowptr_type& filtered_rowptr_, rowptr_type& graph_rowptr_, functor_type& functor_, remaining_functor_types&... remainingFunctors_)
467  : A(A_)
468  , blockSize(blockSize_)
469  , ghosted_point_to_block(ghosted_point_to_block_)
470  , results(results_)
471  , filtered_rowptr(filtered_rowptr_)
472  , graph_rowptr(graph_rowptr_)
473  , functor(functor_)
475  , remainingFunctors(A_, blockSize_, ghosted_point_to_block_, results_, filtered_rowptr_, graph_rowptr_, remainingFunctors_...) {
476  permutation = permutation_type("permutation", A.nnz());
477 #ifdef MUELU_COALESCE_DROP_DEBUG
478  std::string mangledFunctorName = typeid(decltype(functor)).name();
479  int status = 0;
480  char* demangledFunctorName = 0;
481  demangledFunctorName = abi::__cxa_demangle(mangledFunctorName.c_str(), 0, 0, &status);
482  functorName = demangledFunctorName;
483 #endif
484  }
485 
486  KOKKOS_INLINE_FUNCTION
487  void join(Kokkos::pair<local_ordinal_type, local_ordinal_type>& dest, const Kokkos::pair<local_ordinal_type, local_ordinal_type>& src) const {
488  dest.first += src.first;
489  dest.second += src.second;
490  }
491 
492  KOKKOS_INLINE_FUNCTION
493  void operatorRow(const local_ordinal_type rlid) const {
494  functor(rlid);
495  remainingFunctors.operatorRow(rlid);
496  }
497 
498  KOKKOS_INLINE_FUNCTION
499  void operator()(const local_ordinal_type brlid, Kokkos::pair<local_ordinal_type, local_ordinal_type>& nnz, const bool& final) const {
500  auto nnz_filtered = &nnz.first;
501  auto nnz_graph = &nnz.second;
502 
503 #ifdef MUELU_COALESCE_DROP_DEBUG
504  Kokkos::printf("\nStarting on block row %d\n", brlid);
505 #endif
506  for (local_ordinal_type rlid = blockSize * brlid; rlid < blockSize * (brlid + 1); ++rlid) {
507 #ifdef MUELU_COALESCE_DROP_DEBUG
508  {
509  Kokkos::printf("\nStarting on row %d\n", rlid);
510 
511  auto row = A.rowConst(rlid);
512 
513  Kokkos::printf("indices: ");
514  for (local_ordinal_type k = 0; k < row.length; ++k) {
515  auto clid = row.colidx(k);
516  Kokkos::printf("%5d ", clid);
517  }
518  Kokkos::printf("\n");
519 
520  Kokkos::printf("values: ");
521  for (local_ordinal_type k = 0; k < row.length; ++k) {
522  auto val = row.value(k);
523  Kokkos::printf("%5f ", val);
524  }
525  Kokkos::printf("\n");
526  }
527 #endif
528 
529  functor(rlid);
530  remainingFunctors.operatorRow(rlid);
531 
532 #ifdef MUELU_COALESCE_DROP_DEBUG
533  {
534  Kokkos::printf("%s\n", functorName.c_str());
535 
536  auto row = A.rowConst(rlid);
537  const size_t offset = A.graph.row_map(rlid);
538 
539  Kokkos::printf("decisions: ");
540  for (local_ordinal_type k = 0; k < row.length; ++k) {
541  Kokkos::printf("%5d ", results(offset + k));
542  }
543  Kokkos::printf("\n");
544  }
545 #endif
546 
547 #ifdef MUELU_COALESCE_DROP_DEBUG
548  Kokkos::printf("Done with row %d\n", rlid);
549 #endif
550 
551  size_t start = A.graph.row_map(rlid);
552  size_t end = A.graph.row_map(rlid + 1);
553  for (size_t i = start; i < end; ++i) {
554  if (results(i) == KEEP) {
555  ++(*nnz_filtered);
556  }
557  }
558  if (final)
559  filtered_rowptr(rlid + 1) = *nnz_filtered;
560  }
561 
562 #ifdef MUELU_COALESCE_DROP_DEBUG
563  Kokkos::printf("Done with block row %d\nGraph indices ", brlid);
564 #endif
565 
566  // column lids for all rows in the block
567  auto block_clids = Kokkos::subview(A.graph.entries, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
568  A.graph.row_map(blockSize * (brlid + 1))));
569  // set up a permutatation index
570  auto block_permutation = Kokkos::subview(permutation, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
571  A.graph.row_map(blockSize * (brlid + 1))));
572  for (size_t i = 0; i < block_permutation.extent(0); ++i)
573  block_permutation(i) = i;
574  // get permuatation for sorted column indices of the entire block
575  auto comparator = comparison.getComparator(brlid);
576  Misc::serialHeapSort(block_permutation, comparator);
577 
578  local_ordinal_type prev_bclid = -1;
579  bool alreadyAdded = false;
580 
581  // loop over all sorted entries in block
582  auto offset = A.graph.row_map(blockSize * brlid);
583  for (size_t i = 0; i < block_permutation.extent(0); ++i) {
584  auto idx = offset + block_permutation(i);
585  auto clid = A.graph.entries(idx);
586  auto bclid = ghosted_point_to_block(clid);
587 
588  // unseen block column index
589  if (bclid > prev_bclid)
590  alreadyAdded = false;
591 
592  // add entry to graph
593  if (!alreadyAdded && (results(idx) == KEEP)) {
594  ++(*nnz_graph);
595  alreadyAdded = true;
596 #ifdef MUELU_COALESCE_DROP_DEBUG
597  Kokkos::printf("%5d ", bclid);
598 #endif
599  }
600  prev_bclid = bclid;
601  }
602 #ifdef MUELU_COALESCE_DROP_DEBUG
603  Kokkos::printf("\n");
604 #endif
605  if (final)
606  graph_rowptr(brlid + 1) = *nnz_graph;
607  }
608 };
609 
610 template <class local_matrix_type,
611  class functor_type>
612 class VectorCountingFunctor<local_matrix_type, functor_type> {
613  private:
614  using scalar_type = typename local_matrix_type::value_type;
615  using local_ordinal_type = typename local_matrix_type::ordinal_type;
616  using memory_space = typename local_matrix_type::memory_space;
617  using results_view = Kokkos::View<DecisionType*, memory_space>;
618  using block_indices_view_type = Kokkos::View<local_ordinal_type*, memory_space>;
619  using permutation_type = Kokkos::View<local_ordinal_type*, memory_space>;
620 
621  using rowptr_type = typename local_matrix_type::row_map_type::non_const_type;
622  using ATS = Kokkos::ArithTraits<local_ordinal_type>;
623 
624  local_matrix_type A;
630 
632  functor_type functor;
633 
634  std::vector<std::string> functorNames;
635 
638 
639  public:
640  VectorCountingFunctor(local_matrix_type& A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view& results_, rowptr_type& filtered_rowptr_, rowptr_type& graph_rowptr_, functor_type& functor_)
641  : A(A_)
642  , blockSize(blockSize_)
643  , ghosted_point_to_block(ghosted_point_to_block_)
644  , results(results_)
645  , filtered_rowptr(filtered_rowptr_)
646  , graph_rowptr(graph_rowptr_)
647  , functor(functor_)
649  permutation = permutation_type("permutation", A.nnz());
650 #ifdef MUELU_COALESCE_DROP_DEBUG
651  std::string mangledFunctorName = typeid(decltype(functor)).name();
652  int status = 0;
653  char* demangledFunctorName = 0;
654  demangledFunctorName = abi::__cxa_demangle(mangledFunctorName.c_str(), 0, 0, &status);
655  functorName = demangledFunctorName;
656 #endif
657  }
658 
659  KOKKOS_INLINE_FUNCTION
660  void join(Kokkos::pair<local_ordinal_type, local_ordinal_type>& dest, const Kokkos::pair<local_ordinal_type, local_ordinal_type>& src) const {
661  dest.first += src.first;
662  dest.second += src.second;
663  }
664 
665  KOKKOS_INLINE_FUNCTION
666  void operatorRow(const local_ordinal_type rlid) const {
667  functor(rlid);
668  }
669 
670  KOKKOS_INLINE_FUNCTION
671  void operator()(const local_ordinal_type brlid, Kokkos::pair<local_ordinal_type, local_ordinal_type>& nnz, const bool& final) const {
672  auto nnz_filtered = &nnz.first;
673  auto nnz_graph = &nnz.second;
674 
675 #ifdef MUELU_COALESCE_DROP_DEBUG
676  Kokkos::printf("\nStarting on block row %d\n", brlid);
677 #endif
678  for (local_ordinal_type rlid = blockSize * brlid; rlid < blockSize * (brlid + 1); ++rlid) {
679 #ifdef MUELU_COALESCE_DROP_DEBUG
680  {
681  Kokkos::printf("\nStarting on row %d\n", rlid);
682 
683  auto row = A.rowConst(rlid);
684 
685  Kokkos::printf("indices: ");
686  for (local_ordinal_type k = 0; k < row.length; ++k) {
687  auto clid = row.colidx(k);
688  Kokkos::printf("%5d ", clid);
689  }
690  Kokkos::printf("\n");
691 
692  Kokkos::printf("values: ");
693  for (local_ordinal_type k = 0; k < row.length; ++k) {
694  auto val = row.value(k);
695  Kokkos::printf("%5f ", val);
696  }
697  Kokkos::printf("\n");
698  }
699 #endif
700 
701  functor(rlid);
702 
703 #ifdef MUELU_COALESCE_DROP_DEBUG
704  {
705  Kokkos::printf("%s\n", functorName.c_str());
706 
707  auto row = A.rowConst(rlid);
708  const size_t offset = A.graph.row_map(rlid);
709 
710  Kokkos::printf("decisions: ");
711  for (local_ordinal_type k = 0; k < row.length; ++k) {
712  Kokkos::printf("%5d ", results(offset + k));
713  }
714  Kokkos::printf("\n");
715  }
716 #endif
717 
718 #ifdef MUELU_COALESCE_DROP_DEBUG
719  Kokkos::printf("Done with row %d\n", rlid);
720 #endif
721 
722  size_t start = A.graph.row_map(rlid);
723  size_t end = A.graph.row_map(rlid + 1);
724  for (size_t i = start; i < end; ++i) {
725  if (results(i) == KEEP) {
726  ++(*nnz_filtered);
727  }
728  }
729  if (final)
730  filtered_rowptr(rlid + 1) = *nnz_filtered;
731  }
732 
733 #ifdef MUELU_COALESCE_DROP_DEBUG
734  Kokkos::printf("Done with block row %d\nGraph indices ", brlid);
735 #endif
736 
737  // column lids for all rows in the block
738  auto block_clids = Kokkos::subview(A.graph.entries, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
739  A.graph.row_map(blockSize * (brlid + 1))));
740  // set up a permutation index
741  auto block_permutation = Kokkos::subview(permutation, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
742  A.graph.row_map(blockSize * (brlid + 1))));
743  for (size_t i = 0; i < block_permutation.extent(0); ++i)
744  block_permutation(i) = i;
745  // get permutation for sorted column indices of the entire block
746  auto comparator = comparison.getComparator(brlid);
747  Misc::serialHeapSort(block_permutation, comparator);
748 
749  local_ordinal_type prev_bclid = -1;
750  bool alreadyAdded = false;
751 
752  // loop over all sorted entries in block
753  auto offset = A.graph.row_map(blockSize * brlid);
754  for (size_t i = 0; i < block_permutation.extent(0); ++i) {
755  auto idx = offset + block_permutation(i);
756  auto clid = A.graph.entries(idx);
757  auto bclid = ghosted_point_to_block(clid);
758 
759  // unseen block column index
760  if (bclid > prev_bclid)
761  alreadyAdded = false;
762 
763  // add entry to graph
764  if (!alreadyAdded && (results(idx) == KEEP)) {
765  ++(*nnz_graph);
766  alreadyAdded = true;
767 #ifdef MUELU_COALESCE_DROP_DEBUG
768  Kokkos::printf("%5d ", bclid);
769 #endif
770  }
771  prev_bclid = bclid;
772  }
773 #ifdef MUELU_COALESCE_DROP_DEBUG
774  Kokkos::printf("\n");
775 #endif
776  if (final)
777  graph_rowptr(brlid + 1) = *nnz_graph;
778  }
779 };
780 
788 template <class local_matrix_type, bool lumping, bool reuse>
790  private:
791  using scalar_type = typename local_matrix_type::value_type;
792  using local_ordinal_type = typename local_matrix_type::ordinal_type;
793  using local_graph_type = typename local_matrix_type::staticcrsgraph_type;
794  using memory_space = typename local_matrix_type::memory_space;
795  using results_view = Kokkos::View<DecisionType*, memory_space>;
796  using ATS = Kokkos::ArithTraits<scalar_type>;
797  using OTS = Kokkos::ArithTraits<local_ordinal_type>;
798  using block_indices_view_type = Kokkos::View<local_ordinal_type*, memory_space>;
799  using permutation_type = Kokkos::View<local_ordinal_type*, memory_space>;
800  using magnitudeType = typename ATS::magnitudeType;
801 
802  local_matrix_type A;
806  local_matrix_type filteredA;
809  const scalar_type zero = ATS::zero();
810  const scalar_type one = ATS::one();
811 
814 
815  public:
816  VectorFillFunctor(local_matrix_type& A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view& results_, local_matrix_type& filteredA_, local_graph_type& graph_, magnitudeType dirichletThreshold_)
817  : A(A_)
818  , blockSize(blockSize_)
819  , ghosted_point_to_block(ghosted_point_to_block_)
820  , results(results_)
821  , filteredA(filteredA_)
822  , graph(graph_)
823  , dirichletThreshold(dirichletThreshold_)
825  permutation = permutation_type("permutation", A.nnz());
826  }
827 
828  KOKKOS_INLINE_FUNCTION
829  void operator()(const local_ordinal_type brlid) const {
830  for (local_ordinal_type rlid = blockSize * brlid; rlid < blockSize * (brlid + 1); ++rlid) {
831  auto rowA = A.row(rlid);
832  size_t row_start = A.graph.row_map(rlid);
833  auto rowFilteredA = filteredA.row(rlid);
834  local_ordinal_type j = 0;
835  scalar_type diagCorrection = zero;
836  local_ordinal_type diagOffset = -1;
837  for (local_ordinal_type k = 0; k < rowA.length; ++k) {
838  if constexpr (lumping) {
839  local_ordinal_type clid = rowA.colidx(k);
840  if (rlid == clid) {
841  diagOffset = j;
842  }
843  }
844  if (results(row_start + k) == KEEP) {
845  rowFilteredA.colidx(j) = rowA.colidx(k);
846  rowFilteredA.value(j) = rowA.value(k);
847  ++j;
848  } else if constexpr (lumping) {
849  diagCorrection += rowA.value(k);
850  if constexpr (reuse) {
851  rowFilteredA.colidx(j) = rowA.colidx(k);
852  rowFilteredA.value(j) = zero;
853  ++j;
854  }
855  } else if constexpr (reuse) {
856  rowFilteredA.colidx(j) = rowA.colidx(k);
857  rowFilteredA.value(j) = zero;
858  ++j;
859  }
860  }
861  if constexpr (lumping) {
862  rowFilteredA.value(diagOffset) += diagCorrection;
863  if ((dirichletThreshold >= 0.0) && (ATS::real(rowFilteredA.value(diagOffset)) <= dirichletThreshold))
864  rowFilteredA.value(diagOffset) = one;
865  }
866  }
867 
868  // column lids for all rows in the block
869  auto block_clids = Kokkos::subview(A.graph.entries, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
870  A.graph.row_map(blockSize * (brlid + 1))));
871  // set up a permuatation index
872  auto block_permutation = Kokkos::subview(permutation, Kokkos::make_pair(A.graph.row_map(blockSize * brlid),
873  A.graph.row_map(blockSize * (brlid + 1))));
874  for (size_t i = 0; i < block_permutation.extent(0); ++i)
875  block_permutation(i) = i;
876  // get permutation for sorted column indices of the entire block
877  auto comparator = comparison.getComparator(brlid);
878  Misc::serialHeapSort(block_permutation, comparator);
879 
880  local_ordinal_type prev_bclid = -1;
881  bool alreadyAdded = false;
882  local_ordinal_type j = graph.row_map(brlid);
883 
884  // loop over all sorted entries in block
885  auto offset = A.graph.row_map(blockSize * brlid);
886  for (size_t i = 0; i < block_permutation.extent(0); ++i) {
887  auto idx = offset + block_permutation(i);
888  auto clid = A.graph.entries(idx);
889  auto bclid = ghosted_point_to_block(clid);
890 
891  // unseen block column index
892  if (bclid > prev_bclid)
893  alreadyAdded = false;
894 
895  // add entry to graph
896  if (!alreadyAdded && (results(idx) == KEEP)) {
897  graph.entries(j) = bclid;
898  ++j;
899  alreadyAdded = true;
900  }
901  prev_bclid = bclid;
902  }
903  }
904 };
905 
906 } // namespace MueLu::MatrixConstruction
907 
908 #endif
typename local_matrix_type::ordinal_type local_ordinal_type
KOKKOS_INLINE_FUNCTION bool operator()(size_t x, size_t y) const
Kokkos::ArithTraits< local_ordinal_type > OTS
typename local_matrix_type::memory_space memory_space
Kokkos::View< DecisionType *, memory_space > results_view
typename local_matrix_type::row_map_type::non_const_type rowptr_type
KOKKOS_INLINE_FUNCTION void operatorRow(const local_ordinal_type rlid) const
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type rlid, local_ordinal_type &nnz, const bool &final) const
KOKKOS_INLINE_FUNCTION void operatorRow(const local_ordinal_type rlid) const
KOKKOS_INLINE_FUNCTION comparator_type getComparator(local_ordinal_type brlid) const
PointwiseCountingFunctor(local_matrix_type &A_, results_view &results_, rowptr_type &rowptr_, functor_type &functor_)
PointwiseCountingFunctor< local_matrix_type, remaining_functor_types...> remainingFunctors
KOKKOS_INLINE_FUNCTION void join(Kokkos::pair< local_ordinal_type, local_ordinal_type > &dest, const Kokkos::pair< local_ordinal_type, local_ordinal_type > &src) const
Kokkos::View< DecisionType *, memory_space > results_view
typename local_matrix_type::ordinal_type local_ordinal_type
VectorCountingFunctor< local_matrix_type, remaining_functor_types...> remainingFunctors
PointwiseCountingFunctor(local_matrix_type &A_, results_view &results_, rowptr_type &rowptr_, bool firstFunctor_, functor_type &functor_, remaining_functor_types &...remainingFunctors_)
Kokkos::View< local_ordinal_type *, memory_space > permutation_type
Kokkos::View< local_ordinal_type *, memory_space > block_indices_view_type
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type brlid, Kokkos::pair< local_ordinal_type, local_ordinal_type > &nnz, const bool &final) const
typename local_matrix_type::memory_space memory_space
BlockRowComparison< local_matrix_type > comparison
Kokkos::View< local_ordinal_type *, memory_space > block_indices_view_type
typename local_matrix_type::value_type scalar_type
Kokkos::View< DecisionType *, memory_space > results_view
Kokkos::ArithTraits< local_ordinal_type > ATS
Kokkos::View< local_ordinal_type *, memory_space > block_indices_view_type
typename local_matrix_type::value_type scalar_type
typename local_matrix_type::memory_space memory_space
typename local_matrix_type::row_map_type::non_const_type rowptr_type
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type rlid) const
KOKKOS_INLINE_FUNCTION void serialHeapSort(view_type &v, comparator_type comparator)
VectorCountingFunctor(local_matrix_type &A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view &results_, rowptr_type &filtered_rowptr_, rowptr_type &graph_rowptr_, functor_type &functor_, remaining_functor_types &...remainingFunctors_)
Functor that executes a sequence of sub-functors on each block of rows.
typename local_matrix_type::ordinal_type local_ordinal_type
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type rlid) const
PointwiseCountingFunctor(local_matrix_type &A_, results_view &results_, rowptr_type &rowptr_, functor_type &functor_, remaining_functor_types &...remainingFunctors_)
VectorFillFunctor(local_matrix_type &A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view &results_, local_matrix_type &filteredA_, local_graph_type &graph_, magnitudeType dirichletThreshold_)
PointwiseCountingFunctor(local_matrix_type &A_, results_view &results_, rowptr_type &rowptr_, bool firstFunctor_, functor_type &functor_)
Kokkos::View< local_ordinal_type *, memory_space > permutation_type
Kokkos::View< DecisionType *, memory_space > results_view
Functor that fills the filtered matrix while reusing the graph of the matrix before dropping...
typename local_matrix_type::ordinal_type local_ordinal_type
typename local_matrix_type::ordinal_type local_ordinal_type
PointwiseFillReuseFunctor(local_matrix_type &A_, results_view &results_, local_matrix_type &filteredA_, local_graph_type &graph_, magnitudeType dirichletThreshold_)
PointwiseFillNoReuseFunctor(local_matrix_type &A_, results_view &results_, local_matrix_type &filteredA_, magnitudeType dirichletThreshold_)
Functor that executes a sequence of sub-functors on each row for a problem with blockSize == 1...
Kokkos::View< DecisionType *, memory_space > results_view
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type brlid, Kokkos::pair< local_ordinal_type, local_ordinal_type > &nnz, const bool &final) const
KOKKOS_INLINE_FUNCTION Comparator(const local_matrix_type2 &A_, local_ordinal_type bsize_, local_ordinal_type brlid_, block_indices_view_type ghosted_point_to_block_)
void start()
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type rlid, local_ordinal_type &nnz, const bool &final) const
typename local_matrix_type::memory_space memory_space
VectorCountingFunctor(local_matrix_type &A_, local_ordinal_type blockSize_, block_indices_view_type ghosted_point_to_block_, results_view &results_, rowptr_type &filtered_rowptr_, rowptr_type &graph_rowptr_, functor_type &functor_)
Functor does not reuse the graph of the matrix for a problem with blockSize == 1. ...
BlockRowComparison< local_matrix_type > comparison
KOKKOS_INLINE_FUNCTION void operator()(const local_ordinal_type brlid) const
BlockRowComparison(local_matrix_type &A_, local_ordinal_type bsize_, block_indices_view_type ghosted_point_to_block_)
TransListIter end
Kokkos::View< local_ordinal_type *, memory_space > block_indices_view_type
typename local_matrix_type::ordinal_type local_ordinal_type
KOKKOS_INLINE_FUNCTION void join(Kokkos::pair< local_ordinal_type, local_ordinal_type > &dest, const Kokkos::pair< local_ordinal_type, local_ordinal_type > &src) const
typename local_matrix_type::staticcrsgraph_type local_graph_type