MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_UtilitiesBase_def.hpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// MueLu: A package for multigrid based preconditioning
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact
39// Jonathan Hu (jhu@sandia.gov)
40// Andrey Prokopenko (aprokop@sandia.gov)
41// Ray Tuminaro (rstumin@sandia.gov)
42//
43// ***********************************************************************
44//
45// @HEADER
46#ifndef MUELU_UTILITIESBASE_DEF_HPP
47#define MUELU_UTILITIESBASE_DEF_HPP
48
49#include "MueLu_ConfigDefs.hpp"
50
52
53#include <Kokkos_Core.hpp>
54#include <KokkosSparse_CrsMatrix.hpp>
55#include <KokkosSparse_getDiagCopy.hpp>
56
57#include <Xpetra_BlockedVector.hpp>
58#include <Xpetra_BlockedMap.hpp>
59#include <Xpetra_BlockedMultiVector.hpp>
60#include <Xpetra_ExportFactory.hpp>
61
62#include <Xpetra_Import.hpp>
63#include <Xpetra_ImportFactory.hpp>
64#include <Xpetra_MatrixMatrix.hpp>
65#include <Xpetra_CrsGraph.hpp>
66#include <Xpetra_CrsGraphFactory.hpp>
67#include <Xpetra_CrsMatrixWrap.hpp>
68#include <Xpetra_StridedMap.hpp>
69
70#include "MueLu_Exceptions.hpp"
71
72#include <KokkosKernels_Handle.hpp>
73#include <KokkosGraph_RCM.hpp>
74
75
76namespace MueLu {
77
78 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
79 RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
81 Crs2Op(RCP<Xpetra::CrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > Op) {
82 if (Op.is_null())
83 return Teuchos::null;
84 return rcp(new CrsMatrixWrap(Op));
85 }
86
87 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
88 RCP<Xpetra::CrsMatrixWrap<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
90 GetThresholdedMatrix(const RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& Ain, const Scalar threshold, const bool keepDiagonal, const GlobalOrdinal expectedNNZperRow) {
91
92 RCP<const Map> rowmap = Ain->getRowMap();
93 RCP<const Map> colmap = Ain->getColMap();
94 RCP<CrsMatrixWrap> Aout = rcp(new CrsMatrixWrap(rowmap, expectedNNZperRow <= 0 ? Ain->getGlobalMaxNumRowEntries() : expectedNNZperRow));
95 // loop over local rows
96 for(size_t row=0; row<Ain->getLocalNumRows(); row++)
97 {
98 size_t nnz = Ain->getNumEntriesInLocalRow(row);
99
100 Teuchos::ArrayView<const LocalOrdinal> indices;
101 Teuchos::ArrayView<const Scalar> vals;
102 Ain->getLocalRowView(row, indices, vals);
103
104 TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::as<size_t>(indices.size()) != nnz, Exceptions::RuntimeError, "MueLu::ThresholdAFilterFactory::Build: number of nonzeros not equal to number of indices? Error.");
105
106 Teuchos::ArrayRCP<GlobalOrdinal> indout(indices.size(),Teuchos::ScalarTraits<GlobalOrdinal>::zero());
107 Teuchos::ArrayRCP<Scalar> valout(indices.size(),Teuchos::ScalarTraits<Scalar>::zero());
108 size_t nNonzeros = 0;
109 if (keepDiagonal) {
110 GlobalOrdinal glbRow = rowmap->getGlobalElement(row);
111 LocalOrdinal lclColIdx = colmap->getLocalElement(glbRow);
112 for(size_t i=0; i<(size_t)indices.size(); i++) {
113 if(Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > Teuchos::ScalarTraits<Scalar>::magnitude(threshold) || indices[i]==lclColIdx) {
114 indout[nNonzeros] = colmap->getGlobalElement(indices[i]); // LID -> GID (column)
115 valout[nNonzeros] = vals[i];
116 nNonzeros++;
117 }
118 }
119 } else
120 for(size_t i=0; i<(size_t)indices.size(); i++) {
121 if(Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > Teuchos::ScalarTraits<Scalar>::magnitude(threshold)) {
122 indout[nNonzeros] = colmap->getGlobalElement(indices[i]); // LID -> GID (column)
123 valout[nNonzeros] = vals[i];
124 nNonzeros++;
125 }
126 }
127
128 indout.resize(nNonzeros);
129 valout.resize(nNonzeros);
130
131 Aout->insertGlobalValues(Ain->getRowMap()->getGlobalElement(row), indout.view(0,indout.size()), valout.view(0,valout.size()));
132 }
133 Aout->fillComplete(Ain->getDomainMap(), Ain->getRangeMap());
134
135 return Aout;
136 }
137
138
139 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
140 RCP<Xpetra::CrsGraph<LocalOrdinal, GlobalOrdinal, Node> >
142 GetThresholdedGraph(const RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A, const Magnitude threshold, const GlobalOrdinal expectedNNZperRow) {
143
144 using STS = Teuchos::ScalarTraits<Scalar>;
145 RCP<CrsGraph> sparsityPattern = CrsGraphFactory::Build(A->getRowMap(), expectedNNZperRow <= 0 ? A->getGlobalMaxNumRowEntries() : expectedNNZperRow);
146
147 RCP<Vector> diag = GetMatrixOverlappedDiagonal(*A);
148 ArrayRCP<const Scalar> D = diag->getData(0);
150 for(size_t row=0; row<A->getLocalNumRows(); row++)
151 {
152 ArrayView<const LocalOrdinal> indices;
153 ArrayView<const Scalar> vals;
154 A->getLocalRowView(row, indices, vals);
155
156 GlobalOrdinal globalRow = A->getRowMap()->getGlobalElement(row);
157 LocalOrdinal col = A->getColMap()->getLocalElement(globalRow);
158
159 const Scalar Dk = STS::magnitude(D[col]) > 0.0 ? STS::magnitude(D[col]) : 1.0;
160 Array<GlobalOrdinal> indicesNew;
161
162 for(size_t i=0; i<size_t(indices.size()); i++)
163 // keep diagonal per default
164 if(col == indices[i] || STS::magnitude(STS::squareroot(Dk)*vals[i]*STS::squareroot(Dk)) > STS::magnitude(threshold))
165 indicesNew.append(A->getColMap()->getGlobalElement(indices[i]));
166
167 sparsityPattern->insertGlobalIndices(globalRow, ArrayView<const GlobalOrdinal>(indicesNew.data(), indicesNew.length()));
168 }
169 sparsityPattern->fillComplete();
170
171 return sparsityPattern;
172 }
173
174
175 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
176 Teuchos::ArrayRCP<Scalar>
178 GetMatrixDiagonal_arcp(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> & A) {
179 size_t numRows = A.getRowMap()->getLocalNumElements();
180 Teuchos::ArrayRCP<Scalar> diag(numRows);
181 Teuchos::ArrayView<const LocalOrdinal> cols;
182 Teuchos::ArrayView<const Scalar> vals;
183 for (size_t i = 0; i < numRows; ++i) {
184 A.getLocalRowView(i, cols, vals);
185 LocalOrdinal j = 0;
186 for (; j < cols.size(); ++j) {
187 if (Teuchos::as<size_t>(cols[j]) == i) {
188 diag[i] = vals[j];
189 break;
190 }
191 }
192 if (j == cols.size()) {
193 // Diagonal entry is absent
194 diag[i] = Teuchos::ScalarTraits<Scalar>::zero();
195 }
196 }
197 return diag;
198 }
199
201 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
202 Teuchos::RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
204 GetMatrixDiagonal(const Matrix& A) {
205 const auto rowMap = A.getRowMap();
206 auto diag = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(rowMap, true);
207
208 A.getLocalDiagCopy(*diag);
209
210 return diag;
212
213
214 // template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
215 // RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
216 // UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
217 // GetMatrixDiagonalInverse(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> & A, Magnitude tol, Scalar valReplacement) {
218 // Teuchos::TimeMonitor MM = *Teuchos::TimeMonitor::getNewTimer("UtilitiesBase::GetMatrixDiagonalInverse");
219
220 // RCP<const Map> rowMap = A.getRowMap();
221 // RCP<Vector> diag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(rowMap,true);
222
223 // A.getLocalDiagCopy(*diag);
224
225 // RCP<Vector> inv = MueLu::UtilitiesBase<Scalar,LocalOrdinal,GlobalOrdinal,Node>::GetInverse(diag, tol, valReplacement);
226
227 // return inv;
228 // }
229
230
231 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
232 Teuchos::RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
234 GetMatrixDiagonalInverse(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A,
235 typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol,
236 Scalar valReplacement,
237 const bool doLumped) {
238 Teuchos::TimeMonitor MM = *Teuchos::TimeMonitor::getNewTimer("Utilities::GetMatrixDiagonalInverse");
239
240 RCP<const BlockedCrsMatrix> bA = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpFromRef(A));
241 if (!bA.is_null()) {
242 RCP<const Map> rowMap = A.getRowMap();
243 RCP<Vector> diag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(rowMap,true);
244 A.getLocalDiagCopy(*diag);
245 RCP<Vector> inv = MueLu::UtilitiesBase<Scalar,LocalOrdinal,GlobalOrdinal,Node>::GetInverse(diag, tol, valReplacement);
246 return inv;
247 }
248
249 // Some useful type definitions
250 using local_matrix_type = typename Matrix::local_matrix_type;
251 // using local_graph_type = typename local_matrix_type::staticcrsgraph_type;
252 using value_type = typename local_matrix_type::value_type;
253 using values_type = typename local_matrix_type::values_type;
254 using scalar_type = typename values_type::non_const_value_type;
255 using ordinal_type = typename local_matrix_type::ordinal_type;
256 using execution_space = typename local_matrix_type::execution_space;
257 // using memory_space = typename local_matrix_type::memory_space;
258 // Be careful with this one, if using Kokkos::ArithTraits<Scalar>
259 // you are likely to run into errors when handling std::complex<>
260 // a good way to work around that is to use the following:
261 // using KAT = Kokkos::ArithTraits<Kokkos::ArithTraits<Scalar>::val_type> >
262 // here we have: value_type = Kokkos::ArithTraits<Scalar>::val_type
263 using KAT = Kokkos::ArithTraits<value_type>;
264
265 // Get/Create distributed objects
266 RCP<const Map> rowMap = A.getRowMap();
267 RCP<Vector> diag = VectorFactory::Build(rowMap,false);
268
269 // Now generate local objects
270 local_matrix_type localMatrix = A.getLocalMatrixDevice();
271 auto diagVals = diag->getDeviceLocalView(Xpetra::Access::ReadWrite);
272
273 ordinal_type numRows = localMatrix.graph.numRows();
274
275 scalar_type valReplacement_dev = valReplacement;
277 // Note: 2019-11-21, LBV
278 // This could be implemented with a TeamPolicy over the rows
279 // and a TeamVectorRange over the entries in a row if performance
280 // becomes more important here.
281 if (!doLumped)
282 Kokkos::parallel_for("Utilities::GetMatrixDiagonalInverse",
283 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
284 KOKKOS_LAMBDA(const ordinal_type rowIdx) {
285 bool foundDiagEntry = false;
286 auto myRow = localMatrix.rowConst(rowIdx);
287 for(ordinal_type entryIdx = 0; entryIdx < myRow.length; ++entryIdx) {
288 if(myRow.colidx(entryIdx) == rowIdx) {
289 foundDiagEntry = true;
290 if(KAT::magnitude(myRow.value(entryIdx)) > KAT::magnitude(tol)) {
291 diagVals(rowIdx, 0) = KAT::one() / myRow.value(entryIdx);
292 } else {
293 diagVals(rowIdx, 0) = valReplacement_dev;
294 }
295 break;
296 }
297 }
298
299 if(!foundDiagEntry) {diagVals(rowIdx, 0) = KAT::zero();}
300 });
301 else
302 Kokkos::parallel_for("Utilities::GetMatrixDiagonalInverse",
303 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
304 KOKKOS_LAMBDA(const ordinal_type rowIdx) {
305 auto myRow = localMatrix.rowConst(rowIdx);
306 for(ordinal_type entryIdx = 0; entryIdx < myRow.length; ++entryIdx) {
307 diagVals(rowIdx, 0) += KAT::magnitude(myRow.value(entryIdx));
308 }
309 if(KAT::magnitude(diagVals(rowIdx, 0)) > KAT::magnitude(tol))
310 diagVals(rowIdx, 0) = KAT::one() / diagVals(rowIdx, 0);
311 else
312 diagVals(rowIdx, 0) = valReplacement_dev;
313
314 });
315
316 return diag;
317 }
318
319
320 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
321 Teuchos::RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
323 GetLumpedMatrixDiagonal(Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> const & A, const bool doReciprocal,
324 Magnitude tol,
325 Scalar valReplacement,
326 const bool replaceSingleEntryRowWithZero,
327 const bool useAverageAbsDiagVal) {
328
329 typedef Teuchos::ScalarTraits<Scalar> TST;
330
331 RCP<Vector> diag = Teuchos::null;
332 const Scalar zero = TST::zero();
333 const Scalar one = TST::one();
334 const Scalar two = one + one;
335
336 Teuchos::RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
337
338 RCP<const Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > bA =
339 Teuchos::rcp_dynamic_cast<const Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(rcpA);
340 if(bA == Teuchos::null) {
341 RCP<const Map> rowMap = rcpA->getRowMap();
342 diag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(rowMap,true);
343
344 if(rowMap->lib() == Xpetra::UnderlyingLib::UseTpetra) {
345 // Implement using Kokkos
346 using local_vector_type = typename Vector::dual_view_type::t_dev_um;
347 using local_matrix_type = typename Matrix::local_matrix_type;
348 using execution_space = typename local_vector_type::execution_space;
349 // using rowmap_type = typename local_matrix_type::row_map_type;
350 // using entries_type = typename local_matrix_type::index_type;
351 using values_type = typename local_matrix_type::values_type;
352 using scalar_type = typename values_type::non_const_value_type;
353 using mag_type = typename Kokkos::ArithTraits<scalar_type>::mag_type;
354 using KAT_S = typename Kokkos::ArithTraits<scalar_type>;
355 using KAT_M = typename Kokkos::ArithTraits<mag_type>;
356 using size_type = typename local_matrix_type::non_const_size_type;
357
358 local_vector_type diag_dev = diag->getDeviceLocalView(Xpetra::Access::OverwriteAll);
359 local_matrix_type local_mat_dev = rcpA->getLocalMatrixDevice();
360 Kokkos::RangePolicy<execution_space, int> my_policy(0, static_cast<int>(diag_dev.extent(0)));
361 scalar_type valReplacement_dev = valReplacement;
362
363 if(doReciprocal) {
364 Kokkos::View<int*, execution_space> nnzPerRow("nnz per rows", diag_dev.extent(0));
365 Kokkos::View<scalar_type*, execution_space> regSum("regSum", diag_dev.extent(0));
366 Kokkos::View<mag_type, execution_space> avgAbsDiagVal_dev("avgAbsDiagVal");
367 Kokkos::View<int, execution_space> numDiagsEqualToOne_dev("numDiagsEqualToOne");
368
369 Kokkos::parallel_for("GetLumpedMatrixDiagonal", my_policy,
370 KOKKOS_LAMBDA(const int rowIdx) {
371 diag_dev(rowIdx, 0) = KAT_S::zero();
372 for(size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
373 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
374 ++entryIdx) {
375 regSum(rowIdx) += local_mat_dev.values(entryIdx);
376 if(KAT_M::zero() < KAT_S::abs(local_mat_dev.values(entryIdx))) {
377 ++nnzPerRow(rowIdx);
378 }
379 diag_dev(rowIdx, 0) += KAT_S::abs(local_mat_dev.values(entryIdx));
380 if(rowIdx == local_mat_dev.graph.entries(entryIdx)) {
381 Kokkos::atomic_add(&avgAbsDiagVal_dev(), KAT_S::abs(local_mat_dev.values(entryIdx)));
382 }
383 }
384
385 if(nnzPerRow(rowIdx) == 1 && KAT_S::magnitude(diag_dev(rowIdx, 0)) == KAT_M::one()) {
386 Kokkos::atomic_add(&numDiagsEqualToOne_dev(), 1);
387 }
388 });
389
390 typename Kokkos::View<mag_type, execution_space>::HostMirror avgAbsDiagVal = Kokkos::create_mirror_view(avgAbsDiagVal_dev);
391 Kokkos::deep_copy(avgAbsDiagVal, avgAbsDiagVal_dev);
392 int numDiagsEqualToOne;
393 Kokkos::deep_copy(numDiagsEqualToOne, numDiagsEqualToOne_dev);
394
395 if (useAverageAbsDiagVal) {
396 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal()-numDiagsEqualToOne) / (rowMap->getLocalNumElements()-numDiagsEqualToOne);
398
399 Kokkos::parallel_for("ComputeLumpedDiagonalInverse", my_policy,
400 KOKKOS_LAMBDA(const int rowIdx) {
401 if (replaceSingleEntryRowWithZero && nnzPerRow(rowIdx) <= 1) {
402 diag_dev(rowIdx, 0) = KAT_S::zero();
403 } else if((diag_dev(rowIdx, 0) != KAT_S::zero()) && (KAT_S::magnitude(diag_dev(rowIdx, 0)) < KAT_S::magnitude(2*regSum(rowIdx)))) {
404 diag_dev(rowIdx, 0) = KAT_S::one() / KAT_S::magnitude(2*regSum(rowIdx));
405 } else {
406 if(KAT_S::magnitude(diag_dev(rowIdx, 0)) > tol) {
407 diag_dev(rowIdx, 0) = KAT_S::one() / diag_dev(rowIdx, 0);
408 } else {
409 diag_dev(rowIdx, 0) = valReplacement_dev;
410 }
411 }
412 });
414 } else {
415 Kokkos::parallel_for("GetLumpedMatrixDiagonal", my_policy,
416 KOKKOS_LAMBDA(const int rowIdx) {
417 diag_dev(rowIdx, 0) = KAT_S::zero();
418 for(size_type entryIdx = local_mat_dev.graph.row_map(rowIdx);
419 entryIdx < local_mat_dev.graph.row_map(rowIdx + 1);
420 ++entryIdx) {
421 diag_dev(rowIdx, 0) += KAT_S::magnitude(local_mat_dev.values(entryIdx));
422 }
423 });
424 }
425 } else {
426 // Implement using Teuchos
427 ArrayRCP<Scalar> diagVals = diag->getDataNonConst(0);
428 Teuchos::Array<Scalar> regSum(diag->getLocalLength());
429 Teuchos::ArrayView<const LocalOrdinal> cols;
430 Teuchos::ArrayView<const Scalar> vals;
431
432 std::vector<int> nnzPerRow(rowMap->getLocalNumElements());
433
434 //FIXME 2021-10-22 JHU If this is called with doReciprocal=false, what should the correct behavior be? Currently,
435 //FIXME 2021-10-22 JHU the diagonal entry is set to be the sum of the absolute values of the row entries.
436
437 const Magnitude zeroMagn = TST::magnitude(zero);
438 Magnitude avgAbsDiagVal = TST::magnitude(zero);
439 int numDiagsEqualToOne = 0;
440 for (size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
441 nnzPerRow[i] = 0;
442 rcpA->getLocalRowView(i, cols, vals);
443 diagVals[i] = zero;
444 for (LocalOrdinal j = 0; j < cols.size(); ++j) {
445 regSum[i] += vals[j];
446 const Magnitude rowEntryMagn = TST::magnitude(vals[j]);
447 if (rowEntryMagn > zeroMagn)
448 nnzPerRow[i]++;
449 diagVals[i] += rowEntryMagn;
450 if (static_cast<size_t>(cols[j]) == i)
451 avgAbsDiagVal += rowEntryMagn;
453 if (nnzPerRow[i] == 1 && TST::magnitude(diagVals[i])==1.)
454 numDiagsEqualToOne++;
455 }
456 if (useAverageAbsDiagVal)
457 tol = TST::magnitude(100 * Teuchos::ScalarTraits<Scalar>::eps()) * (avgAbsDiagVal-numDiagsEqualToOne) / (rowMap->getLocalNumElements()-numDiagsEqualToOne);
458 if (doReciprocal) {
459 for (size_t i = 0; i < rowMap->getLocalNumElements(); ++i) {
460 if (replaceSingleEntryRowWithZero && nnzPerRow[i] <= static_cast<int>(1))
461 diagVals[i] = zero;
462 else if ((diagVals[i] != zero) && (TST::magnitude(diagVals[i]) < TST::magnitude(two*regSum[i])))
463 diagVals[i] = one / TST::magnitude((two*regSum[i]));
464 else {
465 if(TST::magnitude(diagVals[i]) > tol)
466 diagVals[i] = one / diagVals[i];
467 else {
468 diagVals[i] = valReplacement;
469 }
470 }
471 }
472 }
473 }
474 } else {
475 TEUCHOS_TEST_FOR_EXCEPTION(doReciprocal, Xpetra::Exceptions::RuntimeError,
476 "UtilitiesBase::GetLumpedMatrixDiagonal(): extracting reciprocal of diagonal of a blocked matrix is not supported");
477 diag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(bA->getRangeMapExtractor()->getFullMap(),true);
478
479 for (size_t row = 0; row < bA->Rows(); ++row) {
480 for (size_t col = 0; col < bA->Cols(); ++col) {
481 if (!bA->getMatrix(row,col).is_null()) {
482 // if we are in Thyra mode, but the block (row,row) is again a blocked operator, we have to use (pseudo) Xpetra-style GIDs with offset!
483 bool bThyraMode = bA->getRangeMapExtractor()->getThyraMode() && (Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >(bA->getMatrix(row,col)) == Teuchos::null);
484 RCP<Vector> ddtemp = bA->getRangeMapExtractor()->ExtractVector(diag,row,bThyraMode);
485 RCP<const Vector> dd = GetLumpedMatrixDiagonal(*(bA->getMatrix(row,col)));
486 ddtemp->update(Teuchos::as<Scalar>(1.0),*dd,Teuchos::as<Scalar>(1.0));
487 bA->getRangeMapExtractor()->InsertVector(ddtemp,row,diag,bThyraMode);
488 }
490 }
491
492 }
493
494 return diag;
495 }
496
497
498 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
499 Teuchos::ArrayRCP<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
501 GetMatrixMaxMinusOffDiagonal(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A) {
502 size_t numRows = A.getRowMap()->getLocalNumElements();
503 Magnitude ZERO = Teuchos::ScalarTraits<Magnitude>::zero();
504 Teuchos::ArrayRCP<Magnitude> maxvec(numRows);
505 Teuchos::ArrayView<const LocalOrdinal> cols;
506 Teuchos::ArrayView<const Scalar> vals;
507 for (size_t i = 0; i < numRows; ++i) {
508 A.getLocalRowView(i, cols, vals);
509 Magnitude mymax = ZERO;
510 for (LocalOrdinal j=0; j < cols.size(); ++j) {
511 if (Teuchos::as<size_t>(cols[j]) != i) {
512 mymax = std::max(mymax,-Teuchos::ScalarTraits<Scalar>::real(vals[j]));
513 }
514 }
515 maxvec[i] = mymax;
516 }
517 return maxvec;
518 }
519
520 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
521 Teuchos::ArrayRCP<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
523 GetMatrixMaxMinusOffDiagonal(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, const Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> &BlockNumber) {
524 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()),std::runtime_error,"GetMatrixMaxMinusOffDiagonal: BlockNumber must match's A's column map.");
525
526 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
527
528 size_t numRows = A.getRowMap()->getLocalNumElements();
529 Magnitude ZERO = Teuchos::ScalarTraits<Magnitude>::zero();
530 Teuchos::ArrayRCP<Magnitude> maxvec(numRows);
531 Teuchos::ArrayView<const LocalOrdinal> cols;
532 Teuchos::ArrayView<const Scalar> vals;
533 for (size_t i = 0; i < numRows; ++i) {
534 A.getLocalRowView(i, cols, vals);
535 Magnitude mymax = ZERO;
536 for (LocalOrdinal j=0; j < cols.size(); ++j) {
537 if (Teuchos::as<size_t>(cols[j]) != i && block_id[i] == block_id[cols[j]]) {
538 mymax = std::max(mymax,-Teuchos::ScalarTraits<Scalar>::real(vals[j]));
539 }
540 }
541 // printf("A(%d,:) row_scale(block) = %6.4e\n",(int)i,mymax);
542
543 maxvec[i] = mymax;
544 }
545 return maxvec;
546 }
547
548
549 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
550 Teuchos::RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
552 GetInverse(Teuchos::RCP<const Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > v, typename Teuchos::ScalarTraits<Scalar>::magnitudeType tol, Scalar valReplacement) {
553
554 RCP<Vector> ret = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(v->getMap(),true);
555
556 // check whether input vector "v" is a BlockedVector
557 RCP<const BlockedVector> bv = Teuchos::rcp_dynamic_cast<const BlockedVector>(v);
558 if(bv.is_null() == false) {
559 RCP<BlockedVector> bret = Teuchos::rcp_dynamic_cast<BlockedVector>(ret);
560 TEUCHOS_TEST_FOR_EXCEPTION(bret.is_null() == true, MueLu::Exceptions::RuntimeError,"MueLu::UtilitiesBase::GetInverse: return vector should be of type BlockedVector");
561 RCP<const BlockedMap> bmap = bv->getBlockedMap();
562 for(size_t r = 0; r < bmap->getNumMaps(); ++r) {
563 RCP<const MultiVector> submvec = bv->getMultiVector(r,bmap->getThyraMode());
564 RCP<const Vector> subvec = submvec->getVector(0);
565 RCP<Vector> subvecinf = MueLu::UtilitiesBase<Scalar,LocalOrdinal,GlobalOrdinal,Node>::GetInverse(subvec,tol,valReplacement);
566 bret->setMultiVector(r, subvecinf, bmap->getThyraMode());
567 }
568 return ret;
569 }
570
571 // v is an {Epetra,Tpetra}Vector: work with the underlying raw data
572 ArrayRCP<Scalar> retVals = ret->getDataNonConst(0);
573 ArrayRCP<const Scalar> inputVals = v->getData(0);
574 for (size_t i = 0; i < v->getMap()->getLocalNumElements(); ++i) {
575 if(Teuchos::ScalarTraits<Scalar>::magnitude(inputVals[i]) > tol)
576 retVals[i] = Teuchos::ScalarTraits<Scalar>::one() / inputVals[i];
577 else
578 retVals[i] = valReplacement;
579 }
580 return ret;
581 }
582
583
584 // template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
585 // RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
586 // UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::
587 // GetMatrixOverlappedDiagonal(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> & A) {
588 // RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
589
590 // // Undo block map (if we have one)
591 // RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
592 // if(!browMap.is_null()) rowMap = browMap->getMap();
593
594 // RCP<Vector> localDiag = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(rowMap);
595 // try {
596 // const CrsMatrixWrap* crsOp = dynamic_cast<const CrsMatrixWrap*>(&A);
597 // if (crsOp == NULL) {
598 // throw Exceptions::RuntimeError("cast to CrsMatrixWrap failed");
599 // }
600 // Teuchos::ArrayRCP<size_t> offsets;
601 // crsOp->getLocalDiagOffsets(offsets);
602 // crsOp->getLocalDiagCopy(*localDiag,offsets());
603 // }
604 // catch (...) {
605 // ArrayRCP<Scalar> localDiagVals = localDiag->getDataNonConst(0);
606 // Teuchos::ArrayRCP<Scalar> diagVals = GetMatrixDiagonal(A);
607 // for (LocalOrdinal i = 0; i < localDiagVals.size(); i++)
608 // localDiagVals[i] = diagVals[i];
609 // localDiagVals = diagVals = null;
610 // }
611
612 // RCP<Vector> diagonal = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(colMap);
613 // RCP< const Xpetra::Import<LocalOrdinal,GlobalOrdinal,Node> > importer;
614 // importer = A.getCrsGraph()->getImporter();
615 // if (importer == Teuchos::null) {
616 // importer = Xpetra::ImportFactory<LocalOrdinal,GlobalOrdinal,Node>::Build(rowMap, colMap);
617 // }
618 // diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
619 // return diagonal;
620 // }
621
622
623 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
624 RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
626 GetMatrixOverlappedDiagonal(const Matrix& A) {
627 // FIXME_KOKKOS
628 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
629 RCP<Vector> localDiag = VectorFactory::Build(rowMap);
630
631 const CrsMatrixWrap* crsOp = dynamic_cast<const CrsMatrixWrap*>(&A);
632 if ((crsOp != NULL) && (rowMap->lib() == Xpetra::UseTpetra)) {
633 Teuchos::ArrayRCP<size_t> offsets;
634 crsOp->getLocalDiagOffsets(offsets);
635 crsOp->getLocalDiagCopy(*localDiag,offsets());
636 }
637 else {
638 auto localDiagVals = localDiag->getDeviceLocalView(Xpetra::Access::ReadWrite);
639 const auto diagVals = GetMatrixDiagonal(A)->getDeviceLocalView(Xpetra::Access::ReadOnly);
640 Kokkos::deep_copy(localDiagVals, diagVals);
641 }
642
643 RCP<Vector> diagonal = VectorFactory::Build(colMap);
644 RCP< const Import> importer;
645 importer = A.getCrsGraph()->getImporter();
646 if (importer == Teuchos::null) {
647 importer = ImportFactory::Build(rowMap, colMap);
648 }
649 diagonal->doImport(*localDiag, *(importer), Xpetra::INSERT);
650
651 return diagonal;
652 }
653
654
655 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
656 RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
658 GetMatrixOverlappedDeletedRowsum(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> & A) {
659 using STS = typename Teuchos::ScalarTraits<SC>;
660
661 // Undo block map (if we have one)
662 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
663 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
664 if(!browMap.is_null()) rowMap = browMap->getMap();
665
666 RCP<Vector> local = Xpetra::VectorFactory<SC,LO,GO,Node>::Build(rowMap);
667 RCP<Vector> ghosted = Xpetra::VectorFactory<SC,LO,GO,Node>::Build(colMap,true);
668 ArrayRCP<SC> localVals = local->getDataNonConst(0);
669
670 for (LO row = 0; row < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++row) {
671 size_t nnz = A.getNumEntriesInLocalRow(row);
672 ArrayView<const LO> indices;
673 ArrayView<const SC> vals;
674 A.getLocalRowView(row, indices, vals);
675
676 SC si = STS::zero();
677
678 for (LO colID = 0; colID < static_cast<LO>(nnz); colID++) {
679 if(indices[colID] != row) {
680 si += vals[colID];
681 }
682 }
683 localVals[row] = si;
684 }
685
686 RCP< const Xpetra::Import<LO,GO,Node> > importer;
687 importer = A.getCrsGraph()->getImporter();
688 if (importer == Teuchos::null) {
689 importer = Xpetra::ImportFactory<LO,GO,Node>::Build(rowMap, colMap);
690 }
691 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
692 return ghosted;
693 }
694
695
696
697 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
698 RCP<Xpetra::Vector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType,LocalOrdinal,GlobalOrdinal,Node> >
700 GetMatrixOverlappedAbsDeletedRowsum(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> & A) {
701 RCP<const Map> rowMap = A.getRowMap(), colMap = A.getColMap();
702 using STS = typename Teuchos::ScalarTraits<Scalar>;
703 using MTS = typename Teuchos::ScalarTraits<Magnitude>;
704 using MT = Magnitude;
705 using RealValuedVector = Xpetra::Vector<MT,LO,GO,Node>;
706
707 // Undo block map (if we have one)
708 RCP<const BlockedMap> browMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(rowMap);
709 if(!browMap.is_null()) rowMap = browMap->getMap();
710
711 RCP<RealValuedVector> local = Xpetra::VectorFactory<MT,LO,GO,Node>::Build(rowMap);
712 RCP<RealValuedVector> ghosted = Xpetra::VectorFactory<MT,LO,GO,Node>::Build(colMap,true);
713 ArrayRCP<MT> localVals = local->getDataNonConst(0);
714
715 for (LO rowIdx = 0; rowIdx < static_cast<LO>(A.getRowMap()->getLocalNumElements()); ++rowIdx) {
716 size_t nnz = A.getNumEntriesInLocalRow(rowIdx);
717 ArrayView<const LO> indices;
718 ArrayView<const SC> vals;
719 A.getLocalRowView(rowIdx, indices, vals);
720
721 MT si = MTS::zero();
722
723 for (LO colID = 0; colID < static_cast<LO>(nnz); ++colID) {
724 if(indices[colID] != rowIdx) {
725 si += STS::magnitude(vals[colID]);
726 }
727 }
728 localVals[rowIdx] = si;
729 }
730
731 RCP< const Xpetra::Import<LO,GO,Node> > importer;
732 importer = A.getCrsGraph()->getImporter();
733 if (importer == Teuchos::null) {
734 importer = Xpetra::ImportFactory<LO,GO,Node>::Build(rowMap, colMap);
735 }
736 ghosted->doImport(*local, *(importer), Xpetra::INSERT);
737 return ghosted;
738 }
739
740
741 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
742 Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
744 ResidualNorm(const Xpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Op, const MultiVector& X, const MultiVector& RHS) {
745 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
746 const size_t numVecs = X.getNumVectors();
747 RCP<MultiVector> RES = Residual(Op, X, RHS);
748 Teuchos::Array<Magnitude> norms(numVecs);
749 RES->norm2(norms);
750 return norms;
751 }
752
753 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
754 Teuchos::Array<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>
756 ResidualNorm(const Xpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Op, const MultiVector& X, const MultiVector& RHS, MultiVector & Resid) {
757 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
758 const size_t numVecs = X.getNumVectors();
759 Residual(Op,X,RHS,Resid);
760 Teuchos::Array<Magnitude> norms(numVecs);
761 Resid.norm2(norms);
762 return norms;
763 }
764
765 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
766 RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
768 Residual(const Xpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Op, const MultiVector& X, const MultiVector& RHS) {
769 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides")
770 const size_t numVecs = X.getNumVectors();
771 // TODO Op.getRangeMap should return a BlockedMap if it is a BlockedCrsOperator
772 RCP<MultiVector> RES = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(RHS.getMap(), numVecs, false); // no need to initialize to zero
773 Op.residual(X,RHS,*RES);
774 return RES;
775 }
776
777
778 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
779 void
781 Residual(const Xpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Op, const MultiVector& X, const MultiVector& RHS, MultiVector & Resid) {
782 TEUCHOS_TEST_FOR_EXCEPTION(X.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of solution vectors != number of right-hand sides");
783 TEUCHOS_TEST_FOR_EXCEPTION(Resid.getNumVectors() != RHS.getNumVectors(), Exceptions::RuntimeError, "Number of residual vectors != number of right-hand sides");
784 Op.residual(X,RHS,Resid);
785 }
786
787
788 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
789 Scalar
791 PowerMethod(const Matrix& A, bool scaleByDiag,
792 LocalOrdinal niters, typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance, bool verbose, unsigned int seed) {
793 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
794 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
795
796 // power iteration
797 RCP<Vector> diagInvVec;
798 if (scaleByDiag) {
799 RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getRowMap());
800 A.getLocalDiagCopy(*diagVec);
801 diagInvVec = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getRowMap());
802 diagInvVec->reciprocal(*diagVec);
803 }
804
805 Scalar lambda = PowerMethod(A, diagInvVec, niters, tolerance, verbose, seed);
806 return lambda;
807 }
808
809
810 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
811 Scalar
813 PowerMethod(const Matrix& A, const RCP<Vector> &diagInvVec,
814 LocalOrdinal niters, typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance, bool verbose, unsigned int seed) {
815 TEUCHOS_TEST_FOR_EXCEPTION(!(A.getRangeMap()->isSameAs(*(A.getDomainMap()))), Exceptions::Incompatible,
816 "Utils::PowerMethod: operator must have domain and range maps that are equivalent.");
817
818 // Create three vectors, fill z with random numbers
819 RCP<Vector> q = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getDomainMap());
820 RCP<Vector> r = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getRangeMap());
821 RCP<Vector> z = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getRangeMap());
822
823 z->setSeed(seed); // seed random number generator
824 z->randomize(true);// use Xpetra implementation: -> same results for Epetra and Tpetra
825
826 Teuchos::Array<Magnitude> norms(1);
827
828 typedef Teuchos::ScalarTraits<Scalar> STS;
829
830 const Scalar zero = STS::zero(), one = STS::one();
831
832 Scalar lambda = zero;
833 Magnitude residual = STS::magnitude(zero);
834
835 // power iteration
836 for (int iter = 0; iter < niters; ++iter) {
837 z->norm2(norms); // Compute 2-norm of z
838 q->update(one/norms[0], *z, zero); // Set q = z / normz
839 A.apply(*q, *z); // Compute z = A*q
840 if (diagInvVec != Teuchos::null)
841 z->elementWiseMultiply(one, *diagInvVec, *z, zero);
842 lambda = q->dot(*z); // Approximate maximum eigenvalue: lamba = dot(q,z)
843
844 if (iter % 100 == 0 || iter + 1 == niters) {
845 r->update(1.0, *z, -lambda, *q, zero); // Compute A*q - lambda*q
846 r->norm2(norms);
847 residual = STS::magnitude(norms[0] / lambda);
848 if (verbose) {
849 std::cout << "Iter = " << iter
850 << " Lambda = " << lambda
851 << " Residual of A*q - lambda*q = " << residual
852 << std::endl;
853 }
854 }
855 if (residual < tolerance)
856 break;
857 }
858 return lambda;
859 }
860
861 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
862 RCP<Teuchos::FancyOStream>
864 MakeFancy(std::ostream& os) {
865 RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(os));
866 return fancy;
867 }
868
869
870 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
871 typename Teuchos::ScalarTraits<Scalar>::magnitudeType
873 Distance2(const Teuchos::Array<Teuchos::ArrayRCP<const Scalar>> &v, LocalOrdinal i0, LocalOrdinal i1) {
874 const size_t numVectors = v.size();
875
876 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
877 for (size_t j = 0; j < numVectors; j++) {
878 d += (v[j][i0] - v[j][i1])*(v[j][i0] - v[j][i1]);
879 }
880 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
881 }
882
883
884 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
885 typename Teuchos::ScalarTraits<Scalar>::magnitudeType
887 Distance2(const Teuchos::ArrayView<double> & weight,const Teuchos::Array<Teuchos::ArrayRCP<const Scalar>> &v, LocalOrdinal i0, LocalOrdinal i1) {
888 const size_t numVectors = v.size();
889 using MT = typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
890
891 Scalar d = Teuchos::ScalarTraits<Scalar>::zero();
892 for (size_t j = 0; j < numVectors; j++) {
893 d += Teuchos::as<MT>(weight[j])*(v[j][i0] - v[j][i1])*(v[j][i0] - v[j][i1]);
894 }
895 return Teuchos::ScalarTraits<Scalar>::magnitude(d);
896 }
897
898
899 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
900 Teuchos::ArrayRCP<const bool>
902 DetectDirichletRows(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol, bool count_twos_as_dirichlet) {
903 LocalOrdinal numRows = A.getLocalNumRows();
904 typedef Teuchos::ScalarTraits<Scalar> STS;
905 ArrayRCP<bool> boundaryNodes(numRows, true);
906 if (count_twos_as_dirichlet) {
907 for (LocalOrdinal row = 0; row < numRows; row++) {
908 ArrayView<const LocalOrdinal> indices;
909 ArrayView<const Scalar> vals;
910 A.getLocalRowView(row, indices, vals);
911 size_t nnz = A.getNumEntriesInLocalRow(row);
912 if (nnz > 2) {
913 size_t col;
914 for (col = 0; col < nnz; col++)
915 if ( (indices[col] != row) && STS::magnitude(vals[col]) > tol) {
916 if (!boundaryNodes[row])
917 break;
918 boundaryNodes[row] = false;
919 }
920 if (col == nnz)
921 boundaryNodes[row] = true;
922 }
923 }
924 } else {
925 for (LocalOrdinal row = 0; row < numRows; row++) {
926 ArrayView<const LocalOrdinal> indices;
927 ArrayView<const Scalar> vals;
928 A.getLocalRowView(row, indices, vals);
929 size_t nnz = A.getNumEntriesInLocalRow(row);
930 if (nnz > 1)
931 for (size_t col = 0; col < nnz; col++)
932 if ( (indices[col] != row) && STS::magnitude(vals[col]) > tol) {
933 boundaryNodes[row] = false;
934 break;
935 }
936 }
937 }
938 return boundaryNodes;
939 }
940
941 template <class SC, class LO, class GO, class NO>
942 Kokkos::View<bool*, typename NO::device_type>
944 DetectDirichletRows_kokkos(const Xpetra::Matrix<SC,LO,GO,NO>& A,
945 const typename Teuchos::ScalarTraits<SC>::magnitudeType& tol,
946 const bool count_twos_as_dirichlet) {
947 using impl_scalar_type = typename Kokkos::ArithTraits<SC>::val_type;
948 using ATS = Kokkos::ArithTraits<impl_scalar_type>;
949 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
950 using helpers = Xpetra::Helpers<SC,LO,GO,NO>;
951
952
953 if(helpers::isTpetraBlockCrs(A)) {
954 const Tpetra::BlockCrsMatrix<SC,LO,GO,NO> & Am = helpers::Op2TpetraBlockCrs(A);
955 auto b_graph = Am.getCrsGraph().getLocalGraphDevice();
956 auto b_rowptr = Am.getCrsGraph().getLocalRowPtrsDevice();
957 auto values = Am.getValuesDevice();
958 LO numBlockRows = Am.getLocalNumRows();
959 const LO stride = Am.getBlockSize() * Am.getBlockSize();
960
961 Kokkos::View<bool*, typename NO::device_type> boundaryNodes(Kokkos::ViewAllocateWithoutInitializing("boundaryNodes"), numBlockRows);
962
963 if (count_twos_as_dirichlet)
964 throw Exceptions::RuntimeError("BlockCrs does not support counting twos as Dirichlet");
965
966 Kokkos::parallel_for("MueLu:Utils::DetectDirichletRowsBlockCrs", range_type(0,numBlockRows),
967 KOKKOS_LAMBDA(const LO row) {
968 auto rowView = b_graph.rowConst(row);
969 auto length = rowView.length;
970 LO valstart = b_rowptr[row] * stride;
971
972 boundaryNodes(row) = true;
973 decltype(length) colID =0;
974 for (; colID < length; colID++) {
975 if (rowView.colidx(colID) != row) {
976 LO current = valstart + colID*stride;
977 for(LO k=0; k<stride; k++) {
978 if (ATS::magnitude(values[current+ k]) > tol) {
979 boundaryNodes(row) = false;
980 break;
981 }
982 }
983 }
984 if(boundaryNodes(row) == false)
985 break;
986 }
987 });
988
989 return boundaryNodes;
990 }
991 else {
992 auto localMatrix = A.getLocalMatrixDevice();
993 LO numRows = A.getLocalNumRows();
994 Kokkos::View<bool*, typename NO::device_type> boundaryNodes(Kokkos::ViewAllocateWithoutInitializing("boundaryNodes"), numRows);
995
996 if (count_twos_as_dirichlet)
997 Kokkos::parallel_for("MueLu:Utils::DetectDirichletRows_Twos_As_Dirichlet", range_type(0,numRows),
998 KOKKOS_LAMBDA(const LO row) {
999 auto rowView = localMatrix.row(row);
1000 auto length = rowView.length;
1001
1002 boundaryNodes(row) = true;
1003 if (length > 2) {
1004 decltype(length) colID =0;
1005 for ( ; colID < length; colID++)
1006 if ((rowView.colidx(colID) != row) &&
1007 (ATS::magnitude(rowView.value(colID)) > tol)) {
1008 if (!boundaryNodes(row))
1009 break;
1010 boundaryNodes(row) = false;
1011 }
1012 if (colID == length)
1013 boundaryNodes(row) = true;
1014 }
1015 });
1016 else
1017 Kokkos::parallel_for("MueLu:Utils::DetectDirichletRows", range_type(0,numRows),
1018 KOKKOS_LAMBDA(const LO row) {
1019 auto rowView = localMatrix.row(row);
1020 auto length = rowView.length;
1021
1022 boundaryNodes(row) = true;
1023 for (decltype(length) colID = 0; colID < length; colID++)
1024 if ((rowView.colidx(colID) != row) &&
1025 (ATS::magnitude(rowView.value(colID)) > tol)) {
1026 boundaryNodes(row) = false;
1027 break;
1028 }
1029 });
1030 return boundaryNodes;
1031 }
1032
1033 }
1034
1035
1036 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1037 Teuchos::ArrayRCP<const bool>
1039 DetectDirichletRowsExt(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, bool & bHasZeroDiagonal, const typename Teuchos::ScalarTraits<Scalar>::magnitudeType& tol) {
1040
1041 // assume that there is no zero diagonal in matrix
1042 bHasZeroDiagonal = false;
1043
1044 Teuchos::RCP<Vector> diagVec = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(A.getRowMap());
1045 A.getLocalDiagCopy(*diagVec);
1046 Teuchos::ArrayRCP< const Scalar > diagVecData = diagVec->getData(0);
1047
1048 LocalOrdinal numRows = A.getLocalNumRows();
1049 typedef Teuchos::ScalarTraits<Scalar> STS;
1050 ArrayRCP<bool> boundaryNodes(numRows, false);
1051 for (LocalOrdinal row = 0; row < numRows; row++) {
1052 ArrayView<const LocalOrdinal> indices;
1053 ArrayView<const Scalar> vals;
1054 A.getLocalRowView(row, indices, vals);
1055 size_t nnz = 0; // collect nonzeros in row (excluding the diagonal)
1056 bool bHasDiag = false;
1057 for (decltype(indices.size()) col = 0; col < indices.size(); col++) {
1058 if ( indices[col] != row) {
1059 if (STS::magnitude(vals[col] / STS::magnitude(sqrt(STS::magnitude(diagVecData[row]) * STS::magnitude(diagVecData[col]))) ) > tol) {
1060 nnz++;
1061 }
1062 } else bHasDiag = true; // found a diagonal entry
1063 }
1064 if (bHasDiag == false) bHasZeroDiagonal = true; // we found at least one row without a diagonal
1065 else if(nnz == 0) boundaryNodes[row] = true;
1066 }
1067 return boundaryNodes;
1068 }
1069
1070
1071 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1072 void
1074 FindNonZeros(const Teuchos::ArrayRCP<const Scalar> vals,
1075 Teuchos::ArrayRCP<bool> nonzeros) {
1076 TEUCHOS_ASSERT(vals.size() == nonzeros.size());
1077 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitudeType;
1078 const magnitudeType eps = 2.0*Teuchos::ScalarTraits<magnitudeType>::eps();
1079 for(size_t i=0; i<static_cast<size_t>(vals.size()); i++) {
1080 nonzeros[i] = (Teuchos::ScalarTraits<Scalar>::magnitude(vals[i]) > eps);
1081 }
1082 }
1083
1084 // Find Nonzeros in a device view
1085 template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1086 void
1088 FindNonZeros(const typename Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node>::dual_view_type::t_dev_const_um vals,
1089 Kokkos::View<bool*, typename Node::device_type> nonzeros) {
1090 using ATS = Kokkos::ArithTraits<Scalar>;
1091 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
1092 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1093 TEUCHOS_ASSERT(vals.extent(0) == nonzeros.extent(0));
1094 const typename ATS::magnitudeType eps = 2.0*impl_ATS::eps();
1095
1096 Kokkos::parallel_for("MueLu:Maxwell1::FindNonZeros", range_type(0,vals.extent(0)),
1097 KOKKOS_LAMBDA (const size_t i) {
1098 nonzeros(i) = (impl_ATS::magnitude(vals(i,0)) > eps);
1099 });
1100 }
1101
1102
1103 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1104 void
1106 DetectDirichletColsAndDomains(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A,
1107 const Teuchos::ArrayRCP<bool>& dirichletRows,
1108 Teuchos::ArrayRCP<bool> dirichletCols,
1109 Teuchos::ArrayRCP<bool> dirichletDomain) {
1110 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1111 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > domMap = A .getDomainMap();
1112 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > rowMap = A.getRowMap();
1113 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > colMap = A.getColMap();
1114 TEUCHOS_ASSERT(static_cast<size_t>(dirichletRows.size()) == rowMap->getLocalNumElements());
1115 TEUCHOS_ASSERT(static_cast<size_t>(dirichletCols.size()) == colMap->getLocalNumElements());
1116 TEUCHOS_ASSERT(static_cast<size_t>(dirichletDomain.size()) == domMap->getLocalNumElements());
1117 RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > myColsToZero = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(colMap, 1, /*zeroOut=*/true);
1118 // Find all local column indices that are in Dirichlet rows, record in myColsToZero as 1.0
1119 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1120 if (dirichletRows[i]) {
1121 ArrayView<const LocalOrdinal> indices;
1122 ArrayView<const Scalar> values;
1123 A.getLocalRowView(i,indices,values);
1124 for(size_t j=0; j<static_cast<size_t>(indices.size()); j++)
1125 myColsToZero->replaceLocalValue(indices[j],0,one);
1126 }
1127 }
1128
1129 RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > globalColsToZero;
1130 RCP<const Xpetra::Import<LocalOrdinal,GlobalOrdinal,Node> > importer = A.getCrsGraph()->getImporter();
1131 if (!importer.is_null()) {
1132 globalColsToZero = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(domMap, 1, /*zeroOut=*/true);
1133 // export to domain map
1134 globalColsToZero->doExport(*myColsToZero,*importer,Xpetra::ADD);
1135 // import to column map
1136 myColsToZero->doImport(*globalColsToZero,*importer,Xpetra::INSERT);
1137 }
1138 else
1139 globalColsToZero = myColsToZero;
1140
1141 FindNonZeros(globalColsToZero->getData(0),dirichletDomain);
1142 FindNonZeros(myColsToZero->getData(0),dirichletCols);
1143 }
1144
1145
1146 template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1147 void
1149 DetectDirichletColsAndDomains(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A,
1150 const Kokkos::View<bool*, typename Node::device_type> & dirichletRows,
1151 Kokkos::View<bool*, typename Node::device_type> dirichletCols,
1152 Kokkos::View<bool*, typename Node::device_type> dirichletDomain) {
1153 using ATS = Kokkos::ArithTraits<Scalar>;
1154 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
1155 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1156 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > domMap = A.getDomainMap();
1157 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > rowMap = A.getRowMap();
1158 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > colMap = A.getColMap();
1159 TEUCHOS_ASSERT(dirichletRows.extent(0) == rowMap->getLocalNumElements());
1160 TEUCHOS_ASSERT(dirichletCols.extent(0) == colMap->getLocalNumElements());
1161 TEUCHOS_ASSERT(dirichletDomain.extent(0) == domMap->getLocalNumElements());
1162 RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > myColsToZero = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(colMap, /*zeroOut=*/true);
1163 // Find all local column indices that are in Dirichlet rows, record in myColsToZero as 1.0
1164 auto myColsToZeroView = myColsToZero->getDeviceLocalView(Xpetra::Access::ReadWrite);
1165 auto localMatrix = A.getLocalMatrixDevice();
1166 Kokkos::parallel_for("MueLu:Maxwell1::DetectDirichletCols", range_type(0,rowMap->getLocalNumElements()),
1167 KOKKOS_LAMBDA(const LocalOrdinal row) {
1168 if (dirichletRows(row)) {
1169 auto rowView = localMatrix.row(row);
1170 auto length = rowView.length;
1171
1172 for (decltype(length) colID = 0; colID < length; colID++)
1173 myColsToZeroView(rowView.colidx(colID),0) = impl_ATS::one();
1174 }
1175 });
1176
1177 RCP<Xpetra::Vector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > globalColsToZero;
1178 RCP<const Xpetra::Import<LocalOrdinal,GlobalOrdinal,Node> > importer = A.getCrsGraph()->getImporter();
1179 if (!importer.is_null()) {
1180 globalColsToZero = Xpetra::VectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(domMap, /*zeroOut=*/true);
1181 // export to domain map
1182 globalColsToZero->doExport(*myColsToZero,*importer,Xpetra::ADD);
1183 // import to column map
1184 myColsToZero->doImport(*globalColsToZero,*importer,Xpetra::INSERT);
1185 }
1186 else
1187 globalColsToZero = myColsToZero;
1188 UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::FindNonZeros(globalColsToZero->getDeviceLocalView(Xpetra::Access::ReadOnly),dirichletDomain);
1189 UtilitiesBase<Scalar, LocalOrdinal, GlobalOrdinal, Node>::FindNonZeros(myColsToZero->getDeviceLocalView(Xpetra::Access::ReadOnly),dirichletCols);
1190 }
1191
1192
1193
1194 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1195 void
1197 ApplyRowSumCriterion(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1198 typedef Teuchos::ScalarTraits<Scalar> STS;
1199 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1200 typedef Teuchos::ScalarTraits<MT> MTS;
1201 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node>> rowmap = A.getRowMap();
1202 for (LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1203 size_t nnz = A.getNumEntriesInLocalRow(row);
1204 ArrayView<const LocalOrdinal> indices;
1205 ArrayView<const Scalar> vals;
1206 A.getLocalRowView(row, indices, vals);
1207
1208 Scalar rowsum = STS::zero();
1209 Scalar diagval = STS::zero();
1210
1211 for (LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1212 LocalOrdinal col = indices[colID];
1213 if (row == col)
1214 diagval = vals[colID];
1215 rowsum += vals[colID];
1216 }
1217 // printf("A(%d,:) row_sum(point) = %6.4e\n",row,rowsum);
1218 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1219 //printf("Row %d triggers rowsum\n",(int)row);
1220 dirichletRows[row] = true;
1221 }
1222 }
1223 }
1224
1225 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1226 void
1228 ApplyRowSumCriterion(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, const Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> &BlockNumber, const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol, Teuchos::ArrayRCP<bool>& dirichletRows) {
1229 typedef Teuchos::ScalarTraits<Scalar> STS;
1230 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1231 typedef Teuchos::ScalarTraits<MT> MTS;
1232 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > rowmap = A.getRowMap();
1233
1234 TEUCHOS_TEST_FOR_EXCEPTION(!A.getColMap()->isSameAs(*BlockNumber.getMap()),std::runtime_error,"ApplyRowSumCriterion: BlockNumber must match's A's column map.");
1235
1236 Teuchos::ArrayRCP<const LocalOrdinal> block_id = BlockNumber.getData(0);
1237 for (LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1238 size_t nnz = A.getNumEntriesInLocalRow(row);
1239 ArrayView<const LocalOrdinal> indices;
1240 ArrayView<const Scalar> vals;
1241 A.getLocalRowView(row, indices, vals);
1242
1243 Scalar rowsum = STS::zero();
1244 Scalar diagval = STS::zero();
1245 for (LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1246 LocalOrdinal col = indices[colID];
1247 if (row == col)
1248 diagval = vals[colID];
1249 if(block_id[row] == block_id[col])
1250 rowsum += vals[colID];
1251 }
1252
1253 // printf("A(%d,:) row_sum(block) = %6.4e\n",row,rowsum);
1254 if (rowSumTol < MTS::one() && STS::magnitude(rowsum) > STS::magnitude(diagval) * rowSumTol) {
1255 //printf("Row %d triggers rowsum\n",(int)row);
1256 dirichletRows[row] = true;
1257 }
1258 }
1259 }
1260
1261
1262 // Applies rowsum criterion
1263 template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1264 void
1266 ApplyRowSumCriterion(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A,
1267 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType rowSumTol,
1268 Kokkos::View<bool*, typename Node::device_type> & dirichletRows)
1269 {
1270 typedef Teuchos::ScalarTraits<Scalar> STS;
1271 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node>> rowmap = A.getRowMap();
1272
1273 auto dirichletRowsHost = Kokkos::create_mirror_view(dirichletRows);
1274 Kokkos::deep_copy(dirichletRowsHost, dirichletRows);
1275
1276 for (LocalOrdinal row = 0; row < Teuchos::as<LocalOrdinal>(rowmap->getLocalNumElements()); ++row) {
1277 size_t nnz = A.getNumEntriesInLocalRow(row);
1278 ArrayView<const LocalOrdinal> indices;
1279 ArrayView<const Scalar> vals;
1280 A.getLocalRowView(row, indices, vals);
1281
1282 Scalar rowsum = STS::zero();
1283 Scalar diagval = STS::zero();
1284 for (LocalOrdinal colID = 0; colID < Teuchos::as<LocalOrdinal>(nnz); colID++) {
1285 LocalOrdinal col = indices[colID];
1286 if (row == col)
1287 diagval = vals[colID];
1288 rowsum += vals[colID];
1289 }
1290 if (STS::real(rowsum) > STS::magnitude(diagval) * rowSumTol)
1291 dirichletRowsHost(row) = true;
1292 }
1293
1294 Kokkos::deep_copy(dirichletRows, dirichletRowsHost);
1295 }
1296
1297
1298 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1299 Teuchos::ArrayRCP<const bool>
1301 DetectDirichletCols(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A,
1302 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1303 Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1304 Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1305 Teuchos::RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > domMap = A.getDomainMap();
1306 Teuchos::RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > colMap = A.getColMap();
1307 Teuchos::RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > myColsToZero = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(colMap,1);
1308 myColsToZero->putScalar(zero);
1309 // Find all local column indices that are in Dirichlet rows, record in myColsToZero as 1.0
1310 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1311 if (dirichletRows[i]) {
1312 Teuchos::ArrayView<const LocalOrdinal> indices;
1313 Teuchos::ArrayView<const Scalar> values;
1314 A.getLocalRowView(i,indices,values);
1315 for(size_t j=0; j<static_cast<size_t>(indices.size()); j++)
1316 myColsToZero->replaceLocalValue(indices[j],0,one);
1317 }
1318 }
1319
1320 Teuchos::RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> > globalColsToZero = Xpetra::MultiVectorFactory<Scalar,LocalOrdinal,GlobalOrdinal,Node>::Build(domMap,1);
1321 globalColsToZero->putScalar(zero);
1322 Teuchos::RCP<Xpetra::Export<LocalOrdinal,GlobalOrdinal,Node> > exporter = Xpetra::ExportFactory<LocalOrdinal,GlobalOrdinal,Node>::Build(colMap,domMap);
1323 // export to domain map
1324 globalColsToZero->doExport(*myColsToZero,*exporter,Xpetra::ADD);
1325 // import to column map
1326 myColsToZero->doImport(*globalColsToZero,*exporter,Xpetra::INSERT);
1327 Teuchos::ArrayRCP<const Scalar> myCols = myColsToZero->getData(0);
1328 Teuchos::ArrayRCP<bool> dirichletCols(colMap->getLocalNumElements(), true);
1329 Magnitude eps = Teuchos::ScalarTraits<Magnitude>::eps();
1330 for(size_t i=0; i<colMap->getLocalNumElements(); i++) {
1331 dirichletCols[i] = Teuchos::ScalarTraits<Scalar>::magnitude(myCols[i])>2.0*eps;
1332 }
1333 return dirichletCols;
1334 }
1335
1336
1337 template <class SC, class LO, class GO, class NO>
1338 Kokkos::View<bool*, typename NO::device_type>
1340 DetectDirichletCols(const Xpetra::Matrix<SC,LO,GO,NO>& A,
1341 const Kokkos::View<const bool*, typename NO::device_type>& dirichletRows) {
1342 using ATS = Kokkos::ArithTraits<SC>;
1343 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
1344 using range_type = Kokkos::RangePolicy<LO, typename NO::execution_space>;
1345
1346 SC zero = ATS::zero();
1347
1348 auto localMatrix = A.getLocalMatrixDevice();
1349 LO numRows = A.getLocalNumRows();
1350
1351 Teuchos::RCP<const Xpetra::Map<LO,GO,NO> > domMap = A.getDomainMap();
1352 Teuchos::RCP<const Xpetra::Map<LO,GO,NO> > colMap = A.getColMap();
1353 Teuchos::RCP<Xpetra::MultiVector<SC,LO,GO,NO> > myColsToZero = Xpetra::MultiVectorFactory<SC,LO,GO,NO>::Build(colMap,1);
1354 myColsToZero->putScalar(zero);
1355 auto myColsToZeroView = myColsToZero->getDeviceLocalView(Xpetra::Access::ReadWrite);
1356 // Find all local column indices that are in Dirichlet rows, record in myColsToZero as 1.0
1357 Kokkos::parallel_for("MueLu:Utils::DetectDirichletCols1", range_type(0,numRows),
1358 KOKKOS_LAMBDA(const LO row) {
1359 if (dirichletRows(row)) {
1360 auto rowView = localMatrix.row(row);
1361 auto length = rowView.length;
1362
1363 for (decltype(length) colID = 0; colID < length; colID++)
1364 myColsToZeroView(rowView.colidx(colID),0) = impl_ATS::one();
1365 }
1366 });
1367
1368 Teuchos::RCP<Xpetra::MultiVector<SC,LO,GO,NO> > globalColsToZero = Xpetra::MultiVectorFactory<SC,LO,GO,NO>::Build(domMap,1);
1369 globalColsToZero->putScalar(zero);
1370 Teuchos::RCP<Xpetra::Export<LO,GO,NO> > exporter = Xpetra::ExportFactory<LO,GO,NO>::Build(colMap,domMap);
1371 // export to domain map
1372 globalColsToZero->doExport(*myColsToZero,*exporter,Xpetra::ADD);
1373 // import to column map
1374 myColsToZero->doImport(*globalColsToZero,*exporter,Xpetra::INSERT);
1375
1376 auto myCols = myColsToZero->getDeviceLocalView(Xpetra::Access::ReadOnly);
1377 size_t numColEntries = colMap->getLocalNumElements();
1378 Kokkos::View<bool*, typename NO::device_type> dirichletCols(Kokkos::ViewAllocateWithoutInitializing("dirichletCols"), numColEntries);
1379 const typename ATS::magnitudeType eps = 2.0*ATS::eps();
1380
1381 Kokkos::parallel_for("MueLu:Utils::DetectDirichletCols2", range_type(0,numColEntries),
1382 KOKKOS_LAMBDA (const size_t i) {
1383 dirichletCols(i) = impl_ATS::magnitude(myCols(i,0))>eps;
1384 });
1385 return dirichletCols;
1386 }
1387
1388
1389 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1390 Scalar
1392 Frobenius(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& A, const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>& B) {
1393 // We check only row maps. Column may be different. One would hope that they are the same, as we typically
1394 // calculate frobenius norm of the specified sparsity pattern with an updated matrix from the previous step,
1395 // but matrix addition, even when one is submatrix of the other, changes column map (though change may be as
1396 // simple as couple of elements swapped)
1397 TEUCHOS_TEST_FOR_EXCEPTION(!A.getRowMap()->isSameAs(*B.getRowMap()), Exceptions::Incompatible, "MueLu::CGSolver::Frobenius: row maps are incompatible");
1398 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete() || !B.isFillComplete(), Exceptions::RuntimeError, "Matrices must be fill completed");
1399
1400 const Map& AColMap = *A.getColMap();
1401 const Map& BColMap = *B.getColMap();
1402
1403 Teuchos::ArrayView<const LocalOrdinal> indA, indB;
1404 Teuchos::ArrayView<const Scalar> valA, valB;
1405 size_t nnzA = 0, nnzB = 0;
1406
1407 // We use a simple algorithm
1408 // for each row we fill valBAll array with the values in the corresponding row of B
1409 // as such, it serves as both sorted array and as storage, so we don't need to do a
1410 // tricky problem: "find a value in the row of B corresponding to the specific GID"
1411 // Once we do that, we translate LID of entries of row of A to LID of B, and multiply
1412 // corresponding entries.
1413 // The algorithm should be reasonably cheap, as it does not sort anything, provided
1414 // that getLocalElement and getGlobalElement functions are reasonably effective. It
1415 // *is* possible that the costs are hidden in those functions, but if maps are close
1416 // to linear maps, we should be fine
1417 Teuchos::Array<Scalar> valBAll(BColMap.getLocalNumElements());
1418
1419 LocalOrdinal invalid = Teuchos::OrdinalTraits<LocalOrdinal>::invalid();
1420 Scalar zero = Teuchos::ScalarTraits<Scalar> ::zero(), f = zero, gf;
1421 size_t numRows = A.getLocalNumRows();
1422 for (size_t i = 0; i < numRows; i++) {
1423 A.getLocalRowView(i, indA, valA);
1424 B.getLocalRowView(i, indB, valB);
1425 nnzA = indA.size();
1426 nnzB = indB.size();
1427
1428 // Set up array values
1429 for (size_t j = 0; j < nnzB; j++)
1430 valBAll[indB[j]] = valB[j];
1431
1432 for (size_t j = 0; j < nnzA; j++) {
1433 // The cost of the whole Frobenius dot product function depends on the
1434 // cost of the getLocalElement and getGlobalElement functions here.
1435 LocalOrdinal ind = BColMap.getLocalElement(AColMap.getGlobalElement(indA[j]));
1436 if (ind != invalid)
1437 f += valBAll[ind] * valA[j];
1438 }
1439
1440 // Clean up array values
1441 for (size_t j = 0; j < nnzB; j++)
1442 valBAll[indB[j]] = zero;
1443 }
1444
1445 MueLu_sumAll(AColMap.getComm(), f, gf);
1446
1447 return gf;
1448 }
1449
1450
1451 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1452 void
1455 // Distribute the seeds evenly in [1,maxint-1]. This guarantees nothing
1456 // about where in random number stream we are, but avoids overflow situations
1457 // in parallel when multiplying by a PID. It would be better to use
1458 // a good parallel random number generator.
1459 double one = 1.0;
1460 int maxint = INT_MAX; //= 2^31-1 = 2147483647 for 32-bit integers
1461 int mySeed = Teuchos::as<int>((maxint-1) * (one -(comm.getRank()+1)/(comm.getSize()+one)) );
1462 if (mySeed < 1 || mySeed == maxint) {
1463 std::ostringstream errStr;
1464 errStr << "Error detected with random seed = " << mySeed << ". It should be in the interval [1,2^31-2].";
1465 throw Exceptions::RuntimeError(errStr.str());
1466 }
1467 std::srand(mySeed);
1468 // For Tpetra, we could use Kokkos' random number generator here.
1469 Teuchos::ScalarTraits<Scalar>::seedrandom(mySeed);
1470 // Epetra
1471 // MultiVector::Random() -> Epetra_Util::RandomDouble() -> Epetra_Utils::RandomInt()
1472 // Its own random number generator, based on Seed_. Seed_ is initialized in Epetra_Util constructor with std::rand()
1473 // So our setting std::srand() affects that too
1474 }
1475
1476
1477
1478 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1479 void
1481 FindDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > &A,
1482 std::vector<LocalOrdinal>& dirichletRows, bool count_twos_as_dirichlet) {
1483 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
1484 dirichletRows.resize(0);
1485 for(size_t i=0; i<A->getLocalNumRows(); i++) {
1486 Teuchos::ArrayView<const LocalOrdinal> indices;
1487 Teuchos::ArrayView<const Scalar> values;
1488 A->getLocalRowView(i,indices,values);
1489 int nnz=0;
1490 for (size_t j=0; j<(size_t)indices.size(); j++) {
1491 if (Teuchos::ScalarTraits<Scalar>::magnitude(values[j]) > Teuchos::ScalarTraits<MT>::eps()) {
1492 nnz++;
1493 }
1494 }
1495 if (nnz == 1 || (count_twos_as_dirichlet && nnz == 2)) {
1496 dirichletRows.push_back(i);
1497 }
1498 }
1499 }
1500
1501
1502 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1503 void
1505 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1506 const std::vector<LocalOrdinal>& dirichletRows) {
1507 RCP<const Map> Rmap = A->getRowMap();
1508 RCP<const Map> Cmap = A->getColMap();
1509 Scalar one =Teuchos::ScalarTraits<Scalar>::one();
1510 Scalar zero =Teuchos::ScalarTraits<Scalar>::zero();
1511
1512 for(size_t i=0; i<dirichletRows.size(); i++) {
1513 GlobalOrdinal row_gid = Rmap->getGlobalElement(dirichletRows[i]);
1514
1515 Teuchos::ArrayView<const LocalOrdinal> indices;
1516 Teuchos::ArrayView<const Scalar> values;
1517 A->getLocalRowView(dirichletRows[i],indices,values);
1518 // NOTE: This won't work with fancy node types.
1519 Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
1520 for(size_t j=0; j<(size_t)indices.size(); j++) {
1521 if(Cmap->getGlobalElement(indices[j])==row_gid)
1522 valuesNC[j]=one;
1523 else
1524 valuesNC[j]=zero;
1525 }
1526 }
1527 }
1528
1529 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1530 void
1532 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1533 const Teuchos::ArrayRCP<const bool>& dirichletRows) {
1534 TEUCHOS_ASSERT(A->isFillComplete());
1535 RCP<const Map> domMap = A->getDomainMap();
1536 RCP<const Map> ranMap = A->getRangeMap();
1537 RCP<const Map> Rmap = A->getRowMap();
1538 RCP<const Map> Cmap = A->getColMap();
1539 TEUCHOS_ASSERT(static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1540 const Scalar one = Teuchos::ScalarTraits<Scalar>::one();
1541 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
1542 A->resumeFill();
1543 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1544 if (dirichletRows[i]){
1545 GlobalOrdinal row_gid = Rmap->getGlobalElement(i);
1546
1547 Teuchos::ArrayView<const LocalOrdinal> indices;
1548 Teuchos::ArrayView<const Scalar> values;
1549 A->getLocalRowView(i,indices,values);
1550
1551 Teuchos::ArrayRCP<Scalar> valuesNC(values.size());
1552 for(size_t j=0; j<(size_t)indices.size(); j++) {
1553 if(Cmap->getGlobalElement(indices[j])==row_gid)
1554 valuesNC[j]=one;
1555 else
1556 valuesNC[j]=zero;
1557 }
1558 A->replaceLocalValues(i,indices,valuesNC());
1559 }
1560 }
1561 A->fillComplete(domMap, ranMap);
1562 }
1563
1564
1565 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1566 void
1568 ApplyOAZToMatrixRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1569 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows) {
1570 TEUCHOS_ASSERT(A->isFillComplete());
1571 using ATS = Kokkos::ArithTraits<Scalar>;
1572 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
1573 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1574
1575 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > domMap = A->getDomainMap();
1576 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > ranMap = A->getRangeMap();
1577 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > Rmap = A->getRowMap();
1578 RCP<const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > Cmap = A->getColMap();
1579
1580 TEUCHOS_ASSERT(static_cast<size_t>(dirichletRows.size()) == Rmap->getLocalNumElements());
1581
1582 auto localMatrix = A->getLocalMatrixDevice();
1583 auto localRmap = Rmap->getLocalMap();
1584 auto localCmap = Cmap->getLocalMap();
1585
1586 Kokkos::parallel_for("MueLu::Utils::ApplyOAZ",range_type(0,dirichletRows.extent(0)),
1587 KOKKOS_LAMBDA(const LocalOrdinal row) {
1588 if (dirichletRows(row)){
1589 auto rowView = localMatrix.row(row);
1590 auto length = rowView.length;
1591 auto row_gid = localRmap.getGlobalElement(row);
1592 auto row_lid = localCmap.getLocalElement(row_gid);
1593
1594 for (decltype(length) colID = 0; colID < length; colID++)
1595 if (rowView.colidx(colID) == row_lid)
1596 rowView.value(colID) = impl_ATS::one();
1597 else
1598 rowView.value(colID) = impl_ATS::zero();
1599 }
1600 });
1601 }
1602
1603
1604 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1605 void
1607 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1608 const std::vector<LocalOrdinal>& dirichletRows,
1609 Scalar replaceWith) {
1610 for(size_t i=0; i<dirichletRows.size(); i++) {
1611 Teuchos::ArrayView<const LocalOrdinal> indices;
1612 Teuchos::ArrayView<const Scalar> values;
1613 A->getLocalRowView(dirichletRows[i],indices,values);
1614 // NOTE: This won't work with fancy node types.
1615 Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
1616 for(size_t j=0; j<(size_t)indices.size(); j++)
1617 valuesNC[j]=replaceWith;
1618 }
1619 }
1620
1621
1622 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1623 void
1625 ZeroDirichletRows(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1626 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1627 Scalar replaceWith) {
1628 TEUCHOS_ASSERT(static_cast<size_t>(dirichletRows.size()) == A->getRowMap()->getLocalNumElements());
1629 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1630 if (dirichletRows[i]) {
1631 Teuchos::ArrayView<const LocalOrdinal> indices;
1632 Teuchos::ArrayView<const Scalar> values;
1633 A->getLocalRowView(i,indices,values);
1634 // NOTE: This won't work with fancy node types.
1635 Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
1636 for(size_t j=0; j<(size_t)indices.size(); j++)
1637 valuesNC[j]=replaceWith;
1638 }
1639 }
1640 }
1641
1642
1643 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1644 void
1646 ZeroDirichletRows(Teuchos::RCP<Xpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& X,
1647 const Teuchos::ArrayRCP<const bool>& dirichletRows,
1648 Scalar replaceWith) {
1649 TEUCHOS_ASSERT(static_cast<size_t>(dirichletRows.size()) == X->getMap()->getLocalNumElements());
1650 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1651 if (dirichletRows[i]) {
1652 for(size_t j=0; j<X->getNumVectors(); j++)
1653 X->replaceLocalValue(i,j,replaceWith);
1654 }
1655 }
1656 }
1657
1658
1659 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1660 void
1662 ZeroDirichletRows(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >& A,
1663 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1664 Scalar replaceWith) {
1665 using ATS = Kokkos::ArithTraits<Scalar>;
1666 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1667
1668 typename ATS::val_type impl_replaceWith = replaceWith;
1669
1670 auto localMatrix = A->getLocalMatrixDevice();
1671 LocalOrdinal numRows = A->getLocalNumRows();
1672
1673 Kokkos::parallel_for("MueLu:Utils::ZeroDirichletRows", range_type(0,numRows),
1674 KOKKOS_LAMBDA(const LocalOrdinal row) {
1675 if (dirichletRows(row)) {
1676 auto rowView = localMatrix.row(row);
1677 auto length = rowView.length;
1678 for (decltype(length) colID = 0; colID < length; colID++)
1679 rowView.value(colID) = impl_replaceWith;
1680 }
1681 });
1682 }
1683
1684
1685 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1686 void
1688 ZeroDirichletRows(RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> >& X,
1689 const Kokkos::View<const bool*, typename Node::device_type>& dirichletRows,
1690 Scalar replaceWith) {
1691 using ATS = Kokkos::ArithTraits<Scalar>;
1692 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1693
1694 typename ATS::val_type impl_replaceWith = replaceWith;
1695
1696 auto myCols = X->getDeviceLocalView(Xpetra::Access::ReadWrite);
1697 size_t numVecs = X->getNumVectors();
1698 Kokkos::parallel_for("MueLu:Utils::ZeroDirichletRows_MV", range_type(0,dirichletRows.size()),
1699 KOKKOS_LAMBDA(const size_t i) {
1700 if (dirichletRows(i)) {
1701 for(size_t j=0; j<numVecs; j++)
1702 myCols(i,j) = impl_replaceWith;
1703 }
1704 });
1705 }
1706
1707
1708
1709 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1710 void
1712 ZeroDirichletCols(Teuchos::RCP<Matrix>& A,
1713 const Teuchos::ArrayRCP<const bool>& dirichletCols,
1714 Scalar replaceWith) {
1715 TEUCHOS_ASSERT(static_cast<size_t>(dirichletCols.size()) == A->getColMap()->getLocalNumElements());
1716 for(size_t i=0; i<A->getLocalNumRows(); i++) {
1717 Teuchos::ArrayView<const LocalOrdinal> indices;
1718 Teuchos::ArrayView<const Scalar> values;
1719 A->getLocalRowView(i,indices,values);
1720 // NOTE: This won't work with fancy node types.
1721 Scalar* valuesNC = const_cast<Scalar*>(values.getRawPtr());
1722 for(size_t j=0; j<static_cast<size_t>(indices.size()); j++)
1723 if (dirichletCols[indices[j]])
1724 valuesNC[j] = replaceWith;
1725 }
1726 }
1727
1728
1729 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1730 void
1732 ZeroDirichletCols(RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >& A,
1733 const Kokkos::View<const bool*, typename Node::device_type>& dirichletCols,
1734 Scalar replaceWith) {
1735 using ATS = Kokkos::ArithTraits<Scalar>;
1736 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1737
1738 typename ATS::val_type impl_replaceWith = replaceWith;
1739
1740 auto localMatrix = A->getLocalMatrixDevice();
1741 LocalOrdinal numRows = A->getLocalNumRows();
1742
1743 Kokkos::parallel_for("MueLu:Utils::ZeroDirichletCols", range_type(0,numRows),
1744 KOKKOS_LAMBDA(const LocalOrdinal row) {
1745 auto rowView = localMatrix.row(row);
1746 auto length = rowView.length;
1747 for (decltype(length) colID = 0; colID < length; colID++)
1748 if (dirichletCols(rowView.colidx(colID))) {
1749 rowView.value(colID) = impl_replaceWith;
1750 }
1751 });
1752 }
1753
1754
1755 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1756 void
1758 FindDirichletRowsAndPropagateToCols(Teuchos::RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> > &A,
1759 Teuchos::RCP<Xpetra::Vector<int,LocalOrdinal,GlobalOrdinal,Node> >& isDirichletRow,
1760 Teuchos::RCP<Xpetra::Vector<int,LocalOrdinal,GlobalOrdinal,Node> >& isDirichletCol) {
1761
1762 // Make sure A's RowMap == DomainMap
1763 if(!A->getRowMap()->isSameAs(*A->getDomainMap())) {
1764 throw std::runtime_error("UtilitiesBase::FindDirichletRowsAndPropagateToCols row and domain maps must match.");
1765 }
1766 RCP<const Xpetra::Import<LocalOrdinal,GlobalOrdinal,Node> > importer = A->getCrsGraph()->getImporter();
1767 bool has_import = !importer.is_null();
1768
1769 // Find the Dirichlet rows
1770 std::vector<LocalOrdinal> dirichletRows;
1771 FindDirichletRows(A,dirichletRows);
1772
1773#if 0
1774 printf("[%d] DirichletRow Ids = ",A->getRowMap()->getComm()->getRank());
1775 for(size_t i=0; i<(size_t) dirichletRows.size(); i++)
1776 printf("%d ",dirichletRows[i]);
1777 printf("\n");
1778 fflush(stdout);
1779#endif
1780 // Allocate all as non-Dirichlet
1781 isDirichletRow = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(A->getRowMap(),true);
1782 isDirichletCol = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(A->getColMap(),true);
1783
1784 {
1785 Teuchos::ArrayRCP<int> dr_rcp = isDirichletRow->getDataNonConst(0);
1786 Teuchos::ArrayView<int> dr = dr_rcp();
1787 Teuchos::ArrayRCP<int> dc_rcp = isDirichletCol->getDataNonConst(0);
1788 Teuchos::ArrayView<int> dc = dc_rcp();
1789 for(size_t i=0; i<(size_t) dirichletRows.size(); i++) {
1790 dr[dirichletRows[i]] = 1;
1791 if(!has_import) dc[dirichletRows[i]] = 1;
1792 }
1793 }
1794
1795 if(has_import)
1796 isDirichletCol->doImport(*isDirichletRow,*importer,Xpetra::CombineMode::ADD);
1797
1798 }
1799
1800
1801template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1802RCP<Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> >
1804ReplaceNonZerosWithOnes(const RCP<Matrix> & original) {
1805 using ISC = typename Kokkos::ArithTraits<Scalar>::val_type;
1806 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
1807 using local_matrix_type = typename CrsMatrix::local_matrix_type;
1808 using values_type = typename local_matrix_type::values_type;
1809
1810 const ISC ONE = Kokkos::ArithTraits<ISC>::one();
1811 const ISC ZERO = Kokkos::ArithTraits<ISC>::zero();
1812
1813 // Copy the values array of the old matrix to a new array, replacing all the non-zeros with one
1814 auto localMatrix = original->getLocalMatrixDevice();
1815 TEUCHOS_TEST_FOR_EXCEPTION(!original->hasCrsGraph(),Exceptions::RuntimeError, "ReplaceNonZerosWithOnes: Cannot get CrsGraph");
1816 values_type new_values("values",localMatrix.nnz());
1817
1818 Kokkos::parallel_for("ReplaceNonZerosWithOnes",range_type(0,localMatrix.nnz()),KOKKOS_LAMBDA(const size_t i) {
1819 if (localMatrix.values(i) != ZERO)
1820 new_values(i) = ONE;
1821 else
1822 new_values(i) = ZERO;
1823 });
1824
1825 // Build the new matrix
1826 RCP<Matrix> NewMatrix = Xpetra::MatrixFactory<SC,LO,GO,NO>::Build(original->getCrsGraph(),new_values);
1827 TEUCHOS_TEST_FOR_EXCEPTION(NewMatrix.is_null(),Exceptions::RuntimeError, "ReplaceNonZerosWithOnes: MatrixFactory::Build() did not return matrix");
1828 NewMatrix->fillComplete(original->getDomainMap(),original->getRangeMap());
1829 return NewMatrix;
1830}
1831
1832
1833
1834
1835 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1836 RCP<const Xpetra::BlockedMap<LocalOrdinal,GlobalOrdinal,Node> >
1838 GeneratedBlockedTargetMap(const Xpetra::BlockedMap<LocalOrdinal,GlobalOrdinal,Node> & sourceBlockedMap,
1839 const Xpetra::Import<LocalOrdinal,GlobalOrdinal,Node> & Importer) {
1840 typedef Xpetra::Vector<int,LocalOrdinal,GlobalOrdinal,Node> IntVector;
1841 Xpetra::UnderlyingLib lib = sourceBlockedMap.lib();
1842
1843 // De-stride the map if we have to (might regret this later)
1844 RCP<const Map> fullMap = sourceBlockedMap.getMap();
1845 RCP<const Map> stridedMap = Teuchos::rcp_dynamic_cast<const Xpetra::StridedMap<LocalOrdinal,GlobalOrdinal,Node> >(fullMap);
1846 if(!stridedMap.is_null()) fullMap = stridedMap->getMap();
1847
1848 // Initial sanity checking for map compatibil
1849 const size_t numSubMaps = sourceBlockedMap.getNumMaps();
1850 if(!Importer.getSourceMap()->isCompatible(*fullMap))
1851 throw std::runtime_error("GenerateBlockedTargetMap(): Map compatibility error");
1852
1853 // Build an indicator vector
1854 RCP<IntVector> block_ids = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(fullMap);
1855
1856 for(size_t i=0; i<numSubMaps; i++) {
1857 RCP<const Map> map = sourceBlockedMap.getMap(i);
1858
1859 for(size_t j=0; j<map->getLocalNumElements(); j++) {
1860 LocalOrdinal jj = fullMap->getLocalElement(map->getGlobalElement(j));
1861 block_ids->replaceLocalValue(jj,(int)i);
1862 }
1863 }
1864
1865 // Get the block ids for the new map
1866 RCP<const Map> targetMap = Importer.getTargetMap();
1867 RCP<IntVector> new_block_ids = Xpetra::VectorFactory<int,LocalOrdinal,GlobalOrdinal,Node>::Build(targetMap);
1868 new_block_ids->doImport(*block_ids,Importer,Xpetra::CombineMode::ADD);
1869 Teuchos::ArrayRCP<const int> dataRCP = new_block_ids->getData(0);
1870 Teuchos::ArrayView<const int> data = dataRCP();
1871
1872
1873 // Get the GIDs for each subblock
1874 Teuchos::Array<Teuchos::Array<GlobalOrdinal> > elementsInSubMap(numSubMaps);
1875 for(size_t i=0; i<targetMap->getLocalNumElements(); i++) {
1876 elementsInSubMap[data[i]].push_back(targetMap->getGlobalElement(i));
1877 }
1878
1879 // Generate the new submaps
1880 std::vector<RCP<const Map> > subMaps(numSubMaps);
1881 for(size_t i=0; i<numSubMaps; i++) {
1882 subMaps[i] = Xpetra::MapFactory<LocalOrdinal,GlobalOrdinal,Node>::Build(lib,Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(),elementsInSubMap[i](),targetMap->getIndexBase(),targetMap->getComm());
1883 }
1884
1885 // Build the BlockedMap
1886 return rcp(new BlockedMap(targetMap,subMaps));
1887
1888 }
1889
1890
1891 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1892 bool
1894 MapsAreNested(const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node>& rowMap, const Xpetra::Map<LocalOrdinal,GlobalOrdinal,Node>& colMap) {
1895 ArrayView<const GlobalOrdinal> rowElements = rowMap.getLocalElementList();
1896 ArrayView<const GlobalOrdinal> colElements = colMap.getLocalElementList();
1897
1898 const size_t numElements = rowElements.size();
1899
1900 if (size_t(colElements.size()) < numElements)
1901 return false;
1902
1903 bool goodMap = true;
1904 for (size_t i = 0; i < numElements; i++)
1905 if (rowElements[i] != colElements[i]) {
1906 goodMap = false;
1907 break;
1908 }
1909
1910 return goodMap;
1911 }
1912
1913
1914 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1915 Teuchos::RCP<Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> >
1917 ReverseCuthillMcKee(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> &Op) {
1918 using local_matrix_type = typename Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::local_matrix_type;
1919 using local_graph_type = typename local_matrix_type::staticcrsgraph_type;
1920 using lno_nnz_view_t = typename local_graph_type::entries_type::non_const_type;
1921 using device = typename local_graph_type::device_type;
1922 using execution_space = typename local_matrix_type::execution_space;
1923 using ordinal_type = typename local_matrix_type::ordinal_type;
1924
1925 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
1926
1927 lno_nnz_view_t rcmOrder = KokkosGraph::Experimental::graph_rcm
1928 <device, typename local_graph_type::row_map_type, typename local_graph_type::entries_type, lno_nnz_view_t>
1929 (localGraph.row_map, localGraph.entries);
1930
1931 RCP<Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> > retval =
1932 Xpetra::VectorFactory<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node>::Build(Op.getRowMap());
1933
1934 // Copy out and reorder data
1935 auto view1D = Kokkos::subview(retval->getDeviceLocalView(Xpetra::Access::ReadWrite),Kokkos::ALL (), 0);
1936 Kokkos::parallel_for("Utilities::ReverseCuthillMcKee",
1937 Kokkos::RangePolicy<ordinal_type, execution_space>(0, localGraph.numRows()),
1938 KOKKOS_LAMBDA(const ordinal_type rowIdx) {
1939 view1D(rcmOrder(rowIdx)) = rowIdx;
1940 });
1941 return retval;
1942 }
1943
1944 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1945 Teuchos::RCP<Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> >
1947 CuthillMcKee(const Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node> &Op) {
1948 using local_matrix_type = typename Xpetra::Matrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::local_matrix_type;
1949 using local_graph_type = typename local_matrix_type::staticcrsgraph_type;
1950 using lno_nnz_view_t = typename local_graph_type::entries_type::non_const_type;
1951 using device = typename local_graph_type::device_type;
1952 using execution_space = typename local_matrix_type::execution_space;
1953 using ordinal_type = typename local_matrix_type::ordinal_type;
1954
1955 local_graph_type localGraph = Op.getLocalMatrixDevice().graph;
1956 LocalOrdinal numRows = localGraph.numRows();
1957
1958 lno_nnz_view_t rcmOrder = KokkosGraph::Experimental::graph_rcm
1959 <device, typename local_graph_type::row_map_type, typename local_graph_type::entries_type, lno_nnz_view_t>
1960 (localGraph.row_map, localGraph.entries);
1961
1962 RCP<Xpetra::Vector<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node> > retval =
1963 Xpetra::VectorFactory<LocalOrdinal,LocalOrdinal,GlobalOrdinal,Node>::Build(Op.getRowMap());
1964
1965 // Copy out data
1966 auto view1D = Kokkos::subview(retval->getDeviceLocalView(Xpetra::Access::ReadWrite),Kokkos::ALL (), 0);
1967 // Since KokkosKernels produced RCM, also reverse the order of the view to get CM
1968 Kokkos::parallel_for("Utilities::ReverseCuthillMcKee",
1969 Kokkos::RangePolicy<ordinal_type, execution_space>(0, numRows),
1970 KOKKOS_LAMBDA(const ordinal_type rowIdx) {
1971 view1D(rcmOrder(numRows - 1 - rowIdx)) = rowIdx;
1972 });
1973 return retval;
1974 }
1975
1976
1977} //namespace MueLu
1978
1979#define MUELU_UTILITIESBASE_SHORT
1980#endif // MUELU_UTILITIESBASE_DEF_HPP
1981
1982// LocalWords: LocalOrdinal
#define MueLu_sumAll(rcpComm, in, out)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
MueLu::DefaultNode Node
Exception throws to report incompatible objects (like maps).
Exception throws to report errors in the internal logical of the program.
static void FindDirichletRowsAndPropagateToCols(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletRow, Teuchos::RCP< Xpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > > &isDirichletCol)
static void ZeroDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static RCP< Vector > GetMatrixOverlappedDeletedRowsum(const Matrix &A)
Extract Overlapped Matrix Deleted Rowsum.
Teuchos::ScalarTraits< Scalar >::magnitudeType Magnitude
static Teuchos::RCP< Vector > GetInverse(Teuchos::RCP< const Vector > v, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps() *100, Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero())
Return vector containing inverse of input vector.
static Kokkos::View< bool *, typename NO::device_type > DetectDirichletRows_kokkos(const Matrix &A, const Magnitude &tol=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< SC >::magnitudeType >::zero(), const bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
static RCP< Vector > GetMatrixDiagonalInverse(const Matrix &A, Magnitude tol=Teuchos::ScalarTraits< Scalar >::eps() *100, Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero(), const bool doLumped=false)
Extract Matrix Diagonal.
static Teuchos::ArrayRCP< const bool > DetectDirichletRows(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude &tol=Teuchos::ScalarTraits< Magnitude >::zero(), bool count_twos_as_dirichlet=false)
Detect Dirichlet rows.
static RCP< Xpetra::Vector< LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node > > CuthillMcKee(const Matrix &Op)
static Teuchos::ArrayRCP< Magnitude > GetMatrixMaxMinusOffDiagonal(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A)
Return vector containing: max_{i\not=k}(-a_ik), for each for i in the matrix.
static void ZeroDirichletCols(Teuchos::RCP< Matrix > &A, const Teuchos::ArrayRCP< const bool > &dirichletCols, Scalar replaceWith=Teuchos::ScalarTraits< Scalar >::zero())
static Teuchos::ArrayRCP< Scalar > GetMatrixDiagonal_arcp(const Matrix &A)
Extract Matrix Diagonal.
static RCP< Xpetra::Vector< LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node > > ReverseCuthillMcKee(const Matrix &Op)
static Scalar PowerMethod(const Matrix &A, bool scaleByDiag=true, LocalOrdinal niters=10, Magnitude tolerance=1e-2, bool verbose=false, unsigned int seed=123)
Power method.
static bool MapsAreNested(const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &rowMap, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &colMap)
static void ApplyRowSumCriterion(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Magnitude rowSumTol, Teuchos::ArrayRCP< bool > &dirichletRows)
Apply Rowsum Criterion.
static Teuchos::ScalarTraits< Scalar >::magnitudeType Distance2(const Teuchos::Array< Teuchos::ArrayRCP< const Scalar > > &v, LocalOrdinal i0, LocalOrdinal i1)
Squared distance between two rows in a multivector.
static RCP< CrsMatrixWrap > GetThresholdedMatrix(const RCP< Matrix > &Ain, const Scalar threshold, const bool keepDiagonal=true, const GlobalOrdinal expectedNNZperRow=-1)
Threshold a matrix.
static RCP< const Xpetra::BlockedMap< LocalOrdinal, GlobalOrdinal, Node > > GeneratedBlockedTargetMap(const Xpetra::BlockedMap< LocalOrdinal, GlobalOrdinal, Node > &sourceBlockedMap, const Xpetra::Import< LocalOrdinal, GlobalOrdinal, Node > &Importer)
static Teuchos::ArrayRCP< const bool > DetectDirichletRowsExt(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, bool &bHasZeroDiagonal, const Magnitude &tol=Teuchos::ScalarTraits< Scalar >::zero())
Detect Dirichlet rows (extended version).
static RCP< Vector > GetMatrixOverlappedDiagonal(const Matrix &A)
Extract Overlapped Matrix Diagonal.
static void FindDirichletRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, std::vector< LocalOrdinal > &dirichletRows, bool count_twos_as_dirichlet=false)
static void ApplyOAZToMatrixRows(Teuchos::RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const std::vector< LocalOrdinal > &dirichletRows)
static Teuchos::Array< Magnitude > ResidualNorm(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
static Scalar Frobenius(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &B)
Frobenius inner product of two matrices.
static RCP< Matrix > Crs2Op(RCP< CrsMatrix > Op)
static void SetRandomSeed(const Teuchos::Comm< int > &comm)
Set seed for random number generator.
static RCP< Vector > GetMatrixDiagonal(const Matrix &A)
Extract Matrix Diagonal.
static Teuchos::RCP< Vector > GetLumpedMatrixDiagonal(Matrix const &A, const bool doReciprocal=false, Magnitude tol=Teuchos::ScalarTraits< Scalar >::magnitude(Teuchos::ScalarTraits< Scalar >::zero()), Scalar valReplacement=Teuchos::ScalarTraits< Scalar >::zero(), const bool replaceSingleEntryRowWithZero=false, const bool useAverageAbsDiagVal=false)
Extract Matrix Diagonal of lumped matrix.
static Teuchos::ArrayRCP< const bool > DetectDirichletCols(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Teuchos::ArrayRCP< const bool > &dirichletRows)
Detect Dirichlet columns based on Dirichlet rows.
static RCP< Xpetra::Vector< Magnitude, LocalOrdinal, GlobalOrdinal, Node > > GetMatrixOverlappedAbsDeletedRowsum(const Matrix &A)
static void DetectDirichletColsAndDomains(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Teuchos::ArrayRCP< bool > &dirichletRows, Teuchos::ArrayRCP< bool > dirichletCols, Teuchos::ArrayRCP< bool > dirichletDomain)
Detects Dirichlet columns & domains from a list of Dirichlet rows.
static RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > ReplaceNonZerosWithOnes(const RCP< Matrix > &original)
Creates a copy of a matrix where the non-zero entries are replaced by ones.
static RCP< Teuchos::FancyOStream > MakeFancy(std::ostream &os)
static void FindNonZeros(const Teuchos::ArrayRCP< const Scalar > vals, Teuchos::ArrayRCP< bool > nonzeros)
Find non-zero values in an ArrayRCP Compares the value to 2 * machine epsilon.
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
static RCP< Xpetra::CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > GetThresholdedGraph(const RCP< Matrix > &A, const Magnitude threshold, const GlobalOrdinal expectedNNZperRow=-1)
Threshold a graph.
Namespace for MueLu classes and methods.