Xpetra Version of the Day
Loading...
Searching...
No Matches
Xpetra_MatrixUtils_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Xpetra: A linear algebra interface package
4//
5// Copyright 2012 NTESS and the Xpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef PACKAGES_XPETRA_SUP_MATRIX_UTILS_DEF_HPP_
11#define PACKAGES_XPETRA_SUP_MATRIX_UTILS_DEF_HPP_
12
13#include "Xpetra_ConfigDefs.hpp"
14
15#include "Xpetra_Map.hpp"
16#include "Xpetra_MapUtils.hpp"
17#include "Xpetra_StridedMap.hpp"
18#include "Xpetra_MapFactory.hpp"
19#include "Xpetra_MapExtractor.hpp"
21#include "Xpetra_Matrix.hpp"
22#include "Xpetra_MatrixFactory.hpp"
23#include "Xpetra_BlockedCrsMatrix.hpp"
24#include "Xpetra_MatrixMatrix.hpp"
25
26#include "Xpetra_TpetraMultiVector.hpp"
27#include <Tpetra_RowMatrixTransposer.hpp>
30
32
33namespace Xpetra {
34
35template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
36Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::xpetraGidNumbering2ThyraGidNumbering(
38 RCP<const Map> map = MapUtils::shrinkMapGIDs(*(input.getMap()), *(input.getMap()));
40 for (size_t c = 0; c < input.getNumVectors(); c++) {
42 for (size_t r = 0; r < input.getLocalLength(); r++) {
43 ret->replaceLocalValue(Teuchos::as<LocalOrdinal>(r), c, data[r]);
44 }
45 }
46
47 return ret;
48}
49
50template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
51Teuchos::RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node>> MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::findColumnSubMap(
54 RCP<const Teuchos::Comm<int>> comm = input.getRowMap()->getComm();
55
56 // build an overlapping version of mySpecialMap
57 Teuchos::Array<GlobalOrdinal> ovlUnknownStatusGids;
58 Teuchos::Array<GlobalOrdinal> ovlFoundStatusGids;
59
60 // loop over global column map of A and find all GIDs where it is not sure, whether they are special or not
61 for (size_t i = 0; i < input.getColMap()->getLocalNumElements(); i++) {
62 GlobalOrdinal gcid = input.getColMap()->getGlobalElement(i);
63 if (domainMap.isNodeGlobalElement(gcid) == false) {
64 ovlUnknownStatusGids.push_back(gcid);
65 }
66 }
67
68 // We need a locally replicated list of all DOF gids of the (non-overlapping) range map of A10
69 // Communicate the number of DOFs on each processor
70 std::vector<int> myUnknownDofGIDs(comm->getSize(), 0);
71 std::vector<int> numUnknownDofGIDs(comm->getSize(), 0);
72 myUnknownDofGIDs[comm->getRank()] = ovlUnknownStatusGids.size();
73 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &myUnknownDofGIDs[0], &numUnknownDofGIDs[0]);
74
75 // create array containing all DOF GIDs
76 size_t cntUnknownDofGIDs = 0;
77 for (int p = 0; p < comm->getSize(); p++) cntUnknownDofGIDs += numUnknownDofGIDs[p];
78 std::vector<GlobalOrdinal> lUnknownDofGIDs(cntUnknownDofGIDs, -1); // local version to be filled
79 std::vector<GlobalOrdinal> gUnknownDofGIDs(cntUnknownDofGIDs, -1); // global version after communication
80 // calculate the offset and fill chunk of memory with local data on each processor
81 size_t cntUnknownOffset = 0;
82 for (int p = 0; p < comm->getRank(); p++) cntUnknownOffset += numUnknownDofGIDs[p];
83 for (size_t k = 0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
84 lUnknownDofGIDs[k + cntUnknownOffset] = ovlUnknownStatusGids[k];
85 }
86 if (cntUnknownDofGIDs > 0)
87 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntUnknownDofGIDs), &lUnknownDofGIDs[0], &gUnknownDofGIDs[0]);
88 std::sort(gUnknownDofGIDs.begin(), gUnknownDofGIDs.end());
89 gUnknownDofGIDs.erase(std::unique(gUnknownDofGIDs.begin(), gUnknownDofGIDs.end()), gUnknownDofGIDs.end());
90
91 // loop through all GIDs with unknown status
92 for (size_t k = 0; k < gUnknownDofGIDs.size(); k++) {
93 GlobalOrdinal curgid = gUnknownDofGIDs[k];
94 if (domainMap.isNodeGlobalElement(curgid)) {
95 ovlFoundStatusGids.push_back(curgid); // curgid is in special map (on this processor)
96 }
97 }
98
99 std::vector<int> myFoundDofGIDs(comm->getSize(), 0);
100 std::vector<int> numFoundDofGIDs(comm->getSize(), 0);
101 myFoundDofGIDs[comm->getRank()] = ovlFoundStatusGids.size();
102 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, comm->getSize(), &myFoundDofGIDs[0], &numFoundDofGIDs[0]);
103
104 // create array containing all DOF GIDs
105 size_t cntFoundDofGIDs = 0;
106 for (int p = 0; p < comm->getSize(); p++) cntFoundDofGIDs += numFoundDofGIDs[p];
107 std::vector<GlobalOrdinal> lFoundDofGIDs(cntFoundDofGIDs, -1); // local version to be filled
108 std::vector<GlobalOrdinal> gFoundDofGIDs(cntFoundDofGIDs, -1); // global version after communication
109 // calculate the offset and fill chunk of memory with local data on each processor
110 size_t cntFoundOffset = 0;
111 for (int p = 0; p < comm->getRank(); p++) cntFoundOffset += numFoundDofGIDs[p];
112 for (size_t k = 0; k < Teuchos::as<size_t>(ovlFoundStatusGids.size()); k++) {
113 lFoundDofGIDs[k + cntFoundOffset] = ovlFoundStatusGids[k];
114 }
115 if (cntFoundDofGIDs > 0)
116 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, Teuchos::as<int>(cntFoundDofGIDs), &lFoundDofGIDs[0], &gFoundDofGIDs[0]);
117
118 Teuchos::Array<GlobalOrdinal> ovlDomainMapArray;
119 for (size_t i = 0; i < input.getColMap()->getLocalNumElements(); i++) {
120 GlobalOrdinal gcid = input.getColMap()->getGlobalElement(i);
121 if (domainMap.isNodeGlobalElement(gcid) == true ||
122 std::find(gFoundDofGIDs.begin(), gFoundDofGIDs.end(), gcid) != gFoundDofGIDs.end()) {
123 ovlDomainMapArray.push_back(gcid);
124 }
125 }
126 RCP<Map> ovlDomainMap = MapFactory::Build(domainMap.lib(), Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(), ovlDomainMapArray(), 0, comm);
127 return ovlDomainMap;
128}
129
130template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
131Teuchos::RCP<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::SplitMatrix(
133 Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node>> rangeMapExtractor,
134 Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node>> domainMapExtractor,
135 Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node>> columnMapExtractor,
136 bool bThyraMode) {
137 size_t numRows = rangeMapExtractor->NumMaps();
138 size_t numCols = domainMapExtractor->NumMaps();
139
140 TEUCHOS_TEST_FOR_EXCEPTION(rangeMapExtractor->getThyraMode() == true, Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor must not use Thyra style numbering of GIDs. The MapExtractor must contain all GIDs of the full range map in order to define a proper splitting.")
141 TEUCHOS_TEST_FOR_EXCEPTION(domainMapExtractor->getThyraMode() == true, Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor must not use Thyra style numbering of GIDs. The MapExtractor must contain all GIDs of the full domain map in order to define a proper splitting.")
142
143 RCP<const Map> fullRangeMap = rangeMapExtractor->getFullMap();
144 RCP<const Map> fullDomainMap = domainMapExtractor->getFullMap();
145
146 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getMaxAllGlobalIndex() != input.getRowMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
147 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getGlobalNumElements() != input.getRowMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
148 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getLocalNumElements() != input.getRowMap()->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
149 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getMaxAllGlobalIndex() != input.getRangeMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
150 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getGlobalNumElements() != input.getRangeMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
151 TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getLocalNumElements() != input.getRangeMap()->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
152
153 TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getMaxAllGlobalIndex() != input.getColMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix. fullDomainMap->getMaxAllGlobalIndex() = " << fullDomainMap->getMaxAllGlobalIndex() << " vs. input.getColMap()->getMaxAllGlobalIndex() = " << input.getColMap()->getMaxAllGlobalIndex())
154 TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getMaxAllGlobalIndex() != input.getDomainMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
155 TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getGlobalNumElements() != input.getDomainMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
156 TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getLocalNumElements() != input.getDomainMap()->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
157
158 // check column map extractor
159 Teuchos::RCP<const MapExtractor> myColumnMapExtractor = Teuchos::null;
160 if (columnMapExtractor == Teuchos::null) {
161 TEUCHOS_TEST_FOR_EXCEPTION(domainMapExtractor->getThyraMode() == true, Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Auto generation of column map extractor not supported for Thyra style numbering.");
162 // This code is always executed, since we always provide map extractors in Xpetra numbering!
163 std::vector<Teuchos::RCP<const Map>> ovlxmaps(numCols, Teuchos::null);
164 for (size_t c = 0; c < numCols; c++) {
165 // TODO: is this routine working correctly?
166 Teuchos::RCP<const Map> colMap = MatrixUtils::findColumnSubMap(input, *(domainMapExtractor->getMap(c)));
167 ovlxmaps[c] = colMap;
168 }
169 RCP<const Map> fullColMap = MapUtils::concatenateMaps(ovlxmaps);
170 // This MapExtractor is always in Xpetra mode!
171 myColumnMapExtractor = MapExtractorFactory::Build(fullColMap, ovlxmaps);
172 } else
173 myColumnMapExtractor = columnMapExtractor; // use user-provided column map extractor.
174
175 // all above MapExtractors are always in Xpetra mode
176 // build separate ones containing Thyra mode GIDs (if necessary)
177 Teuchos::RCP<const MapExtractor> thyRangeMapExtractor = Teuchos::null;
178 Teuchos::RCP<const MapExtractor> thyDomainMapExtractor = Teuchos::null;
179 Teuchos::RCP<const MapExtractor> thyColMapExtractor = Teuchos::null;
180 if (bThyraMode == true) {
181 // build Thyra-style map extractors
182 std::vector<Teuchos::RCP<const Map>> thyRgMapExtractorMaps(numRows, Teuchos::null);
183 for (size_t r = 0; r < numRows; r++) {
184 RCP<const Map> rMap = rangeMapExtractor->getMap(r);
185 RCP<const Map> shrinkedMap = MapUtils::shrinkMapGIDs(*rMap, *rMap);
186 RCP<const StridedMap> strRangeMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rMap);
187 if (strRangeMap != Teuchos::null) {
188 std::vector<size_t> strInfo = strRangeMap->getStridingData();
189 GlobalOrdinal offset = strRangeMap->getOffset();
190 LocalOrdinal stridedBlockId = strRangeMap->getStridedBlockId();
191 RCP<const StridedMap> strShrinkedMap = Teuchos::rcp(new StridedMap(shrinkedMap, strInfo, shrinkedMap->getIndexBase(), stridedBlockId, offset));
192 thyRgMapExtractorMaps[r] = strShrinkedMap;
193 } else {
194 thyRgMapExtractorMaps[r] = shrinkedMap;
195 }
196 TEUCHOS_TEST_FOR_EXCEPTION(thyRgMapExtractorMaps[r]->getLocalNumElements() != rMap->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style range map extractor contains faulty data.")
197 }
198 RCP<const Map> fullThyRangeMap = MapUtils::concatenateMaps(thyRgMapExtractorMaps);
199 thyRangeMapExtractor = MapExtractorFactory::Build(fullThyRangeMap, thyRgMapExtractorMaps, true);
200 std::vector<Teuchos::RCP<const Map>> thyDoMapExtractorMaps(numCols, Teuchos::null);
201 std::vector<Teuchos::RCP<const Map>> thyColMapExtractorMaps(numCols, Teuchos::null);
202 for (size_t c = 0; c < numCols; c++) {
203 RCP<const Map> cMap = domainMapExtractor->getMap(c);
204
205 RCP<const Map> shrinkedDomainMap = MapUtils::shrinkMapGIDs(*cMap, *cMap);
206 RCP<const StridedMap> strDomainMap = Teuchos::rcp_dynamic_cast<const StridedMap>(cMap);
207 if (strDomainMap != Teuchos::null) {
208 std::vector<size_t> strInfo = strDomainMap->getStridingData();
209 GlobalOrdinal offset = strDomainMap->getOffset();
210 LocalOrdinal stridedBlockId = strDomainMap->getStridedBlockId();
211 RCP<const StridedMap> strShrinkedDomainMap = Teuchos::rcp(new StridedMap(shrinkedDomainMap, strInfo, shrinkedDomainMap->getIndexBase(), stridedBlockId, offset));
212 thyDoMapExtractorMaps[c] = strShrinkedDomainMap;
213 } else {
214 thyDoMapExtractorMaps[c] = shrinkedDomainMap;
215 }
216 RCP<const Map> colMap = myColumnMapExtractor->getMap(c);
217 RCP<const Map> shrinkedColMap = MapUtils::shrinkMapGIDs(*colMap, *cMap);
218 RCP<const StridedMap> strColMap = Teuchos::rcp_dynamic_cast<const StridedMap>(colMap);
219 if (strColMap != Teuchos::null) {
220 std::vector<size_t> strInfo = strColMap->getStridingData();
221 GlobalOrdinal offset = strColMap->getOffset();
222 LocalOrdinal stridedBlockId = strColMap->getStridedBlockId();
223 RCP<const StridedMap> strShrinkedColMap = Teuchos::rcp(new StridedMap(shrinkedColMap, strInfo, shrinkedColMap->getIndexBase(), stridedBlockId, offset));
224 thyColMapExtractorMaps[c] = strShrinkedColMap;
225 } else {
226 thyColMapExtractorMaps[c] = shrinkedColMap;
227 }
228
229 TEUCHOS_TEST_FOR_EXCEPTION(thyColMapExtractorMaps[c]->getLocalNumElements() != colMap->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style column map extractor contains faulty data.")
230 TEUCHOS_TEST_FOR_EXCEPTION(thyDoMapExtractorMaps[c]->getLocalNumElements() != cMap->getLocalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style domain map extractor contains faulty data.")
231 }
232 RCP<const Map> fullThyDomainMap = MapUtils::concatenateMaps(thyDoMapExtractorMaps);
233 RCP<const Map> fullThyColumnMap = MapUtils::concatenateMaps(thyColMapExtractorMaps);
234 thyDomainMapExtractor = MapExtractorFactory::Build(fullThyDomainMap, thyDoMapExtractorMaps, true);
235 thyColMapExtractor = MapExtractorFactory::Build(fullThyColumnMap, thyColMapExtractorMaps, true);
236 }
237 // create submatrices
238 std::vector<Teuchos::RCP<Matrix>> subMatrices(numRows * numCols, Teuchos::null);
239 for (size_t r = 0; r < numRows; r++) {
240 for (size_t c = 0; c < numCols; c++) {
241 // create empty CrsMatrix objects
242 // make sure that the submatrices are defined using the right row maps (either Thyra or xpetra style)
243 // Note: we're reserving a little bit too much memory for the submatrices, but should be still reasonable
244 if (bThyraMode == true)
245 subMatrices[r * numCols + c] = MatrixFactory::Build(thyRangeMapExtractor->getMap(r, true), input.getLocalMaxNumRowEntries());
246 else
247 subMatrices[r * numCols + c] = MatrixFactory::Build(rangeMapExtractor->getMap(r), input.getLocalMaxNumRowEntries());
248 }
249 }
250
251 // We need a vector which lives on the column map of input and stores the block id that the column belongs to.
252 // create a vector on the domain map. Loop over it and fill in the corresponding block id numbers
253 // create a vector on the column map and import the data
254 // Importer: source map is non-overlapping. Target map is overlapping
255 // call colMap.Import(domMap,Importer,Insert)
256 // do the same with "Add" to make sure only one processor is responsible for the different GIDs!
257#if 0 // TAW needs to be fixed (does not compile for Scalar=complex)
258 typedef Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node> VectorFactory;
262
263 RCP<Vector> doCheck = VectorFactory::Build(input.getDomainMap(), true);
264 doCheck->putScalar(1.0);
265 RCP<Vector> coCheck = VectorFactory::Build(input.getColMap(), true);
267 coCheck->doImport(*doCheck, *imp, Xpetra::ADD);
268 TEUCHOS_TEST_FOR_EXCEPTION(coCheck->normInf() != Teuchos::ScalarTraits< Scalar >::magnitude(1.0), Xpetra::Exceptions::RuntimeError, "Xpetra::MatrixUtils::SplitMatrix: error when distributing data.");
269
270 doCheck->putScalar(-1.0);
271 coCheck->putScalar(-1.0);
272
273 Teuchos::ArrayRCP< Scalar > doCheckData = doCheck->getDataNonConst(0);
274 for (size_t rrr = 0; rrr < input.getDomainMap()->getLocalNumElements(); rrr++) {
275 // global row id to extract data from global monolithic matrix
276 GlobalOrdinal id = input.getDomainMap()->getGlobalElement(rrr); // LID -> GID (column)
277
278 // Find the block id in range map extractor that belongs to same global id.
279 size_t BlockId = domainMapExtractor->getMapIndexForGID(id);
280
281 doCheckData[rrr] = Teuchos::as<Scalar>(BlockId);
282 }
283
284 coCheck->doImport(*doCheck, *imp, Xpetra::INSERT);
285
286 Teuchos::ArrayRCP< Scalar > coCheckData = coCheck->getDataNonConst(0);
287#endif
288 // loop over all rows of input matrix
289 for (size_t rr = 0; rr < input.getRowMap()->getLocalNumElements(); rr++) {
290 // global row id to extract data from global monolithic matrix
291 GlobalOrdinal growid = input.getRowMap()->getGlobalElement(rr); // LID -> GID (column)
292
293 // Find the block id in range map extractor that belongs to same global row id.
294 // We assume the global ids to be unique in the map extractor
295 // The MapExtractor objects may be constructed using the thyra mode. However, we use
296 // global GID ids (as we have a single input matrix). The only problematic thing could
297 // be that the GIDs of the input matrix are inconsistent with the GIDs in the map extractor.
298 // Note, that for the Thyra mode the GIDs in the map extractor are generated using the ordering
299 // of the blocks.
300 size_t rowBlockId = rangeMapExtractor->getMapIndexForGID(growid);
301
302 // global row id used for subblocks to insert information
303 GlobalOrdinal subblock_growid = growid; // for Xpetra-style numbering the global row ids are not changing
304 if (bThyraMode == true) {
305 // find local row id associated with growid in the corresponding subblock
306 LocalOrdinal lrowid = rangeMapExtractor->getMap(rowBlockId)->getLocalElement(growid);
307 // translate back local row id to global row id for the subblock
308 subblock_growid = thyRangeMapExtractor->getMap(rowBlockId, true)->getGlobalElement(lrowid);
309 }
310
311 // extract matrix entries from input matrix
312 // we use global ids since we have to determine the corresponding
313 // block column ids using the global ids anyway
316 input.getLocalRowView(rr, indices, vals);
317
318 std::vector<Teuchos::Array<GlobalOrdinal>> blockColIdx(numCols, Teuchos::Array<GlobalOrdinal>());
319 std::vector<Teuchos::Array<Scalar>> blockColVals(numCols, Teuchos::Array<Scalar>());
320
321 for (size_t i = 0; i < (size_t)indices.size(); i++) {
322 // gobal column id to extract data from full monolithic matrix
323 GlobalOrdinal gcolid = input.getColMap()->getGlobalElement(indices[i]);
324
325 size_t colBlockId = myColumnMapExtractor->getMapIndexForGID(gcolid); // old buggy thing
326 // size_t colBlockId = Teuchos::as<size_t>(coCheckData[indices[i]]);
327
328 // global column id used for subblocks to insert information
329 GlobalOrdinal subblock_gcolid = gcolid; // for Xpetra-style numbering the global col ids are not changing
330 if (bThyraMode == true) {
331 // find local col id associated with gcolid in the corresponding subblock
332 LocalOrdinal lcolid = myColumnMapExtractor->getMap(colBlockId)->getLocalElement(gcolid);
333 // translate back local col id to global col id for the subblock
334 subblock_gcolid = thyColMapExtractor->getMap(colBlockId, true)->getGlobalElement(lcolid);
335 }
336 blockColIdx[colBlockId].push_back(subblock_gcolid);
337 blockColVals[colBlockId].push_back(vals[i]);
338 }
339
340 for (size_t c = 0; c < numCols; c++) {
341 subMatrices[rowBlockId * numCols + c]->insertGlobalValues(subblock_growid, blockColIdx[c].view(0, blockColIdx[c].size()), blockColVals[c].view(0, blockColVals[c].size()));
342 }
343 }
344
345 // call fill complete on subblocks and create BlockedCrsOperator
346 RCP<BlockedCrsMatrix> bA = Teuchos::null;
347 if (bThyraMode == true) {
348 for (size_t r = 0; r < numRows; r++) {
349 for (size_t c = 0; c < numCols; c++) {
350 subMatrices[r * numCols + c]->fillComplete(thyDomainMapExtractor->getMap(c, true), thyRangeMapExtractor->getMap(r, true));
351 }
352 }
353 bA = Teuchos::rcp(new BlockedCrsMatrix(thyRangeMapExtractor, thyDomainMapExtractor, 10 /*input.getRowMap()->getLocalMaxNumRowEntries()*/));
354 } else {
355 for (size_t r = 0; r < numRows; r++) {
356 for (size_t c = 0; c < numCols; c++) {
357 subMatrices[r * numCols + c]->fillComplete(domainMapExtractor->getMap(c), rangeMapExtractor->getMap(r));
358 }
359 }
360 bA = Teuchos::rcp(new BlockedCrsMatrix(rangeMapExtractor, domainMapExtractor, 10 /*input.getRowMap()->getLocalMaxNumRowEntries()*/));
361 }
362
363 for (size_t r = 0; r < numRows; r++) {
364 for (size_t c = 0; c < numCols; c++) {
365 bA->setMatrix(r, c, subMatrices[r * numCols + c]);
366 }
367 }
368 return bA;
369}
370
371template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
372void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CheckRepairMainDiagonal(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& Ac,
373 bool const& repairZeroDiagonals, Teuchos::FancyOStream& fos,
374 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType threshold,
375 const Scalar replacementValue) {
376 using TST = typename Teuchos::ScalarTraits<Scalar>;
377 using Teuchos::rcp_dynamic_cast;
378
379 GlobalOrdinal gZeroDiags;
380 bool usedEfficientPath = false;
381
382 RCP<CrsMatrixWrap> crsWrapAc = rcp_dynamic_cast<CrsMatrixWrap>(Ac);
383 RCP<TpetraCrsMatrix> tpCrsAc;
384 if (!crsWrapAc.is_null())
385 tpCrsAc = rcp_dynamic_cast<TpetraCrsMatrix>(crsWrapAc->getCrsMatrix());
386
387 if (!tpCrsAc.is_null()) {
388 auto tpCrsGraph = tpCrsAc->getTpetra_CrsMatrix()->getCrsGraph();
389 size_t numRows = Ac->getRowMap()->getLocalNumElements();
391 using range_type = Kokkos::RangePolicy<LocalOrdinal, typename Node::execution_space>;
392 auto offsets = offset_type(Kokkos::ViewAllocateWithoutInitializing("offsets"), numRows);
393 tpCrsGraph->getLocalDiagOffsets(offsets);
394
395 const size_t STINV =
396 Tpetra::Details::OrdinalTraits<typename offset_type::value_type>::invalid();
397
398 if (repairZeroDiagonals) {
399 // Make sure that the matrix has all its diagonal entries, so
400 // we can fix them in-place.
401
402 LO numMissingDiagonalEntries = 0;
403
404 Kokkos::parallel_reduce(
405 "countMissingDiagonalEntries",
406 range_type(0, numRows),
407 KOKKOS_LAMBDA(const LO i, LO& missing) {
408 missing += (offsets(i) == STINV);
409 },
410 numMissingDiagonalEntries);
411
412 GlobalOrdinal gNumMissingDiagonalEntries;
413 Teuchos::reduceAll(*(Ac->getRowMap()->getComm()), Teuchos::REDUCE_SUM, Teuchos::as<GlobalOrdinal>(numMissingDiagonalEntries),
414 Teuchos::outArg(gNumMissingDiagonalEntries));
415
416 if (gNumMissingDiagonalEntries == 0) {
417 // Matrix has all diagonal entries, now we fix them
418
419 auto lclA = tpCrsAc->getTpetra_CrsMatrix()->getLocalMatrixDevice();
420
421#if KOKKOS_VERSION >= 40799
422 using ATS = KokkosKernels::ArithTraits<Scalar>;
423#else
424 using ATS = Kokkos::ArithTraits<Scalar>;
425#endif
426#if KOKKOS_VERSION >= 40799
427 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
428#else
429 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
430#endif
431
432 LO lZeroDiags = 0;
433 typename ATS::val_type impl_replacementValue = replacementValue;
434
435 Kokkos::parallel_reduce(
436 "fixSmallDiagonalEntries",
437 range_type(0, numRows),
438 KOKKOS_LAMBDA(const LO i, LO& fixed) {
439 const auto offset = offsets(i);
440 auto curRow = lclA.row(i);
441 if (impl_ATS::magnitude(curRow.value(offset)) <= threshold) {
442 curRow.value(offset) = impl_replacementValue;
443 fixed += 1;
444 }
445 },
446 lZeroDiags);
447
448 Teuchos::reduceAll(*(Ac->getRowMap()->getComm()), Teuchos::REDUCE_SUM, Teuchos::as<GlobalOrdinal>(lZeroDiags),
449 Teuchos::outArg(gZeroDiags));
450
451 usedEfficientPath = true;
452 }
453 } else {
454 // We only want to count up small diagonal entries, but not
455 // fix them. So missing diagonal entries are not an issue.
456
457 auto lclA = tpCrsAc->getTpetra_CrsMatrix()->getLocalMatrixDevice();
458
459#if KOKKOS_VERSION >= 40799
460 using ATS = KokkosKernels::ArithTraits<Scalar>;
461#else
462 using ATS = Kokkos::ArithTraits<Scalar>;
463#endif
464#if KOKKOS_VERSION >= 40799
465 using impl_ATS = KokkosKernels::ArithTraits<typename ATS::val_type>;
466#else
467 using impl_ATS = Kokkos::ArithTraits<typename ATS::val_type>;
468#endif
469
470 LO lZeroDiags = 0;
471
472 Kokkos::parallel_reduce(
473 "detectSmallDiagonalEntries",
474 range_type(0, numRows),
475 KOKKOS_LAMBDA(const LO i, LO& small) {
476 const auto offset = offsets(i);
477 if (offset == STINV)
478 small += 1;
479 else {
480 auto curRow = lclA.row(i);
481 if (impl_ATS::magnitude(curRow.value(offset)) <= threshold) {
482 small += 1;
483 }
484 }
485 },
486 lZeroDiags);
487
488 Teuchos::reduceAll(*(Ac->getRowMap()->getComm()), Teuchos::REDUCE_SUM, Teuchos::as<GlobalOrdinal>(lZeroDiags),
489 Teuchos::outArg(gZeroDiags));
490
491 usedEfficientPath = true;
492 }
493 }
494
495 if (!usedEfficientPath) {
496 RCP<const Map> rowMap = Ac->getRowMap();
497 RCP<Vector> diagVec = VectorFactory::Build(rowMap);
498 Ac->getLocalDiagCopy(*diagVec);
499
500 LocalOrdinal lZeroDiags = 0;
501 Teuchos::ArrayRCP<const Scalar> diagVal = diagVec->getData(0);
502
503 for (size_t i = 0; i < rowMap->getLocalNumElements(); i++) {
504 if (TST::magnitude(diagVal[i]) <= threshold) {
505 lZeroDiags++;
506 }
507 }
508
509 Teuchos::reduceAll(*(rowMap->getComm()), Teuchos::REDUCE_SUM, Teuchos::as<GlobalOrdinal>(lZeroDiags),
510 Teuchos::outArg(gZeroDiags));
511
512 if (repairZeroDiagonals && gZeroDiags > 0) {
513 /*
514 TAW: If Ac has empty rows, put a 1 on the diagonal of Ac. Be aware that Ac might have empty rows AND
515 columns. The columns might not exist in the column map at all. It would be nice to add the entries
516 to the original matrix Ac. But then we would have to use insertLocalValues. However we cannot add
517 new entries for local column indices that do not exist in the column map of Ac (at least Epetra is
518 not able to do this). With Tpetra it is also not possible to add new entries after the FillComplete
519 call with a static map, since the column map already exists and the diagonal entries are completely
520 missing. Here we build a diagonal matrix with zeros on the diagonal and ones on the diagonal for
521 the rows where Ac has empty rows We have to build a new matrix to be able to use insertGlobalValues.
522 Then we add the original matrix Ac to our new block diagonal matrix and use the result as new
523 (non-singular) matrix Ac. This is very inefficient.
524
525 If you know something better, please let me know.
526 */
527 RCP<Matrix> fixDiagMatrix = MatrixFactory::Build(rowMap, 1);
529 Teuchos::Array<Scalar> valout(1);
530 for (size_t r = 0; r < rowMap->getLocalNumElements(); r++) {
531 if (TST::magnitude(diagVal[r]) <= threshold) {
532 GlobalOrdinal grid = rowMap->getGlobalElement(r);
533 indout[0] = grid;
534 valout[0] = replacementValue;
535 fixDiagMatrix->insertGlobalValues(grid, indout(), valout());
536 }
537 }
538 {
539 Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("CheckRepairMainDiagonal: fillComplete1"));
540 fixDiagMatrix->fillComplete(Ac->getDomainMap(), Ac->getRangeMap());
541 }
542
543 RCP<Matrix> newAc;
544 Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TwoMatrixAdd(*Ac, false, 1.0, *fixDiagMatrix, false, 1.0, newAc, fos);
545 if (Ac->IsView("stridedMaps"))
546 newAc->CreateView("stridedMaps", Ac);
547
548 Ac = Teuchos::null; // free singular matrix
549 fixDiagMatrix = Teuchos::null;
550 Ac = newAc; // set fixed non-singular matrix
551
552 // call fillComplete with optimized storage option set to true
553 // This is necessary for new faster Epetra MM kernels.
555 p->set("DoOptimizeStorage", true);
556 {
557 Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("CheckRepairMainDiagonal: fillComplete2"));
558 Ac->fillComplete(p);
559 }
560 } // end repair
561 }
562
563 // print some output
564 fos << "CheckRepairMainDiagonal: " << (repairZeroDiagonals ? "repaired " : "found ")
565 << gZeroDiags << " too small entries (threshold = " << threshold << ") on main diagonal of Ac." << std::endl;
566
567#ifdef HAVE_XPETRA_DEBUG // only for debugging
568 {
569 // check whether Ac has been repaired...
570 RCP<const Map> rowMap = Ac->getRowMap();
571 RCP<Vector> diagVec = VectorFactory::Build(rowMap);
573 Ac->getLocalDiagCopy(*diagVec);
574 diagVal = diagVec->getData(0);
575 for (size_t r = 0; r < Ac->getRowMap()->getLocalNumElements(); r++) {
576 if (TST::magnitude(diagVal[r]) <= threshold) {
577 fos << "Error: there are too small entries left on diagonal after repair..." << std::endl;
578 break;
579 }
580 }
581 }
582#endif
583}
584
585template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
586void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::RelativeDiagonalBoost(RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>& A,
587 const Teuchos::ArrayView<const double>& relativeThreshold, Teuchos::FancyOStream& fos) {
588 Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("RelativeDiagonalBoost"));
589
590 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() != relativeThreshold.size() && relativeThreshold.size() != 1, Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::RelativeDiagonal Boost: Either A->GetFixedBlockSize() != relativeThreshold.size() OR relativeThreshold.size() == 1");
591
592 LocalOrdinal numPDEs = A->GetFixedBlockSize();
593 typedef typename Teuchos::ScalarTraits<Scalar> TST;
595 Scalar zero = TST::zero();
596 Scalar one = TST::one();
597
598 // Get the diagonal
599 RCP<Vector> diag = VectorFactory::Build(A->getRowMap());
600 A->getLocalDiagCopy(*diag);
601 Teuchos::ArrayRCP<const Scalar> dataVal = diag->getData(0);
602 size_t N = A->getRowMap()->getLocalNumElements();
603
604 // Compute the diagonal maxes for each PDE
605 std::vector<MT> l_diagMax(numPDEs), g_diagMax(numPDEs);
606 for (size_t i = 0; i < N; i++) {
607 int pde = (int)(i % numPDEs);
608 if ((int)i < numPDEs)
609 l_diagMax[pde] = TST::magnitude(dataVal[i]);
610 else
611 l_diagMax[pde] = std::max(l_diagMax[pde], TST::magnitude(dataVal[i]));
612 }
613 Teuchos::reduceAll(*A->getRowMap()->getComm(), Teuchos::REDUCE_MAX, numPDEs, l_diagMax.data(), g_diagMax.data());
614
615 // Apply the diagonal maxes via matrix-matrix addition
616 RCP<Matrix> boostMatrix = MatrixFactory::Build(A->getRowMap(), 1);
618 Teuchos::Array<Scalar> value(1);
619 for (size_t i = 0; i < N; i++) {
620 GlobalOrdinal GRID = A->getRowMap()->getGlobalElement(i);
621 int pde = (int)(i % numPDEs);
622 index[0] = GRID;
623 if (TST::magnitude(dataVal[i]) < relativeThreshold[pde] * g_diagMax[pde])
624 value[0] = relativeThreshold[pde] * g_diagMax[pde] - TST::magnitude(dataVal[i]);
625 else
626 value[0] = zero;
627 boostMatrix->insertGlobalValues(GRID, index(), value());
628 }
629 boostMatrix->fillComplete(A->getDomainMap(), A->getRangeMap());
630
631 // FIXME: We really need an add that lets you "add into"
632 RCP<Matrix> newA;
633 Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TwoMatrixAdd(*A, false, one, *boostMatrix, false, one, newA, fos);
634 if (A->IsView("stridedMaps"))
635 newA->CreateView("stridedMaps", A);
636 A = newA;
637 A->fillComplete();
638}
639
640template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
641void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::extractBlockDiagonal(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A,
643 const UnderlyingLib lib = A.getRowMap()->lib();
644
645 if (lib == Xpetra::UseTpetra) {
646 const Tpetra::CrsMatrix<SC, LO, GO, NO>& At = Xpetra::Helpers<SC, LO, GO, NO>::Op2TpetraCrs(A);
648 Tpetra::Details::extractBlockDiagonal(At, Dt);
649 }
650}
651
652template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
653void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::inverseScaleBlockDiagonal(Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node>& blockDiagonal,
654 bool doTranspose,
656 const UnderlyingLib lib = blockDiagonal.getMap()->lib();
657
658 if (lib == Xpetra::UseTpetra) {
661 Tpetra::Details::inverseScaleBlockDiagonal(Dt, doTranspose, St);
662 }
663}
664
665template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
666void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::checkLocalRowMapMatchesColMap(const Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>& A) {
667 RCP<const Map> rowMap = A.getRowMap();
668 RCP<const Map> colMap = A.getColMap();
669 bool fail = false;
670 if (rowMap->lib() == Xpetra::UseTpetra) {
671 auto tpRowMap = Teuchos::rcp_dynamic_cast<const TpetraMap>(rowMap, true)->getTpetra_Map();
672 auto tpColMap = Teuchos::rcp_dynamic_cast<const TpetraMap>(colMap, true)->getTpetra_Map();
673 fail = !tpColMap->isLocallyFitted(*tpRowMap);
674 } else {
675 RCP<const Teuchos::Comm<int>> comm = rowMap->getComm();
676 LO numRows = Teuchos::as<LocalOrdinal>(rowMap->getLocalNumElements());
677
678 for (LO rowLID = 0; rowLID < numRows; rowLID++) {
679 GO rowGID = rowMap->getGlobalElement(rowLID);
680 LO colGID = colMap->getGlobalElement(rowLID);
681 if (rowGID != colGID) {
682 fail = true;
683 std::cerr << "On rank " << comm->getRank() << ", LID " << rowLID << " is GID " << rowGID << " in the rowmap, but GID " << colGID << " in the column map.\n";
684 }
685 }
686 }
688 "Local parts of row and column map do not match!");
689}
690
691template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
692void MatrixUtils<Scalar, LocalOrdinal, GlobalOrdinal, Node>::convertMatrixToStridedMaps(
694 std::vector<size_t>& rangeStridingInfo, std::vector<size_t>& domainStridingInfo) {
695 RCP<const StridedMap> stridedRowMap = StridedMapFactory::Build(matrix->getRowMap(), rangeStridingInfo, -1, 0);
696 RCP<const StridedMap> stridedColMap = StridedMapFactory::Build(matrix->getColMap(), domainStridingInfo, -1, 0);
697
698 if (matrix->IsView("stridedMaps") == true) matrix->RemoveView("stridedMaps");
699 matrix->CreateView("stridedMaps", stridedRowMap, stridedColMap);
700}
701
702} // end namespace Xpetra
703
704#endif // PACKAGES_XPETRA_SUP_MATRIX_UTILS_DEF_HPP_
size_type size() const
void push_back(const value_type &x)
size_type size() const
bool is_null() const
static RCP< Time > getNewTimer(const std::string &name)
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getMap() const =0
The Map describing the parallel distribution of this object.
Exception throws to report incompatible objects (like maps).
Exception throws to report errors in the internal logical of the program.
static RCP< Import< LocalOrdinal, GlobalOrdinal, Node > > Build(const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &source, const RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &target, const Teuchos::RCP< Teuchos::ParameterList > &plist=Teuchos::null)
Constructor specifying the number of non-zeros for all rows.
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
Map constructor with Xpetra-defined contiguous uniform distribution.
virtual UnderlyingLib lib() const =0
Get the library used by this object (Tpetra or Epetra?).
virtual bool isNodeGlobalElement(GlobalOrdinal globalIndex) const =0
Whether the given global index is valid for this Map on this process.
static Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > concatenateMaps(const std::vector< Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > > &subMaps)
Helper function to concatenate several maps.
static Teuchos::RCP< Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > shrinkMapGIDs(const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &input, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &nonOvlInput)
Helper function to shrink the GIDs and generate a standard map whith GIDs starting at 0.
Xpetra-specific matrix class.
virtual const RCP< const Map > & getRowMap() const
Returns the Map that describes the row distribution in this matrix.
virtual const RCP< const Map > & getColMap() const
Returns the Map that describes the column distribution in this matrix. This might be null until fillC...
virtual void getLocalRowView(LocalOrdinal LocalRow, ArrayView< const LocalOrdinal > &indices, ArrayView< const Scalar > &values) const =0
Extract a const, non-persisting view of local indices in a specified row of the matrix.
virtual size_t getLocalMaxNumRowEntries() const =0
Returns the maximum number of entries across all rows/columns on this node.
static Teuchos::RCP< MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > &map, size_t NumVectors, bool zeroOut=true)
Constructor specifying the number of non-zeros for all rows.
virtual size_t getNumVectors() const =0
Number of columns in the multivector.
virtual Teuchos::ArrayRCP< const Scalar > getData(size_t j) const =0
Const view of the local values in a particular vector of this multivector.
virtual size_t getLocalLength() const =0
Local number of rows on the calling process.
virtual const Teuchos::RCP< const map_type > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X....
virtual const Teuchos::RCP< const map_type > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y....
static RCP< Xpetra::StridedMap< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, std::vector< size_t > &stridingInfo, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, LocalOrdinal stridedBlockId=-1, GlobalOrdinal offset=0, LocalGlobal lg=Xpetra::GloballyDistributed)
Map constructor with Xpetra-defined contiguous uniform distribution.
Class that stores a strided map.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
TypeTo as(const TypeFrom &t)
basic_FancyOStream< char > FancyOStream
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
RCP< const Tpetra::CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > toTpetra(const RCP< const CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > &graph)
static magnitudeType magnitude(T a)