Xpetra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Xpetra_MatrixUtils.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Xpetra: A linear algebra interface package
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 // Tobias Wiesner (tawiesn@sandia.gov)
43 //
44 // ***********************************************************************
45 //
46 // @HEADER
47 #ifndef PACKAGES_XPETRA_SUP_MATRIX_UTILS_HPP_
48 #define PACKAGES_XPETRA_SUP_MATRIX_UTILS_HPP_
49 
50 #include "Xpetra_ConfigDefs.hpp"
51 
52 
53 #include "Xpetra_Map.hpp"
54 #include "Xpetra_MapUtils.hpp"
55 #include "Xpetra_StridedMap.hpp"
56 #include "Xpetra_MapFactory.hpp"
57 #include "Xpetra_MapExtractor.hpp"
59 #include "Xpetra_Matrix.hpp"
60 #include "Xpetra_MatrixFactory.hpp"
62 #include "Xpetra_MatrixMatrix.hpp"
63 
64 #include "Xpetra_IO.hpp"
65 
66 #ifdef HAVE_XPETRA_TPETRA
67 #include "Xpetra_TpetraMultiVector.hpp"
68 #include <Tpetra_RowMatrixTransposer.hpp>
69 #include <Tpetra_Details_extractBlockDiagonal.hpp>
70 #include <Tpetra_Details_scaleBlockDiagonal.hpp>
71 #endif
72 
73 namespace Xpetra {
74 
84 template <class Scalar,
85  class LocalOrdinal,
86  class GlobalOrdinal,
87  class Node>
88 class MatrixUtils {
89 #undef XPETRA_MATRIXUTILS_SHORT
90 #include "Xpetra_UseShortNames.hpp"
91 
92 public:
93 
94  static Teuchos::RCP<Xpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> > xpetraGidNumbering2ThyraGidNumbering(
96  RCP<const Map> map = MapUtils::shrinkMapGIDs(*(input.getMap()),*(input.getMap()));
97  RCP<MultiVector> ret = MultiVectorFactory::Build(map, input.getNumVectors(), true);
98  for (size_t c = 0; c < input.getNumVectors(); c++) {
99  Teuchos::ArrayRCP< const Scalar > data = input.getData(c);
100  for (size_t r = 0; r < input.getLocalLength(); r++) {
101  ret->replaceLocalValue(Teuchos::as<LocalOrdinal>(r), c, data[r]);
102  }
103  }
104 
105  return ret;
106  }
107 
108  static Teuchos::RCP<Xpetra::Map<LocalOrdinal, GlobalOrdinal, Node> > findColumnSubMap(
111 
112  RCP< const Teuchos::Comm<int> > comm = input.getRowMap()->getComm();
113 
114  // build an overlapping version of mySpecialMap
115  Teuchos::Array<GlobalOrdinal> ovlUnknownStatusGids;
116  Teuchos::Array<GlobalOrdinal> ovlFoundStatusGids;
117 
118  // loop over global column map of A and find all GIDs where it is not sure, whether they are special or not
119  for(size_t i = 0; i<input.getColMap()->getNodeNumElements(); i++) {
120  GlobalOrdinal gcid = input.getColMap()->getGlobalElement(i);
121  if(domainMap.isNodeGlobalElement(gcid) == false) {
122  ovlUnknownStatusGids.push_back(gcid);
123  }
124  }
125 
126  // We need a locally replicated list of all DOF gids of the (non-overlapping) range map of A10
127  // Communicate the number of DOFs on each processor
128  std::vector<int> myUnknownDofGIDs(comm->getSize(),0);
129  std::vector<int> numUnknownDofGIDs(comm->getSize(),0);
130  myUnknownDofGIDs[comm->getRank()] = ovlUnknownStatusGids.size();
131  Teuchos::reduceAll(*comm,Teuchos::REDUCE_MAX,comm->getSize(),&myUnknownDofGIDs[0],&numUnknownDofGIDs[0]);
132 
133  // create array containing all DOF GIDs
134  size_t cntUnknownDofGIDs = 0;
135  for(int p = 0; p < comm->getSize(); p++) cntUnknownDofGIDs += numUnknownDofGIDs[p];
136  std::vector<GlobalOrdinal> lUnknownDofGIDs(cntUnknownDofGIDs,-1); // local version to be filled
137  std::vector<GlobalOrdinal> gUnknownDofGIDs(cntUnknownDofGIDs,-1); // global version after communication
138  // calculate the offset and fill chunk of memory with local data on each processor
139  size_t cntUnknownOffset = 0;
140  for(int p = 0; p < comm->getRank(); p++) cntUnknownOffset += numUnknownDofGIDs[p];
141  for(size_t k=0; k < Teuchos::as<size_t>(ovlUnknownStatusGids.size()); k++) {
142  lUnknownDofGIDs[k+cntUnknownOffset] = ovlUnknownStatusGids[k];
143  }
144  if(cntUnknownDofGIDs > 0)
145  Teuchos::reduceAll(*comm,Teuchos::REDUCE_MAX,Teuchos::as<int>(cntUnknownDofGIDs),&lUnknownDofGIDs[0],&gUnknownDofGIDs[0]);
146  std::sort(gUnknownDofGIDs.begin(), gUnknownDofGIDs.end());
147  gUnknownDofGIDs.erase(std::unique(gUnknownDofGIDs.begin(), gUnknownDofGIDs.end()), gUnknownDofGIDs.end());
148 
149  // loop through all GIDs with unknown status
150  for(size_t k=0; k < gUnknownDofGIDs.size(); k++) {
151  GlobalOrdinal curgid = gUnknownDofGIDs[k];
152  if(domainMap.isNodeGlobalElement(curgid)) {
153  ovlFoundStatusGids.push_back(curgid); // curgid is in special map (on this processor)
154  }
155  }
156 
157  std::vector<int> myFoundDofGIDs(comm->getSize(),0);
158  std::vector<int> numFoundDofGIDs(comm->getSize(),0);
159  myFoundDofGIDs[comm->getRank()] = ovlFoundStatusGids.size();
160  Teuchos::reduceAll(*comm,Teuchos::REDUCE_MAX,comm->getSize(),&myFoundDofGIDs[0],&numFoundDofGIDs[0]);
161 
162  // create array containing all DOF GIDs
163  size_t cntFoundDofGIDs = 0;
164  for(int p = 0; p < comm->getSize(); p++) cntFoundDofGIDs += numFoundDofGIDs[p];
165  std::vector<GlobalOrdinal> lFoundDofGIDs(cntFoundDofGIDs,-1); // local version to be filled
166  std::vector<GlobalOrdinal> gFoundDofGIDs(cntFoundDofGIDs,-1); // global version after communication
167  // calculate the offset and fill chunk of memory with local data on each processor
168  size_t cntFoundOffset = 0;
169  for(int p = 0; p < comm->getRank(); p++) cntFoundOffset += numFoundDofGIDs[p];
170  for(size_t k=0; k < Teuchos::as<size_t>(ovlFoundStatusGids.size()); k++) {
171  lFoundDofGIDs[k+cntFoundOffset] = ovlFoundStatusGids[k];
172  }
173  if(cntFoundDofGIDs > 0)
174  Teuchos::reduceAll(*comm,Teuchos::REDUCE_MAX,Teuchos::as<int>(cntFoundDofGIDs),&lFoundDofGIDs[0],&gFoundDofGIDs[0]);
175 
176  Teuchos::Array<GlobalOrdinal> ovlDomainMapArray;
177  for(size_t i = 0; i<input.getColMap()->getNodeNumElements(); i++) {
178  GlobalOrdinal gcid = input.getColMap()->getGlobalElement(i);
179  if(domainMap.isNodeGlobalElement(gcid) == true ||
180  std::find(gFoundDofGIDs.begin(), gFoundDofGIDs.end(), gcid) != gFoundDofGIDs.end()) {
181  ovlDomainMapArray.push_back(gcid);
182  }
183  }
184  RCP<Map> ovlDomainMap = MapFactory::Build (domainMap.lib(),Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(),ovlDomainMapArray(),0,comm);
185  return ovlDomainMap;
186  }
187 
196  static Teuchos::RCP<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> > SplitMatrix(
198  Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node> > rangeMapExtractor,
199  Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node> > domainMapExtractor,
200  Teuchos::RCP<const Xpetra::MapExtractor<Scalar, LocalOrdinal, GlobalOrdinal, Node> > columnMapExtractor = Teuchos::null,
201  bool bThyraMode = false) {
202 
203  size_t numRows = rangeMapExtractor->NumMaps();
204  size_t numCols = domainMapExtractor->NumMaps();
205 
206  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.")
207  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.")
208 
209  RCP<const Map> fullRangeMap = rangeMapExtractor->getFullMap();
210  RCP<const Map> fullDomainMap = domainMapExtractor->getFullMap();
211 
212  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getMaxAllGlobalIndex() != input.getRowMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
213  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getGlobalNumElements() != input.getRowMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
214  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getNodeNumElements() != input.getRowMap()->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
215  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getMaxAllGlobalIndex() != input.getRangeMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
216  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getGlobalNumElements() != input.getRangeMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
217  TEUCHOS_TEST_FOR_EXCEPTION(fullRangeMap->getNodeNumElements() != input.getRangeMap()->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: RangeMapExtractor incompatible to row map of input matrix.")
218 
219  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())
220  TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getMaxAllGlobalIndex() != input.getDomainMap()->getMaxAllGlobalIndex(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
221  TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getGlobalNumElements() != input.getDomainMap()->getGlobalNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
222  TEUCHOS_TEST_FOR_EXCEPTION(fullDomainMap->getNodeNumElements() != input.getDomainMap()->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: DomainMapExtractor incompatible to domain map of input matrix.")
223 
224  // check column map extractor
225  Teuchos::RCP<const MapExtractor> myColumnMapExtractor = Teuchos::null;
226  if(columnMapExtractor == Teuchos::null) {
227  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.");
228  // This code is always executed, since we always provide map extractors in Xpetra numbering!
229  std::vector<Teuchos::RCP<const Map> > ovlxmaps(numCols, Teuchos::null);
230  for(size_t c = 0; c < numCols; c++) {
231  // TODO: is this routine working correctly?
232  Teuchos::RCP<const Map> colMap = MatrixUtils::findColumnSubMap(input, *(domainMapExtractor->getMap(c)));
233  ovlxmaps[c] = colMap;
234  }
235  RCP<const Map> fullColMap = MapUtils::concatenateMaps(ovlxmaps);
236  // This MapExtractor is always in Xpetra mode!
237  myColumnMapExtractor = MapExtractorFactory::Build(fullColMap,ovlxmaps);
238  } else
239  myColumnMapExtractor = columnMapExtractor; // use user-provided column map extractor.
240 
241  // all above MapExtractors are always in Xpetra mode
242  // build separate ones containing Thyra mode GIDs (if necessary)
243  Teuchos::RCP<const MapExtractor> thyRangeMapExtractor = Teuchos::null;
244  Teuchos::RCP<const MapExtractor> thyDomainMapExtractor = Teuchos::null;
245  Teuchos::RCP<const MapExtractor> thyColMapExtractor = Teuchos::null;
246  if(bThyraMode == true) {
247  // build Thyra-style map extractors
248  std::vector<Teuchos::RCP<const Map> > thyRgMapExtractorMaps(numRows, Teuchos::null);
249  for (size_t r = 0; r < numRows; r++) {
250  RCP<const Map> rMap = rangeMapExtractor->getMap(r);
251  RCP<const Map> shrinkedMap = MapUtils::shrinkMapGIDs(*rMap,*rMap);
252  RCP<const StridedMap> strRangeMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rMap);
253  if(strRangeMap != Teuchos::null) {
254  std::vector<size_t> strInfo = strRangeMap->getStridingData();
255  GlobalOrdinal offset = strRangeMap->getOffset();
256  LocalOrdinal stridedBlockId = strRangeMap->getStridedBlockId();
257  RCP<const StridedMap> strShrinkedMap = Teuchos::rcp(new StridedMap(shrinkedMap, strInfo, shrinkedMap->getIndexBase(), stridedBlockId, offset));
258  thyRgMapExtractorMaps[r] = strShrinkedMap;
259  } else {
260  thyRgMapExtractorMaps[r] = shrinkedMap;
261  }
262  TEUCHOS_TEST_FOR_EXCEPTION(thyRgMapExtractorMaps[r]->getNodeNumElements() != rMap->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style range map extractor contains faulty data.")
263  }
264  RCP<const Map> fullThyRangeMap = MapUtils::concatenateMaps(thyRgMapExtractorMaps);
265  thyRangeMapExtractor = MapExtractorFactory::Build(fullThyRangeMap,thyRgMapExtractorMaps,true);
266  std::vector<Teuchos::RCP<const Map> > thyDoMapExtractorMaps (numCols, Teuchos::null);
267  std::vector<Teuchos::RCP<const Map> > thyColMapExtractorMaps(numCols, Teuchos::null);
268  for (size_t c = 0; c < numCols; c++) {
269  RCP<const Map> cMap = domainMapExtractor->getMap(c);
270 
271  RCP<const Map> shrinkedDomainMap = MapUtils::shrinkMapGIDs(*cMap,*cMap);
272  RCP<const StridedMap> strDomainMap = Teuchos::rcp_dynamic_cast<const StridedMap>(cMap);
273  if(strDomainMap != Teuchos::null) {
274  std::vector<size_t> strInfo = strDomainMap->getStridingData();
275  GlobalOrdinal offset = strDomainMap->getOffset();
276  LocalOrdinal stridedBlockId = strDomainMap->getStridedBlockId();
277  RCP<const StridedMap> strShrinkedDomainMap = Teuchos::rcp(new StridedMap(shrinkedDomainMap, strInfo, shrinkedDomainMap->getIndexBase(), stridedBlockId, offset));
278  thyDoMapExtractorMaps[c] = strShrinkedDomainMap;
279  } else {
280  thyDoMapExtractorMaps[c] = shrinkedDomainMap;
281  }
282  RCP<const Map> colMap = myColumnMapExtractor->getMap(c);
283  RCP<const Map> shrinkedColMap = MapUtils::shrinkMapGIDs(*colMap,*cMap);
284  RCP<const StridedMap> strColMap = Teuchos::rcp_dynamic_cast<const StridedMap>(colMap);
285  if(strColMap != Teuchos::null) {
286  std::vector<size_t> strInfo = strColMap->getStridingData();
287  GlobalOrdinal offset = strColMap->getOffset();
288  LocalOrdinal stridedBlockId = strColMap->getStridedBlockId();
289  RCP<const StridedMap> strShrinkedColMap = Teuchos::rcp(new StridedMap(shrinkedColMap, strInfo, shrinkedColMap->getIndexBase(), stridedBlockId, offset));
290  thyColMapExtractorMaps[c] = strShrinkedColMap;
291  } else {
292  thyColMapExtractorMaps[c] = shrinkedColMap;
293  }
294 
295  TEUCHOS_TEST_FOR_EXCEPTION(thyColMapExtractorMaps[c]->getNodeNumElements() != colMap->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style column map extractor contains faulty data.")
296  TEUCHOS_TEST_FOR_EXCEPTION(thyDoMapExtractorMaps[c]->getNodeNumElements() != cMap->getNodeNumElements(), Xpetra::Exceptions::Incompatible, "Xpetra::MatrixUtils::Split: Thyra-style domain map extractor contains faulty data.")
297  }
298  RCP<const Map> fullThyDomainMap = MapUtils::concatenateMaps(thyDoMapExtractorMaps);
299  RCP<const Map> fullThyColumnMap = MapUtils::concatenateMaps(thyColMapExtractorMaps);
300  thyDomainMapExtractor = MapExtractorFactory::Build(fullThyDomainMap,thyDoMapExtractorMaps,true);
301  thyColMapExtractor = MapExtractorFactory::Build(fullThyColumnMap,thyColMapExtractorMaps,true);
302  }
303  // create submatrices
304  std::vector<Teuchos::RCP<Matrix> > subMatrices(numRows*numCols, Teuchos::null);
305  for (size_t r = 0; r < numRows; r++) {
306  for (size_t c = 0; c < numCols; c++) {
307  // create empty CrsMatrix objects
308  // make sure that the submatrices are defined using the right row maps (either Thyra or xpetra style)
309  // Note: we're reserving a little bit too much memory for the submatrices, but should be still reasonable
310  if(bThyraMode == true)
311  subMatrices[r*numCols+c] = MatrixFactory::Build (thyRangeMapExtractor->getMap(r,true),input.getNodeMaxNumRowEntries());
312  else
313  subMatrices[r*numCols+c] = MatrixFactory::Build (rangeMapExtractor->getMap(r),input.getNodeMaxNumRowEntries());
314  }
315  }
316 
317  // We need a vector which lives on the column map of input and stores the block id that the column belongs to.
318  // create a vector on the domain map. Loop over it and fill in the corresponding block id numbers
319  // create a vector on the column map and import the data
320  // Importer: source map is non-overlapping. Target map is overlapping
321  // call colMap.Import(domMap,Importer,Insert)
322  // do the same with "Add" to make sure only one processor is responsible for the different GIDs!
323 #if 0 // TAW needs to be fixed (does not compile for Scalar=complex)
328 
329  RCP<Vector> doCheck = VectorFactory::Build(input.getDomainMap(), true);
330  doCheck->putScalar(1.0);
331  RCP<Vector> coCheck = VectorFactory::Build(input.getColMap(), true);
332  RCP<Import> imp = ImportFactory::Build(input.getDomainMap(), input.getColMap());
333  coCheck->doImport(*doCheck, *imp, Xpetra::ADD);
334  TEUCHOS_TEST_FOR_EXCEPTION(coCheck->normInf() != Teuchos::ScalarTraits< Scalar >::magnitude(1.0), Xpetra::Exceptions::RuntimeError, "Xpetra::MatrixUtils::SplitMatrix: error when distributing data.");
335 
336  doCheck->putScalar(-1.0);
337  coCheck->putScalar(-1.0);
338 
339  Teuchos::ArrayRCP< Scalar > doCheckData = doCheck->getDataNonConst(0);
340  for (size_t rrr = 0; rrr < input.getDomainMap()->getNodeNumElements(); rrr++) {
341  // global row id to extract data from global monolithic matrix
342  GlobalOrdinal id = input.getDomainMap()->getGlobalElement(rrr); // LID -> GID (column)
343 
344  // Find the block id in range map extractor that belongs to same global id.
345  size_t BlockId = domainMapExtractor->getMapIndexForGID(id);
346 
347  doCheckData[rrr] = Teuchos::as<Scalar>(BlockId);
348  }
349 
350  coCheck->doImport(*doCheck, *imp, Xpetra::INSERT);
351 
352  Teuchos::ArrayRCP< Scalar > coCheckData = coCheck->getDataNonConst(0);
353 #endif
354  // loop over all rows of input matrix
355  for (size_t rr = 0; rr < input.getRowMap()->getNodeNumElements(); rr++) {
356 
357  // global row id to extract data from global monolithic matrix
358  GlobalOrdinal growid = input.getRowMap()->getGlobalElement(rr); // LID -> GID (column)
359 
360  // Find the block id in range map extractor that belongs to same global row id.
361  // We assume the global ids to be unique in the map extractor
362  // The MapExtractor objects may be constructed using the thyra mode. However, we use
363  // global GID ids (as we have a single input matrix). The only problematic thing could
364  // be that the GIDs of the input matrix are inconsistent with the GIDs in the map extractor.
365  // Note, that for the Thyra mode the GIDs in the map extractor are generated using the ordering
366  // of the blocks.
367  size_t rowBlockId = rangeMapExtractor->getMapIndexForGID(growid);
368 
369  // global row id used for subblocks to insert information
370  GlobalOrdinal subblock_growid = growid; // for Xpetra-style numbering the global row ids are not changing
371  if(bThyraMode == true) {
372  // find local row id associated with growid in the corresponding subblock
373  LocalOrdinal lrowid = rangeMapExtractor->getMap(rowBlockId)->getLocalElement(growid);
374  // translate back local row id to global row id for the subblock
375  subblock_growid = thyRangeMapExtractor->getMap(rowBlockId,true)->getGlobalElement(lrowid);
376  }
377 
378  // extract matrix entries from input matrix
379  // we use global ids since we have to determine the corresponding
380  // block column ids using the global ids anyway
381  Teuchos::ArrayView<const LocalOrdinal> indices;
382  Teuchos::ArrayView<const Scalar> vals;
383  input.getLocalRowView(rr, indices, vals);
384 
385  std::vector<Teuchos::Array<GlobalOrdinal> > blockColIdx (numCols, Teuchos::Array<GlobalOrdinal>());
386  std::vector<Teuchos::Array<Scalar> > blockColVals(numCols, Teuchos::Array<Scalar>());
387 
388  for(size_t i=0; i<(size_t)indices.size(); i++) {
389  // gobal column id to extract data from full monolithic matrix
390  GlobalOrdinal gcolid = input.getColMap()->getGlobalElement(indices[i]);
391 
392  size_t colBlockId = myColumnMapExtractor->getMapIndexForGID(gcolid); // old buggy thing
393  //size_t colBlockId = Teuchos::as<size_t>(coCheckData[indices[i]]);
394 
395  // global column id used for subblocks to insert information
396  GlobalOrdinal subblock_gcolid = gcolid; // for Xpetra-style numbering the global col ids are not changing
397  if(bThyraMode == true) {
398  // find local col id associated with gcolid in the corresponding subblock
399  LocalOrdinal lcolid = myColumnMapExtractor->getMap(colBlockId)->getLocalElement(gcolid);
400  // translate back local col id to global col id for the subblock
401  subblock_gcolid = thyColMapExtractor->getMap(colBlockId,true)->getGlobalElement(lcolid);
402  }
403  blockColIdx [colBlockId].push_back(subblock_gcolid);
404  blockColVals[colBlockId].push_back(vals[i]);
405  }
406 
407  for (size_t c = 0; c < numCols; c++) {
408  subMatrices[rowBlockId*numCols+c]->insertGlobalValues(subblock_growid,blockColIdx[c].view(0,blockColIdx[c].size()),blockColVals[c].view(0,blockColVals[c].size()));
409  }
410 
411  }
412 
413  // call fill complete on subblocks and create BlockedCrsOperator
414  RCP<BlockedCrsMatrix> bA = Teuchos::null;
415  if(bThyraMode == true) {
416  for (size_t r = 0; r < numRows; r++) {
417  for (size_t c = 0; c < numCols; c++) {
418  subMatrices[r*numCols+c]->fillComplete(thyDomainMapExtractor->getMap(c,true), thyRangeMapExtractor->getMap(r,true));
419  }
420  }
421  bA = Teuchos::rcp(new BlockedCrsMatrix(thyRangeMapExtractor, thyDomainMapExtractor, 10 /*input.getRowMap()->getNodeMaxNumRowEntries()*/));
422  } else {
423  for (size_t r = 0; r < numRows; r++) {
424  for (size_t c = 0; c < numCols; c++) {
425  subMatrices[r*numCols+c]->fillComplete(domainMapExtractor->getMap(c), rangeMapExtractor->getMap(r));
426  }
427  }
428  bA = Teuchos::rcp(new BlockedCrsMatrix(rangeMapExtractor, domainMapExtractor, 10 /*input.getRowMap()->getNodeMaxNumRowEntries()*/));
429  }
430 
431  for (size_t r = 0; r < numRows; r++) {
432  for (size_t c = 0; c < numCols; c++) {
433  bA->setMatrix(r,c,subMatrices[r*numCols+c]);
434  }
435  }
436  return bA;
437  } // SplitMatrix
438 
442  bool const &repairZeroDiagonals, Teuchos::FancyOStream &fos,
443  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType threshold = Teuchos::ScalarTraits<typename Teuchos::ScalarTraits<Scalar>::magnitudeType>::zero())
444  {
445  typedef typename Teuchos::ScalarTraits<Scalar> TST;
446  Scalar one = TST::one();
447 
448  Teuchos::RCP<Teuchos::ParameterList> p = Teuchos::rcp(new Teuchos::ParameterList());
449  p->set("DoOptimizeStorage", true);
450 
451  RCP<const Map> rowMap = Ac->getRowMap();
452  RCP<Vector> diagVec = VectorFactory::Build(rowMap);
453  Ac->getLocalDiagCopy(*diagVec);
454 
455  LocalOrdinal lZeroDiags = 0;
456  Teuchos::ArrayRCP< const Scalar > diagVal = diagVec->getData(0);
457 
458  for (size_t i = 0; i < rowMap->getNodeNumElements(); i++) {
459  if (TST::magnitude(diagVal[i]) <= threshold) {
460  lZeroDiags++;
461  }
462  }
463  GlobalOrdinal gZeroDiags;
464  Teuchos::reduceAll(*(rowMap->getComm()), Teuchos::REDUCE_SUM, Teuchos::as<GlobalOrdinal>(lZeroDiags),
465  Teuchos::outArg(gZeroDiags));
466 
467  if (repairZeroDiagonals && gZeroDiags > 0) {
468  /*
469  TAW: If Ac has empty rows, put a 1 on the diagonal of Ac. Be aware that Ac might have empty rows AND
470  columns. The columns might not exist in the column map at all. It would be nice to add the entries
471  to the original matrix Ac. But then we would have to use insertLocalValues. However we cannot add
472  new entries for local column indices that do not exist in the column map of Ac (at least Epetra is
473  not able to do this). With Tpetra it is also not possible to add new entries after the FillComplete
474  call with a static map, since the column map already exists and the diagonal entries are completely
475  missing. Here we build a diagonal matrix with zeros on the diagonal and ones on the diagonal for
476  the rows where Ac has empty rows We have to build a new matrix to be able to use insertGlobalValues.
477  Then we add the original matrix Ac to our new block diagonal matrix and use the result as new
478  (non-singular) matrix Ac. This is very inefficient.
479 
480  If you know something better, please let me know.
481  */
482  RCP<Matrix> fixDiagMatrix = MatrixFactory::Build(rowMap, 1);
483  Teuchos::Array<GlobalOrdinal> indout(1);
484  Teuchos::Array<Scalar> valout(1);
485  for (size_t r = 0; r < rowMap->getNodeNumElements(); r++) {
486  if (TST::magnitude(diagVal[r]) <= threshold) {
487  GlobalOrdinal grid = rowMap->getGlobalElement(r);
488  indout[0] = grid;
489  valout[0] = one;
490  fixDiagMatrix->insertGlobalValues(grid,indout(), valout());
491  }
492  }
493  {
494  Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("CheckRepairMainDiagonal: fillComplete1"));
495  fixDiagMatrix->fillComplete(Ac->getDomainMap(),Ac->getRangeMap());
496  }
497 
498  RCP<Matrix> newAc;
499  Xpetra::MatrixMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::TwoMatrixAdd(*Ac, false, 1.0, *fixDiagMatrix, false, 1.0, newAc, fos);
500  if (Ac->IsView("stridedMaps"))
501  newAc->CreateView("stridedMaps", Ac);
502 
503  Ac = Teuchos::null; // free singular matrix
504  fixDiagMatrix = Teuchos::null;
505  Ac = newAc; // set fixed non-singular matrix
506 
507  // call fillComplete with optimized storage option set to true
508  // This is necessary for new faster Epetra MM kernels.
509  {
510  Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("CheckRepairMainDiagonal: fillComplete2"));
511  Ac->fillComplete(p);
512  }
513  } // end repair
514 
515 
516 
517  // print some output
518  fos << "CheckRepairMainDiagonal: " << (repairZeroDiagonals ? "repaired " : "found ")
519  << gZeroDiags << " too small entries on main diagonal of Ac." << std::endl;
520 
521 #ifdef HAVE_XPETRA_DEBUG // only for debugging
522  // check whether Ac has been repaired...
523  Ac->getLocalDiagCopy(*diagVec);
524  diagVal = diagVec->getData(0);
525  for (size_t r = 0; r < Ac->getRowMap()->getNodeNumElements(); r++) {
526  if (TST::magnitude(diagVal[r]) <= threshold) {
527  fos << "Error: there are too small entries left on diagonal after repair..." << std::endl;
528  break;
529  }
530  }
531 #endif
532  } //CheckRepairMainDiagonal
533 
534 
535 
543  const Teuchos::ArrayView<const double> & relativeThreshold, Teuchos::FancyOStream &fos)
544  {
545  Teuchos::TimeMonitor m1(*Teuchos::TimeMonitor::getNewTimer("RelativeDiagonalBoost"));
546 
547  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");
548 
549  LocalOrdinal numPDEs = A->GetFixedBlockSize();
550  typedef typename Teuchos::ScalarTraits<Scalar> TST;
551  typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType MT;
552  Scalar zero = TST::zero();
553  Scalar one = TST::one();
554 
555  // Get the diagonal
556  RCP<Vector> diag = VectorFactory::Build(A->getRowMap());
557  A->getLocalDiagCopy(*diag);
558  Teuchos::ArrayRCP< const Scalar > dataVal = diag->getData(0);
559  size_t N = A->getRowMap()->getNodeNumElements();
560 
561  // Compute the diagonal maxes for each PDE
562  std::vector<MT> l_diagMax(numPDEs), g_diagMax(numPDEs);
563  for(size_t i=0; i<N; i++) {
564  int pde = (int) (i % numPDEs);
565  if((int)i < numPDEs)
566  l_diagMax[pde] = TST::magnitude(dataVal[i]);
567  else
568  l_diagMax[pde] = std::max(l_diagMax[pde],TST::magnitude(dataVal[i]));
569  }
570  Teuchos::reduceAll(*A->getRowMap()->getComm(), Teuchos::REDUCE_MAX, numPDEs, l_diagMax.data(), g_diagMax.data() );
571 
572  // Apply the diagonal maxes via matrix-matrix addition
573  RCP<Matrix> boostMatrix = MatrixFactory::Build(A->getRowMap(),1);
574  Teuchos::Array<GlobalOrdinal> index(1);
575  Teuchos::Array<Scalar> value(1);
576  for (size_t i = 0; i<N; i++) {
577  GlobalOrdinal GRID = A->getRowMap()->getGlobalElement(i);
578  int pde = (int) (i % numPDEs);
579  index[0] = GRID;
580  if (TST::magnitude(dataVal[i]) < relativeThreshold[pde] * g_diagMax[pde])
581  value[0] = relativeThreshold[pde] * g_diagMax[pde] - TST::magnitude(dataVal[i]);
582  else
583  value[0] =zero;
584  boostMatrix->insertGlobalValues(GRID,index(),value());
585  }
586  boostMatrix->fillComplete(A->getDomainMap(),A->getRangeMap());
587 
588  // FIXME: We really need an add that lets you "add into"
589  RCP<Matrix> newA;
590  Xpetra::MatrixMatrix<Scalar,LocalOrdinal,GlobalOrdinal,Node>::TwoMatrixAdd(*A,false,one, *boostMatrix,false,one,newA,fos);
591  if (A->IsView("stridedMaps"))
592  newA->CreateView("stridedMaps", A);
593  A = newA;
594  A->fillComplete();
595  }
596 
597 
598  // Extracting the block diagonal of a matrix
601  const UnderlyingLib lib = A.getRowMap()->lib();
602 
603  if(lib == Xpetra::UseEpetra) {
604 #if defined(HAVE_XPETRA_EPETRA)
605  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixUtils::extractBlockDiagonal not available for Epetra."));
606 #endif // HAVE_XPETRA_EPETRA
607  } else if(lib == Xpetra::UseTpetra) {
608 #ifdef HAVE_XPETRA_TPETRA
609  const Tpetra::CrsMatrix<SC,LO,GO,NO> & At = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
610  Tpetra::MultiVector<SC,LO,GO,NO> & Dt = Xpetra::toTpetra(diagonal);
611  Tpetra::Details::extractBlockDiagonal(At,Dt);
612 #endif // HAVE_XPETRA_TPETRA
613  }
614  }
615 
616  // Inverse scaling by a block-diagonal matrix
618  bool doTranspose,
620 
621  const UnderlyingLib lib = blockDiagonal.getMap()->lib();
622 
623  if(lib == Xpetra::UseEpetra) {
624 #if defined(HAVE_XPETRA_EPETRA)
625  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixUtils::inverseScaleBlockDiagonal not available for Epetra."));
626 #endif // HAVE_XPETRA_EPETRA
627  } else if(lib == Xpetra::UseTpetra) {
628 #ifdef HAVE_XPETRA_TPETRA
629  const Tpetra::MultiVector<SC,LO,GO,NO> & Dt = Xpetra::toTpetra(blockDiagonal);
630  Tpetra::MultiVector<SC,LO,GO,NO> & St = Xpetra::toTpetra(toBeScaled);
631  Tpetra::Details::inverseScaleBlockDiagonal(Dt,doTranspose,St);
632 #endif // HAVE_XPETRA_TPETRA
633  }
634  }
635 
637  RCP<const Map> rowMap = A.getRowMap();
638  RCP<const Map> colMap = A.getColMap();
639  RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
640  LO numRows = Teuchos::as<LocalOrdinal>(rowMap->getNodeNumElements());
641  bool fail = false;
642  for (LO rowLID = 0; rowLID < numRows; rowLID++) {
643  GO rowGID = rowMap->getGlobalElement(rowLID);
644  LO colLID = colMap->getLocalElement(rowGID);
645  if (rowLID != colLID) {
646  fail = true;
647  std::cerr << "On rank " << comm->getRank() << ", GID " << rowGID << " is LID " << rowLID << "in the rowmap, but LID " << colLID << " in the column map.\n";
648  }
649  }
650  TEUCHOS_TEST_FOR_EXCEPTION(fail, Exceptions::RuntimeError,
651  "Local parts of row and column map do not match!");
652  }
653 
654 
655 };
656 
657 } // end namespace Xpetra
658 
659 #define XPETRA_MATRIXUTILS_SHORT
660 
661 #endif // PACKAGES_XPETRA_SUP_MATRIX_UTILS_HPP_
virtual size_t getNodeMaxNumRowEntries() const =0
Returns the maximum number of entries across all rows/columns on this node.
static Teuchos::RCP< Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > findColumnSubMap(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &input, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &domainMap)
static void checkLocalRowMapMatchesColMap(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A)
static void RelativeDiagonalBoost(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > &A, const Teuchos::ArrayView< const double > &relativeThreshold, Teuchos::FancyOStream &fos)
static Teuchos::RCP< Xpetra::Vector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node >> &map, bool zeroOut=true)
Constructor specifying the number of non-zeros for all rows.
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.
GlobalOrdinal GO
static RCP< Matrix > Build(const RCP< const Map > &rowMap)
Exception throws to report errors in the internal logical of the program.
LocalOrdinal LO
static void CheckRepairMainDiagonal(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node >> &Ac, bool const &repairZeroDiagonals, Teuchos::FancyOStream &fos, const typename Teuchos::ScalarTraits< Scalar >::magnitudeType threshold=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< Scalar >::magnitudeType >::zero())
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::BlockedCrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > SplitMatrix(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &input, Teuchos::RCP< const Xpetra::MapExtractor< Scalar, LocalOrdinal, GlobalOrdinal, Node > > rangeMapExtractor, Teuchos::RCP< const Xpetra::MapExtractor< Scalar, LocalOrdinal, GlobalOrdinal, Node > > domainMapExtractor, Teuchos::RCP< const Xpetra::MapExtractor< Scalar, LocalOrdinal, GlobalOrdinal, Node > > columnMapExtractor=Teuchos::null, bool bThyraMode=false)
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 bool isNodeGlobalElement(GlobalOrdinal globalIndex) const =0
Whether the given global index is valid for this Map on this process.
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.
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 Teuchos::ArrayRCP< const Scalar > getData(size_t j) const =0
Const view of the local values in a particular vector of this multivector.
virtual Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node > > getMap() const =0
The Map describing the parallel distribution of this object.
virtual size_t getLocalLength() const =0
Local number of rows on the calling process.
static void inverseScaleBlockDiagonal(const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &blockDiagonal, bool doTranspose, Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &toBeScaled)
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...
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
static Teuchos::RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > xpetraGidNumbering2ThyraGidNumbering(const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &input)
std::vector< size_t > getStridingData() const
static Teuchos::RCP< Xpetra::MapExtractor< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Map > &fullmap, const std::vector< Teuchos::RCP< const Map > > &maps, bool bThyraMode=false)
Constructor specifying the Maps.
RCP< const Tpetra::CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > toTpetra(const RCP< const CrsGraph< LocalOrdinal, GlobalOrdinal, Node > > &graph)
Exception throws to report incompatible objects (like maps).
static void extractBlockDiagonal(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &diagonal)
virtual Teuchos::RCP< const Map > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y...
virtual const RCP< const Map > & getRowMap() const
Returns the Map that describes the row distribution in this matrix.
virtual size_t getNumVectors() const =0
Number of columns in the multivector.
virtual UnderlyingLib lib() const =0
Get the library used by this object (Tpetra or Epetra?)
virtual Teuchos::RCP< const Map > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
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.
Xpetra-specific matrix class.
Class that stores a strided map.
static RCP< const Tpetra::CrsMatrix< SC, LO, GO, NO > > Op2TpetraCrs(RCP< Matrix > Op)