MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_LocalQR.hpp
Go to the documentation of this file.
1#ifndef MUELU_LOCALQR_HPP
2#define MUELU_LOCALQR_HPP
3
4#include <Kokkos_Core.hpp>
5#include <KokkosKernels_ArithTraits.hpp>
6#include "Xpetra_ConfigDefs.hpp"
7
8#include "KokkosBlas1_set.hpp"
9#include "KokkosBatched_ApplyQ_Decl.hpp"
10#include "KokkosBatched_SetIdentity_Decl.hpp"
11#include "KokkosBatched_SetIdentity_Impl.hpp"
12#include "Kokkos_DualView.hpp"
13#include "Kokkos_Pair.hpp"
14#include "KokkosBatched_QR_Decl.hpp"
15
16namespace MueLu::LocalQR {
17
18template <class LocalOrdinal, class View>
20 public:
22 : view_(view) {}
23
24 KOKKOS_INLINE_FUNCTION
25 void operator()(const LocalOrdinal& i, LocalOrdinal& vmax) const {
26 if (vmax < view_(i))
27 vmax = view_(i);
28 }
29
30 KOKKOS_INLINE_FUNCTION
31 void join(LocalOrdinal& dst, const LocalOrdinal& src) const {
32 if (dst < src) {
33 dst = src;
34 }
35 }
36
37 KOKKOS_INLINE_FUNCTION
38 void init(LocalOrdinal& dst) const {
39 dst = 0;
40 }
41
42 private:
43 View view_;
44};
45
46// local QR decomposition
47template <class LOType, class GOType, class SCType, class DeviceType, class NspType, class aggRowsType, class maxAggDofSizeType, class agg2RowMapLOType, class statusType, class rowsType, class rowsAuxType, class colsAuxType, class valsAuxType>
49 private:
50 typedef LOType LO;
51 typedef GOType GO;
52 typedef SCType SC;
53
54 typedef typename DeviceType::execution_space execution_space;
55 typedef typename KokkosKernels::ArithTraits<SC>::val_type impl_SC;
56 typedef KokkosKernels::ArithTraits<impl_SC> impl_ATS;
57 typedef typename impl_ATS::magnitudeType Magnitude;
58
59 public:
60 typedef Kokkos::View<impl_SC**, typename execution_space::scratch_memory_space, Kokkos::MemoryUnmanaged> shared_matrix;
61 typedef Kokkos::View<impl_SC*, typename execution_space::scratch_memory_space, Kokkos::MemoryUnmanaged> shared_vector;
62
63 private:
64 NspType fineNS;
65 NspType coarseNS;
66 aggRowsType aggRows;
67 maxAggDofSizeType maxAggDofSize; //< maximum number of dofs in aggregate (max size of aggregate * numDofsPerNode)
68 agg2RowMapLOType agg2RowMapLO;
69 statusType statusAtomic;
70 rowsType rows;
71 rowsAuxType rowsAux;
72 colsAuxType colsAux;
73 valsAuxType valsAux;
76
77 public:
78 LocalQRDecompFunctor(NspType fineNS_, NspType coarseNS_, aggRowsType aggRows_, maxAggDofSizeType maxAggDofSize_, agg2RowMapLOType agg2RowMapLO_, statusType statusAtomic_, rowsType rows_, rowsAuxType rowsAux_, colsAuxType colsAux_, valsAuxType valsAux_, bool doQRStep_, int scratchLevel_)
79 : fineNS(fineNS_)
80 , coarseNS(coarseNS_)
81 , aggRows(aggRows_)
82 , maxAggDofSize(maxAggDofSize_)
83 , agg2RowMapLO(agg2RowMapLO_)
84 , statusAtomic(statusAtomic_)
85 , rows(rows_)
86 , rowsAux(rowsAux_)
87 , colsAux(colsAux_)
88 , valsAux(valsAux_)
89 , doQRStep(doQRStep_)
90 , scratchLevel(scratchLevel_) {}
91
92 KOKKOS_INLINE_FUNCTION
93 void operator()(const typename Kokkos::TeamPolicy<execution_space>::member_type& thread, size_t& nnz) const {
94 auto agg = thread.league_rank();
95
96 const auto aggOffset = aggRows(agg);
97 // size of aggregate: number of DOFs in aggregate
98 const auto aggSize = aggRows(agg + 1) - aggOffset;
99
100 const impl_SC one = impl_ATS::one();
101 const impl_SC zero = impl_ATS::zero();
102
103 const int m = aggSize;
104 const int n = fineNS.extent(1);
105
106 // calculate row offset for coarse nullspace
107 Xpetra::global_size_t offset = agg * n;
108
109 if (doQRStep) {
110 // A is m x n
111 // Q is m x m
112 // R is m x n
113
114 // A (initially) gets overwritten with R in QR
115 shared_matrix r(thread.team_scratch(scratchLevel), m, n);
116 // Q
117 shared_matrix q(thread.team_scratch(scratchLevel), m, m);
118
119 // Extract the piece of the nullspace corresponding to the aggregate
120 for (int j = 0; j < n; j++)
121 for (int k = 0; k < m; k++)
122 r(k, j) = fineNS(agg2RowMapLO(aggOffset + k), j);
123
124 if (m >= n) {
125 // tau has size n
126 shared_vector tau(thread.team_scratch(scratchLevel), n);
127
128 // work has size m
129 shared_vector work(thread.team_scratch(scratchLevel), m);
130
131 // Calculate QR. After this call R will be in the upper triangular part of r.
132 // Q is in encoded in the strictly lower triangular part of r and tau. We will
133 // need to explicitly form Q as a matrix below.
134 KokkosBatched::SerialQR<KokkosBlas::Algo::QR::Unblocked>::invoke(r, tau, work);
135
136 // Initialize Q to an identity matrix
137 KokkosBatched::SerialSetIdentity::invoke(q);
138
139 // Form Q as a matrix but multiplying against the identity
140 KokkosBatched::SerialApplyQ<KokkosBatched::Side::Left, KokkosBlas::Trans::NoTranspose, KokkosBlas::Algo::ApplyQ::Unblocked>::invoke(r, tau, q, work);
141
142 // Build coarse nullspace using the upper triangular part of R
143 for (int j = 0; j < n; j++) {
144 for (int k = 0; k < n; k++)
145 coarseNS(offset + k, j) = (k <= j) ? r(k, j) : zero;
146 }
147
148 } else {
149 // Special handling for m < n (i.e. single node aggregates in structural mechanics)
150
151 // The local QR decomposition is not possible in the "overconstrained"
152 // case (i.e. number of columns in qr > number of rowsAux), which
153 // corresponds to #DOFs in Aggregate < n. For usual problems this
154 // is only possible for single node aggregates in structural mechanics.
155 // (Similar problems may arise in discontinuous Galerkin problems...)
156 // We bypass the QR decomposition and use an identity block in the
157 // tentative prolongator for the single node aggregate and transfer the
158 // corresponding fine level null space information 1-to-1 to the coarse
159 // level null space part.
160
161 // NOTE: The resulting tentative prolongation operator has
162 // (m*DofsPerNode-n) zero columns leading to a singular
163 // coarse level operator A. To deal with that one has the following
164 // options:
165 // - Use the "RepairMainDiagonal" flag in the RAPFactory (default:
166 // false) to add some identity block to the diagonal of the zero rowsAux
167 // in the coarse level operator A, such that standard level smoothers
168 // can be used again.
169 // - Use special (projection-based) level smoothers, which can deal
170 // with singular matrices (very application specific)
171 // - Adapt the code below to avoid zero columns. However, we do not
172 // support a variable number of DOFs per node in MueLu/Xpetra which
173 // makes the implementation really hard.
174 //
175 // FIXME: do we need to check for singularity here somehow? Zero
176 // columns would be easy but linear dependency would require proper QR.
177
178 // R = extended (by adding identity rowsAux) qr
179 for (int j = 0; j < n; j++)
180 for (int k = 0; k < n; k++)
181 if (k < m)
182 coarseNS(offset + k, j) = r(k, j);
183 else
184 coarseNS(offset + k, j) = (k == j ? one : zero);
185
186 // Q = I (rectangular)
187 for (int i = 0; i < m; i++)
188 for (int j = 0; j < n; j++)
189 q(i, j) = (j == i ? one : zero);
190 }
191
192 // Process each row in the local Q factor and fill helper arrays to assemble P
193 for (int j = 0; j < m; j++) {
194 LO localRow = agg2RowMapLO(aggRows(agg) + j);
195 size_t rowStart = rowsAux(localRow);
196 size_t lnnz = 0;
197 for (int k = 0; k < n; k++) {
198 // skip zeros
199 if (q(j, k) != zero) {
200 colsAux(rowStart + lnnz) = offset + k;
201 valsAux(rowStart + lnnz) = q(j, k);
202 lnnz++;
203 }
204 }
205 rows(localRow + 1) = lnnz;
206 nnz += lnnz;
207 }
208 } else {
210 // "no-QR" option //
212 // Local Q factor is just the fine nullspace support over the current aggregate.
213 // Local R factor is the identity.
214 // TODO I have not implemented any special handling for aggregates that are too
215 // TODO small to locally support the nullspace, as is done in the standard QR
216 // TODO case above.
217
218 for (int j = 0; j < m; j++) {
219 LO localRow = agg2RowMapLO(aggRows(agg) + j);
220 size_t rowStart = rowsAux(localRow);
221 size_t lnnz = 0;
222 for (int k = 0; k < n; k++) {
223 const impl_SC qr_jk = fineNS(localRow, k);
224 // skip zeros
225 if (qr_jk != zero) {
226 colsAux(rowStart + lnnz) = offset + k;
227 valsAux(rowStart + lnnz) = qr_jk;
228 lnnz++;
229 }
230 }
231 rows(localRow + 1) = lnnz;
232 nnz += lnnz;
233 }
234
235 for (int j = 0; j < n; j++)
236 coarseNS(offset + j, j) = one;
237 }
238 }
239};
240
241} // namespace MueLu::LocalQR
242
243#endif
MueLu::DefaultLocalOrdinal LocalOrdinal
Kokkos::View< impl_SC **, typename execution_space::scratch_memory_space, Kokkos::MemoryUnmanaged > shared_matrix
LocalQRDecompFunctor(NspType fineNS_, NspType coarseNS_, aggRowsType aggRows_, maxAggDofSizeType maxAggDofSize_, agg2RowMapLOType agg2RowMapLO_, statusType statusAtomic_, rowsType rows_, rowsAuxType rowsAux_, colsAuxType colsAux_, valsAuxType valsAux_, bool doQRStep_, int scratchLevel_)
KokkosKernels::ArithTraits< impl_SC > impl_ATS
DeviceType::execution_space execution_space
Kokkos::View< impl_SC *, typename execution_space::scratch_memory_space, Kokkos::MemoryUnmanaged > shared_vector
KokkosKernels::ArithTraits< SC >::val_type impl_SC
KOKKOS_INLINE_FUNCTION void operator()(const typename Kokkos::TeamPolicy< execution_space >::member_type &thread, size_t &nnz) const
KOKKOS_INLINE_FUNCTION void join(LocalOrdinal &dst, const LocalOrdinal &src) const
KOKKOS_INLINE_FUNCTION void init(LocalOrdinal &dst) const
KOKKOS_INLINE_FUNCTION void operator()(const LocalOrdinal &i, LocalOrdinal &vmax) const