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