MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_CombinePFactory_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_COMBINEPFACTORY_DEF_HPP
11#define MUELU_COMBINEPFACTORY_DEF_HPP
12
13#include <stdlib.h>
14#include <iomanip>
15
16// #include <Teuchos_LAPACK.hpp>
17#include <Teuchos_SerialDenseMatrix.hpp>
18#include <Teuchos_SerialDenseVector.hpp>
19#include <Teuchos_SerialDenseSolver.hpp>
20
21#include <Xpetra_CrsMatrixWrap.hpp>
22#include <Xpetra_ImportFactory.hpp>
23#include <Xpetra_Matrix.hpp>
24#include <Xpetra_MapFactory.hpp>
25#include <Xpetra_MultiVectorFactory.hpp>
26#include <Xpetra_VectorFactory.hpp>
27
28#include <Xpetra_IO.hpp>
29
32
33#include "MueLu_MasterList.hpp"
34#include "MueLu_Monitor.hpp"
35
36namespace MueLu {
37
38template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
40 RCP<ParameterList> validParamList = rcp(new ParameterList());
41 validParamList->setEntry("combine: numBlks", ParameterEntry(1));
42 validParamList->setEntry("combine: useMaxLevels", ParameterEntry(false));
43 validParamList->set<RCP<const FactoryBase>>("A", Teuchos::null, "Generating factory of the matrix A");
44
45 return validParamList;
46}
47
48template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
50 DeclareInput(Level& fineLevel, Level& /* coarseLevel */) const {
51 // Input(fineLevel, "subblock");
52}
53
54template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
56 Level& coarseLevel) const {
57 return BuildP(fineLevel, coarseLevel);
58}
59
60namespace {
61template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
62Teuchos::RCP<Xpetra::CrsMatrixWrap<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
63constructIdentityProlongator(const Teuchos::RCP<const Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>>& map) {
64 using local_matrix_type = typename Xpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_matrix_device_type;
65 using local_graph_type = typename Xpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_graph_device_type;
66 using row_map_type = typename local_matrix_type::row_map_type::non_const_type;
67 using entries_type = typename local_graph_type::entries_type::non_const_type;
68 using values_type = typename local_matrix_type::values_type;
69 using local_scalar_type = typename values_type::value_type;
70
71 LocalOrdinal numLocal = map->getLocalNumElements();
72 row_map_type rowptr("rowptr", numLocal + 1);
73 entries_type colind("colind", numLocal);
74 values_type values("values", numLocal);
75
76 Kokkos::parallel_for(
77 "Setup CRS values for identity prolongator",
78 Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>(0, numLocal),
79 KOKKOS_LAMBDA(const LocalOrdinal index) {
80 rowptr(index) = index;
81 colind(index) = index;
82 values(index) = local_scalar_type{1.0};
83 if (index == (numLocal - 1)) {
84 rowptr(numLocal) = numLocal;
85 }
86 });
87
88 auto eye = Xpetra::CrsMatrixFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(map, map, 0);
89 eye->setAllValues(rowptr, colind, values);
90 eye->expertStaticFillComplete(map, map);
91 return Teuchos::make_rcp<Xpetra::CrsMatrixWrap<Scalar, LocalOrdinal, GlobalOrdinal, Node>>(eye);
92}
93} // namespace
94
95template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
97 Level& coarseLevel) const {
98 FactoryMonitor m(*this, "Build", coarseLevel);
99
100 const ParameterList& pL = GetParameterList();
101 const LO nBlks = as<LO>(pL.get<int>("combine: numBlks"));
102 const bool useMaxLevels = pL.get<bool>("combine: useMaxLevels");
103
104 RCP<Matrix> A = Get<RCP<Matrix>>(fineLevel, "A");
105
106 // Record all matrices that each define a block in block diagonal comboP
107 // matrix used for PDE/multiblock interpolation. Additionally, count
108 // total number of local rows, nonzeros, coarseDofs, and colDofs.
109
110 Teuchos::ArrayRCP<RCP<Matrix>> arrayOfMatrices(nBlks);
111 size_t nComboRowMap = 0, nnzCombo = 0, nComboColMap = 0, nComboDomMap = 0;
112
113 LO nTotalNumberLocalColMapEntries = 0;
114 Teuchos::ArrayRCP<size_t> DomMapSizePerBlk(nBlks);
115 Teuchos::ArrayRCP<size_t> ColMapSizePerBlk(nBlks);
116 Teuchos::ArrayRCP<size_t> ColMapLocalSizePerBlk(nBlks);
117 Teuchos::ArrayRCP<size_t> ColMapRemoteSizePerBlk(nBlks);
118 Teuchos::ArrayRCP<size_t> ColMapLocalCumulativePerBlk(nBlks + 1); // hardwire 0th entry so that it has the value of 0
119 Teuchos::ArrayRCP<size_t> ColMapRemoteCumulativePerBlk(nBlks + 1); // hardwire 0th entry so that it has the value of 0
120
121 bool anyCoarseGridsRemaining = false;
122
123 if (useMaxLevels) {
124 for (int j = 0; j < nBlks; j++) {
125 std::string blockName = "Psubblock" + Teuchos::toString(j);
126 anyCoarseGridsRemaining |= coarseLevel.IsAvailable(blockName, NoFactory::get());
127 };
128
129 int localAnyCoarseGridsRemaining = anyCoarseGridsRemaining;
130 int globalAnyCoarseGridsRemaining = localAnyCoarseGridsRemaining;
131 Teuchos::reduceAll(*A->getDomainMap()->getComm(), Teuchos::REDUCE_MAX, localAnyCoarseGridsRemaining, Teuchos::ptr(&globalAnyCoarseGridsRemaining));
132
133 anyCoarseGridsRemaining |= globalAnyCoarseGridsRemaining > 0;
134 }
135
136 auto setSubblockProlongator = [&](RCP<Matrix> Psubblock, int j) {
137 arrayOfMatrices[j] = Psubblock;
138 nComboRowMap += Teuchos::as<size_t>((arrayOfMatrices[j])->getRowMap()->getLocalNumElements());
139 DomMapSizePerBlk[j] = Teuchos::as<size_t>((arrayOfMatrices[j])->getDomainMap()->getLocalNumElements());
140 ColMapSizePerBlk[j] = Teuchos::as<size_t>((arrayOfMatrices[j])->getColMap()->getLocalNumElements());
141 nComboDomMap += DomMapSizePerBlk[j];
142 nComboColMap += ColMapSizePerBlk[j];
143 nnzCombo += Teuchos::as<size_t>((arrayOfMatrices[j])->getLocalNumEntries());
144 TEUCHOS_TEST_FOR_EXCEPTION((arrayOfMatrices[j])->getDomainMap()->getIndexBase() != 0, Exceptions::RuntimeError, "interpolation subblocks must use 0 indexbase");
145
146 // figure out how many empty entries in each column map
147 int tempii = 0;
148 for (int i = 0; i < (int)DomMapSizePerBlk[j]; i++) {
149 if ((arrayOfMatrices[j])->getDomainMap()->getGlobalElement(i) == (arrayOfMatrices[j])->getColMap()->getGlobalElement(tempii)) tempii++;
150 }
151 nTotalNumberLocalColMapEntries += tempii;
152 ColMapLocalSizePerBlk[j] = tempii;
153 ColMapRemoteSizePerBlk[j] = ColMapSizePerBlk[j] - ColMapLocalSizePerBlk[j];
154 };
155
156 for (int j = 0; j < nBlks; j++) {
157 std::string blockName = "Psubblock" + Teuchos::toString(j);
158 if (coarseLevel.IsAvailable(blockName, NoFactory::get())) {
159 setSubblockProlongator(coarseLevel.Get<RCP<Matrix>>(blockName, NoFactory::get()), j);
160 } else {
161 std::string subblockOpName = "Operatorsubblock" + Teuchos::toString(j);
162 bool hasOperator = false;
163 if (coarseLevel.IsAvailable(subblockOpName)) {
164 auto A_blk = coarseLevel.Get<RCP<Operator>>(subblockOpName);
165 hasOperator = A_blk != Teuchos::null;
166 }
167
168 if (useMaxLevels && anyCoarseGridsRemaining && hasOperator) {
169 // Use Psubblock = I
170 auto P_id = constructIdentityProlongator<Scalar, LocalOrdinal, GlobalOrdinal, Node>(coarseLevel.Get<RCP<Operator>>(subblockOpName)->getDomainMap());
171 setSubblockProlongator(P_id, j);
172 } else {
173 arrayOfMatrices[j] = Teuchos::null;
174 ColMapLocalSizePerBlk[j] = 0;
175 ColMapRemoteSizePerBlk[j] = 0;
176 }
177 }
178 ColMapLocalCumulativePerBlk[j + 1] = ColMapLocalSizePerBlk[j] + ColMapLocalCumulativePerBlk[j];
179 ColMapRemoteCumulativePerBlk[j + 1] = ColMapRemoteSizePerBlk[j] + ColMapRemoteCumulativePerBlk[j];
180 }
181
182 TEUCHOS_TEST_FOR_EXCEPTION(nComboRowMap != A->getRowMap()->getLocalNumElements(), Exceptions::RuntimeError, "sum of subblock rows != #row's Afine");
183
184 // build up csr arrays for combo block diagonal P
185 Teuchos::ArrayRCP<size_t> comboPRowPtr(nComboRowMap + 1);
186 Teuchos::ArrayRCP<LocalOrdinal> comboPCols(nnzCombo);
187 Teuchos::ArrayRCP<Scalar> comboPVals(nnzCombo);
188
189 size_t nnzCnt = 0, nrowCntFromPrevBlks = 0, ncolCntFromPrevBlks = 0;
190 LO maxNzPerRow = 0;
191 for (int j = 0; j < nBlks; j++) {
192 // grab csr pointers for individual blocks of P
193 if (arrayOfMatrices[j] != Teuchos::null) {
194 Teuchos::ArrayRCP<const size_t> subblockRowPtr((arrayOfMatrices[j])->getLocalNumRows());
195 Teuchos::ArrayRCP<const LocalOrdinal> subblockCols((arrayOfMatrices[j])->getLocalNumEntries());
196 Teuchos::ArrayRCP<const Scalar> subblockVals((arrayOfMatrices[j])->getLocalNumEntries());
197 if ((int)(arrayOfMatrices[j])->getLocalMaxNumRowEntries() > maxNzPerRow) maxNzPerRow = (int)(arrayOfMatrices[j])->getLocalMaxNumRowEntries();
198 Teuchos::RCP<CrsMatrixWrap> subblockwrap = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>((arrayOfMatrices[j]));
199 Teuchos::RCP<CrsMatrix> subblockcrs = subblockwrap->getCrsMatrix();
200 subblockcrs->getAllValues(subblockRowPtr, subblockCols, subblockVals);
201
202 // copy jth block into csr arrays of comboP
203
204 for (decltype(subblockRowPtr.size()) i = 0; i < subblockRowPtr.size() - 1; i++) {
205 size_t rowLength = subblockRowPtr[i + 1] - subblockRowPtr[i];
206 comboPRowPtr[nrowCntFromPrevBlks + i] = nnzCnt;
207 for (size_t k = 0; k < rowLength; k++) {
208 if ((int)subblockCols[k + subblockRowPtr[i]] < (int)ColMapLocalSizePerBlk[j]) {
209 comboPCols[nnzCnt] = subblockCols[k + subblockRowPtr[i]] + ColMapLocalCumulativePerBlk[j];
210 if ((int)comboPCols[nnzCnt] >= (int)ColMapLocalCumulativePerBlk[nBlks]) {
211 printf("ERROR1\n");
212 exit(1);
213 }
214 } else {
215 // Here we subtract off the number of local colmap guys ... so this tell us where we are among ghost unknowns. We then want to stick this ghost after
216 // all the Local guys ... so we add ColMapLocalCumulativePerBlk[nBlks] .... finally we need to account for the fact that other ghost blocks may have already
217 // been handled ... so we then add + ColMapRemoteCumulativePerBlk[j];
218 comboPCols[nnzCnt] = subblockCols[k + subblockRowPtr[i]] - ColMapLocalSizePerBlk[j] + ColMapLocalCumulativePerBlk[nBlks] + ColMapRemoteCumulativePerBlk[j];
219 if ((int)comboPCols[nnzCnt] >= (int)(ColMapLocalCumulativePerBlk[nBlks] + ColMapRemoteCumulativePerBlk[nBlks])) {
220 printf("ERROR2\n");
221 exit(1);
222 }
223 }
224 comboPVals[nnzCnt++] = subblockVals[k + subblockRowPtr[i]];
225 }
226 }
227
228 nrowCntFromPrevBlks += Teuchos::as<size_t>((arrayOfMatrices[j])->getRowMap()->getLocalNumElements());
229 ncolCntFromPrevBlks += DomMapSizePerBlk[j]; // rst: check this
230 }
231 }
232 comboPRowPtr[nComboRowMap] = nnzCnt;
233
234 // Come up with global IDs for the coarse grid maps. We assume that each xxx
235 // block has a minimum GID of 0. Since MueLu is generally creating these
236 // GIDS, this assumption is probably correct, but we'll check it.
237
238 Teuchos::Array<GlobalOrdinal> comboDomainMapGIDs(nComboDomMap);
239 Teuchos::Array<GlobalOrdinal> comboColMapGIDs(nComboColMap);
240
241 LO nTotalNumberRemoteColMapEntries = 0;
242 GlobalOrdinal offset = 0;
243 size_t domainMapIndex = 0;
244 int nComboColIndex = 0;
245 for (int j = 0; j < nBlks; j++) {
246 int nThisBlkColIndex = 0;
247
248 GlobalOrdinal tempMax = 0, maxGID = 0;
249 if (arrayOfMatrices[j] != Teuchos::null) tempMax = (arrayOfMatrices[j])->getDomainMap()->getMaxGlobalIndex();
250 Teuchos::reduceAll(*(A->getDomainMap()->getComm()), Teuchos::REDUCE_MAX, tempMax, Teuchos::ptr(&maxGID));
251
252 if (arrayOfMatrices[j] != Teuchos::null) {
253 TEUCHOS_TEST_FOR_EXCEPTION(arrayOfMatrices[j]->getDomainMap()->getMinAllGlobalIndex() < 0, Exceptions::RuntimeError, "Global ID assumption for domainMap not met within subblock");
254
255 GO priorDomGID = 0;
256 for (size_t c = 0; c < DomMapSizePerBlk[j]; ++c) { // check this
257 // The global ids of jth block are assumed to go between 0 and maxGID_j. So the 1th blocks DomainGIDs should start at maxGID_0+1. The 2nd
258 // block DomainDIGS starts at maxGID_0+1 + maxGID_1 + 1. We use offset to keep track of these starting points.
259 priorDomGID = (arrayOfMatrices[j])->getDomainMap()->getGlobalElement(c);
260 comboDomainMapGIDs[domainMapIndex++] = offset + priorDomGID;
261 if (priorDomGID == (arrayOfMatrices[j])->getColMap()->getGlobalElement(nThisBlkColIndex)) {
262 comboColMapGIDs[nComboColIndex++] = offset + priorDomGID;
263 nThisBlkColIndex++;
264 }
265 }
266
267 for (size_t cc = nThisBlkColIndex; cc < ColMapSizePerBlk[j]; ++cc) {
268 comboColMapGIDs[nTotalNumberLocalColMapEntries + nTotalNumberRemoteColMapEntries++] = offset + (arrayOfMatrices[j])->getColMap()->getGlobalElement(cc);
269 }
270 }
271 offset += maxGID + 1;
272 }
273#ifdef out
274 RCP<const Map> coarseDomainMap = Xpetra::MapFactory<LO, GO, NO>::Build(A->getDomainMap()->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), comboDomainMapGIDs, 0, A->getDomainMap()->getComm());
275 RCP<const Map> coarseColMap = Xpetra::MapFactory<LO, GO, NO>::Build(A->getDomainMap()->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), comboColMapGIDs, 0, A->getDomainMap()->getComm());
276#endif
277
278 RCP<const Map> coarseDomainMap = Xpetra::MapFactory<LO, GO, NO>::Build(A->getDomainMap()->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), comboDomainMapGIDs, 0, A->getRowMap()->getComm());
279 RCP<const Map> coarseColMap = Xpetra::MapFactory<LO, GO, NO>::Build(A->getDomainMap()->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), comboColMapGIDs, 0, A->getRowMap()->getComm());
280
281 Teuchos::RCP<CrsMatrix> comboPCrs = CrsMatrixFactory::Build(A->getRowMap(), coarseColMap, maxNzPerRow);
282 // comboPCrs->getCrsGraph(); //.getRowInfo(6122);
283 // comboPCrs->getRowInfo(6122);
284
285 // Teuchos::RCP<CrsMatrix> comboPCrs = CrsMatrixFactory::Build(A->getRowMap(), coarseColMap,nnzCombo+1000);
286
287 // for (size_t i = 0; i < nComboRowMap; i++) {
288 // printf("FIXME\n"); if (nComboRowMap > 6142) nComboRowMap = 6142;
289 for (size_t i = 0; i < nComboRowMap; i++) {
290 comboPCrs->insertLocalValues(i, comboPCols.view(comboPRowPtr[i], comboPRowPtr[i + 1] - comboPRowPtr[i]),
291 comboPVals.view(comboPRowPtr[i], comboPRowPtr[i + 1] - comboPRowPtr[i]));
292 }
293 comboPCrs->fillComplete(coarseDomainMap, A->getRowMap());
294
295 Teuchos::RCP<Matrix> comboP = Teuchos::rcp(new CrsMatrixWrap(comboPCrs));
296
297 Set(coarseLevel, "P", comboP);
298}
299
300} // namespace MueLu
301
302#define MUELU_COMBINEPFACTORY_SHORT
303#endif // MUELU_COMBINEPFACTORY_DEF_HPP
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultGlobalOrdinal GlobalOrdinal
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
static const NoFactory * get()
Namespace for MueLu classes and methods.