MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_RebalanceBlockRestrictionFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_REBALANCEBLOCKRESTRICTIONFACTORY_DEF_HPP_
47 #define MUELU_REBALANCEBLOCKRESTRICTIONFACTORY_DEF_HPP_
48 
49 #include <Teuchos_Tuple.hpp>
50 
51 #include "Xpetra_MultiVector.hpp"
52 #include "Xpetra_MultiVectorFactory.hpp"
53 #include "Xpetra_Vector.hpp"
54 #include "Xpetra_VectorFactory.hpp"
55 #include <Xpetra_Matrix.hpp>
57 #include <Xpetra_MapFactory.hpp>
58 #include <Xpetra_MapExtractor.hpp>
60 #include <Xpetra_MatrixFactory.hpp>
61 #include <Xpetra_Import.hpp>
62 #include <Xpetra_ImportFactory.hpp>
63 
65 
66 #include "MueLu_HierarchyUtils.hpp"
68 #include "MueLu_Level.hpp"
69 #include "MueLu_MasterList.hpp"
70 #include "MueLu_Monitor.hpp"
71 #include "MueLu_PerfUtils.hpp"
72 
73 namespace MueLu {
74 
75 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
77  RCP<ParameterList> validParamList = rcp(new ParameterList());
78 
79 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
80  SET_VALID_ENTRY("repartition: use subcommunicators");
81 #undef SET_VALID_ENTRY
82 
83  // validParamList->set< RCP<const FactoryBase> >("repartition: use subcommunicators", Teuchos::null, "test");
84 
85  validParamList->set<RCP<const FactoryBase> >("R", Teuchos::null, "Factory of the restriction operator that need to be rebalanced (only used if type=Restriction)");
86  validParamList->set<RCP<const FactoryBase> >("Importer", Teuchos::null, "Generating factory of the matrix Importer for rebalancing");
87  validParamList->set<RCP<const FactoryBase> >("SubImporters", Teuchos::null, "Generating factory of the matrix sub-Importers for rebalancing");
88  validParamList->set<RCP<const FactoryBase> >("Nullspace", Teuchos::null, "Generating factory of the Nullspace operator");
89 
90  return validParamList;
91 }
92 
93 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
95  FactManager_.push_back(FactManager);
96 }
97 
98 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
100  Input(coarseLevel, "R");
101 
102  std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
103  for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
104  SetFactoryManager fineSFM(rcpFromRef(fineLevel), *it);
105  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), *it);
106 
107  if (!UseSingleSourceImporters_) coarseLevel.DeclareInput("Importer", (*it)->GetFactory("Importer").get(), this);
108  coarseLevel.DeclareInput("Nullspace", (*it)->GetFactory("Nullspace").get(), this);
109  }
110 
111  // Use the non-manager path if the maps / importers are generated in one place
112  if (UseSingleSourceImporters_) {
113  Input(coarseLevel, "SubImporters");
114  }
115 }
116 
117 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
119  FactoryMonitor m(*this, "Build", coarseLevel);
120 
121  RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
122 
123  Teuchos::RCP<Matrix> originalTransferOp = Teuchos::null;
124  originalTransferOp = Get<RCP<Matrix> >(coarseLevel, "R");
125 
127  Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(originalTransferOp);
128  TEUCHOS_TEST_FOR_EXCEPTION(bOriginalTransferOp == Teuchos::null, Exceptions::BadCast, "MueLu::RebalanceBlockTransferFactory::Build: input matrix P or R is not of type BlockedCrsMatrix! error.");
129 
130  RCP<const MapExtractor> rangeMapExtractor = bOriginalTransferOp->getRangeMapExtractor();
131  RCP<const MapExtractor> domainMapExtractor = bOriginalTransferOp->getDomainMapExtractor();
132 
133  // restrict communicator?
134  bool bRestrictComm = false;
135  const ParameterList &pL = GetParameterList();
136  if (pL.get<bool>("repartition: use subcommunicators") == true)
137  bRestrictComm = true;
138 
139  // check if GIDs for full maps have to be sorted:
140  // For the Thyra mode ordering they do not have to be sorted since the GIDs are
141  // numbered as 0...n1,0...,n2 (starting with zero for each subblock). The MapExtractor
142  // generates unique GIDs during the construction.
143  // For Xpetra style, the GIDs have to be reordered. Such that one obtains a ordered
144  // list of GIDs in an increasing ordering. In Xpetra, the GIDs are all unique through
145  // out all submaps.
146  bool bThyraRangeGIDs = rangeMapExtractor->getThyraMode();
147  bool bThyraDomainGIDs = domainMapExtractor->getThyraMode();
148 
149  // rebuild rebalanced blocked P operator
150  std::vector<GO> fullRangeMapVector;
151  std::vector<GO> fullDomainMapVector;
152  std::vector<RCP<const Map> > subBlockRRangeMaps;
153  std::vector<RCP<const Map> > subBlockRDomainMaps;
154  subBlockRRangeMaps.reserve(bOriginalTransferOp->Rows()); // reserve size for block P operators
155  subBlockRDomainMaps.reserve(bOriginalTransferOp->Cols()); // reserve size for block P operators
156 
157  std::vector<Teuchos::RCP<Matrix> > subBlockRebR;
158  subBlockRebR.reserve(bOriginalTransferOp->Cols());
159 
160  std::vector<RCP<const Import> > importers = std::vector<RCP<const Import> >(bOriginalTransferOp->Rows(), Teuchos::null);
161  if (UseSingleSourceImporters_) {
162  importers = Get<std::vector<RCP<const Import> > >(coarseLevel, "SubImporters");
163  }
164 
165  int curBlockId = 0;
166  Teuchos::RCP<const Import> rebalanceImporter;
167  std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
168  for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
169  // begin SubFactoryManager environment
170  SetFactoryManager fineSFM(rcpFromRef(fineLevel), *it);
171  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), *it);
172 
173  if (UseSingleSourceImporters_)
174  rebalanceImporter = importers[curBlockId];
175  else
176  rebalanceImporter = coarseLevel.Get<Teuchos::RCP<const Import> >("Importer", (*it)->GetFactory("Importer").get());
177 
178  // extract matrix block
179  Teuchos::RCP<Matrix> Rii = bOriginalTransferOp->getMatrix(curBlockId, curBlockId);
180 
181  // TODO run this only in the debug version
182  TEUCHOS_TEST_FOR_EXCEPTION(bThyraRangeGIDs == true && Rii->getRowMap()->getMinAllGlobalIndex() != 0,
184  "MueLu::RebalanceBlockRestrictionFactory::Build: inconsistent Thyra GIDs. Thyra global ids for block range " << curBlockId << " start with " << Rii->getRowMap()->getMinAllGlobalIndex() << " but should start with 0");
185  TEUCHOS_TEST_FOR_EXCEPTION(bThyraDomainGIDs == true && Rii->getColMap()->getMinAllGlobalIndex() != 0,
187  "MueLu::RebalanceBlockRestrictionFactory::Build: inconsistent Thyra GIDs. Thyra global ids for block domain " << curBlockId << " start with " << Rii->getColMap()->getMinAllGlobalIndex() << " but should start with 0");
188 
189  Teuchos::RCP<Matrix> rebRii;
190  if (rebalanceImporter != Teuchos::null) {
191  std::stringstream ss;
192  ss << "Rebalancing restriction block R(" << curBlockId << "," << curBlockId << ")";
193  SubFactoryMonitor m1(*this, ss.str(), coarseLevel);
194  {
195  SubFactoryMonitor subM(*this, "Rebalancing restriction -- fusedImport", coarseLevel);
196  // Note: The 3rd argument says to use originalR's domain map.
197 
198  RCP<Map> dummy;
199  rebRii = MatrixFactory::Build(Rii, *rebalanceImporter, dummy, rebalanceImporter->getTargetMap());
200  }
201 
202  RCP<ParameterList> params = rcp(new ParameterList());
203  params->set("printLoadBalancingInfo", true);
204  std::stringstream ss2;
205  ss2 << "R(" << curBlockId << "," << curBlockId << ") rebalanced:";
206  GetOStream(Statistics0) << PerfUtils::PrintMatrixInfo(*rebRii, ss2.str(), params);
207  } else {
208  rebRii = Rii;
209  RCP<ParameterList> params = rcp(new ParameterList());
210  params->set("printLoadBalancingInfo", true);
211  std::stringstream ss2;
212  ss2 << "R(" << curBlockId << "," << curBlockId << ") not rebalanced:";
213  GetOStream(Statistics0) << PerfUtils::PrintMatrixInfo(*rebRii, ss2.str(), params);
214  }
215 
216  // fix striding information for rebalanced diagonal block rebRii
217  Teuchos::RCP<const StridedMap> orig_stridedRgMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rangeMapExtractor->getMap(Teuchos::as<size_t>(curBlockId), rangeMapExtractor->getThyraMode()));
218  Teuchos::RCP<const Map> stridedRgMap = Teuchos::null;
219  if (orig_stridedRgMap != Teuchos::null) {
220  std::vector<size_t> stridingData = orig_stridedRgMap->getStridingData();
221  Teuchos::ArrayView<const GlobalOrdinal> nodeRangeMapii = rebRii->getRangeMap()->getLocalElementList();
222  stridedRgMap = StridedMapFactory::Build(
223  originalTransferOp->getRangeMap()->lib(),
225  nodeRangeMapii,
226  rebRii->getRangeMap()->getIndexBase(),
227  stridingData,
228  originalTransferOp->getRangeMap()->getComm(),
229  orig_stridedRgMap->getStridedBlockId(),
230  orig_stridedRgMap->getOffset());
231  } else
232  stridedRgMap = Rii->getRangeMap();
233 
234  Teuchos::RCP<const StridedMap> orig_stridedDoMap = Teuchos::rcp_dynamic_cast<const StridedMap>(domainMapExtractor->getMap(Teuchos::as<size_t>(curBlockId), domainMapExtractor->getThyraMode()));
235  Teuchos::RCP<const Map> stridedDoMap = Teuchos::null;
236  if (orig_stridedDoMap != Teuchos::null) {
237  std::vector<size_t> stridingData = orig_stridedDoMap->getStridingData();
238  Teuchos::ArrayView<const GlobalOrdinal> nodeDomainMapii = rebRii->getDomainMap()->getLocalElementList();
239  stridedDoMap = StridedMapFactory::Build(
240  originalTransferOp->getDomainMap()->lib(),
242  nodeDomainMapii,
243  rebRii->getDomainMap()->getIndexBase(),
244  stridingData,
245  originalTransferOp->getDomainMap()->getComm(),
246  orig_stridedDoMap->getStridedBlockId(),
247  orig_stridedDoMap->getOffset());
248  } else
249  stridedDoMap = Rii->getDomainMap();
250 
251  if (bRestrictComm) {
252  stridedRgMap->removeEmptyProcesses();
253  stridedDoMap->removeEmptyProcesses();
254  }
255 
256  TEUCHOS_TEST_FOR_EXCEPTION(stridedRgMap == Teuchos::null, Exceptions::RuntimeError, "MueLu::RebalanceBlockRestrictionFactory::Build: failed to generate striding information. error.");
257  TEUCHOS_TEST_FOR_EXCEPTION(stridedDoMap == Teuchos::null, Exceptions::RuntimeError, "MueLu::RebalanceBlockRestrictionFactory::Build: failed to generate striding information. error.");
258 
259  // replace stridedMaps view in diagonal sub block
260  if (rebRii->IsView("stridedMaps")) rebRii->RemoveView("stridedMaps");
261  rebRii->CreateView("stridedMaps", stridedRgMap, stridedDoMap);
262 
263  // store rebalanced subblock
264  subBlockRebR.push_back(rebRii);
265 
266  // append strided row map (= range map) to list of range maps.
267  Teuchos::RCP<const Map> rangeMapii = rebRii->getRowMap("stridedMaps");
268  subBlockRRangeMaps.push_back(rangeMapii);
269  Teuchos::ArrayView<const GlobalOrdinal> nodeRangeMapii = rebRii->getRangeMap()->getLocalElementList();
270  // append the GIDs in the end. Do not sort if we have Thyra style GIDs
271  fullRangeMapVector.insert(fullRangeMapVector.end(), nodeRangeMapii.begin(), nodeRangeMapii.end());
272  if (bThyraRangeGIDs == false)
273  sort(fullRangeMapVector.begin(), fullRangeMapVector.end());
274 
275  // append strided col map (= domain map) to list of range maps.
276  Teuchos::RCP<const Map> domainMapii = rebRii->getColMap("stridedMaps");
277  subBlockRDomainMaps.push_back(domainMapii);
278  Teuchos::ArrayView<const GlobalOrdinal> nodeDomainMapii = rebRii->getDomainMap()->getLocalElementList();
279  // append the GIDs in the end. Do not sort if we have Thyra style GIDs
280  fullDomainMapVector.insert(fullDomainMapVector.end(), nodeDomainMapii.begin(), nodeDomainMapii.end());
281  if (bThyraDomainGIDs == false)
282  sort(fullDomainMapVector.begin(), fullDomainMapVector.end());
283 
285 
286  // rebalance null space
287  // This rebalances the null space partial vector associated with the current block (generated by the NullspaceFactory
288  // associated with the block)
289  if (rebalanceImporter != Teuchos::null) { // rebalance null space
290  std::stringstream ss2;
291  ss2 << "Rebalancing nullspace block(" << curBlockId << "," << curBlockId << ")";
292  SubFactoryMonitor subM(*this, ss2.str(), coarseLevel);
293 
294  RCP<MultiVector> nullspace = coarseLevel.Get<RCP<MultiVector> >("Nullspace", (*it)->GetFactory("Nullspace").get());
295  RCP<MultiVector> permutedNullspace = MultiVectorFactory::Build(rebalanceImporter->getTargetMap(), nullspace->getNumVectors());
296  permutedNullspace->doImport(*nullspace, *rebalanceImporter, Xpetra::INSERT);
297 
298  // TODO subcomm enabled everywhere or nowhere
299  if (bRestrictComm)
300  permutedNullspace->replaceMap(permutedNullspace->getMap()->removeEmptyProcesses());
301 
302  coarseLevel.Set<RCP<MultiVector> >("Nullspace", permutedNullspace, (*it)->GetFactory("Nullspace").get());
303 
304  } // end rebalance null space
305  else { // do nothing
306  RCP<MultiVector> nullspace = coarseLevel.Get<RCP<MultiVector> >("Nullspace", (*it)->GetFactory("Nullspace").get());
307  coarseLevel.Set<RCP<MultiVector> >("Nullspace", nullspace, (*it)->GetFactory("Nullspace").get());
308  }
309 
311 
312  curBlockId++;
313  } // end for loop
314 
315  // extract map index base from maps of blocked P
316  GO rangeIndexBase = originalTransferOp->getRangeMap()->getIndexBase();
317  GO domainIndexBase = originalTransferOp->getDomainMap()->getIndexBase();
318 
319  // check this
320  Teuchos::ArrayView<GO> fullRangeMapGIDs(fullRangeMapVector.size() ? &fullRangeMapVector[0] : 0, fullRangeMapVector.size());
321  Teuchos::RCP<const StridedMap> stridedRgFullMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rangeMapExtractor->getFullMap());
322  Teuchos::RCP<const Map> fullRangeMap = Teuchos::null;
323  if (stridedRgFullMap != Teuchos::null) {
324  std::vector<size_t> stridedData = stridedRgFullMap->getStridingData();
325  fullRangeMap =
326  StridedMapFactory::Build(
327  originalTransferOp->getRangeMap()->lib(),
329  fullRangeMapGIDs,
330  rangeIndexBase,
331  stridedData,
332  originalTransferOp->getRangeMap()->getComm(),
333  stridedRgFullMap->getStridedBlockId(),
334  stridedRgFullMap->getOffset());
335  } else {
336  fullRangeMap =
337  MapFactory::Build(
338  originalTransferOp->getRangeMap()->lib(),
340  fullRangeMapGIDs,
341  rangeIndexBase,
342  originalTransferOp->getRangeMap()->getComm());
343  }
344 
345  Teuchos::ArrayView<GO> fullDomainMapGIDs(fullDomainMapVector.size() ? &fullDomainMapVector[0] : 0, fullDomainMapVector.size());
346  Teuchos::RCP<const StridedMap> stridedDoFullMap = Teuchos::rcp_dynamic_cast<const StridedMap>(domainMapExtractor->getFullMap());
347  Teuchos::RCP<const Map> fullDomainMap = Teuchos::null;
348  if (stridedDoFullMap != Teuchos::null) {
349  TEUCHOS_TEST_FOR_EXCEPTION(stridedDoFullMap == Teuchos::null, Exceptions::BadCast, "MueLu::BlockedPFactory::Build: full map in domain map extractor has no striding information! error.");
350  std::vector<size_t> stridedData2 = stridedDoFullMap->getStridingData();
351  fullDomainMap =
352  StridedMapFactory::Build(
353  originalTransferOp->getDomainMap()->lib(),
355  fullDomainMapGIDs,
356  domainIndexBase,
357  stridedData2,
358  originalTransferOp->getDomainMap()->getComm(),
359  stridedDoFullMap->getStridedBlockId(),
360  stridedDoFullMap->getOffset());
361  } else {
362  fullDomainMap =
363  MapFactory::Build(
364  originalTransferOp->getDomainMap()->lib(),
366  fullDomainMapGIDs,
367  domainIndexBase,
368  originalTransferOp->getDomainMap()->getComm());
369  }
370 
371  if (bRestrictComm) {
372  fullRangeMap->removeEmptyProcesses();
373  fullDomainMap->removeEmptyProcesses();
374  }
375 
376  // build map extractors
377  Teuchos::RCP<const MapExtractor> rebrangeMapExtractor =
378  MapExtractorFactory::Build(fullRangeMap, subBlockRRangeMaps, bThyraRangeGIDs);
379  Teuchos::RCP<const MapExtractor> rebdomainMapExtractor =
380  MapExtractorFactory::Build(fullDomainMap, subBlockRDomainMaps, bThyraDomainGIDs);
381 
382  Teuchos::RCP<BlockedCrsMatrix> bRebR = Teuchos::rcp(new BlockedCrsMatrix(rebrangeMapExtractor, rebdomainMapExtractor, 10));
383  for (size_t i = 0; i < subBlockRRangeMaps.size(); i++) {
384  Teuchos::RCP<CrsMatrixWrap> crsOpii = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(subBlockRebR[i]);
385  bRebR->setMatrix(i, i, crsOpii);
386  }
387 
388  bRebR->fillComplete();
389 
390  Set(coarseLevel, "R", Teuchos::rcp_dynamic_cast<Matrix>(bRebR)); // do nothing // TODO remove this!
391 
392 } // Build
393 
394 } // namespace MueLu
395 
396 #endif /* MUELU_REBALANCEBLOCKRESTRICTIONFACTORY_DEF_HPP_ */
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Specifies the data that this class needs, and the factories that generate that data.
Exception indicating invalid cast attempted.
GlobalOrdinal GO
iterator begin() const
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
T * get() const
void sort(View &view, const size_t &size)
Print statistics that do not involve significant additional computation.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
iterator end() const
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
#define SET_VALID_ENTRY(name)
Exception throws to report errors in the internal logical of the program.
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
An exception safe way to call the method &#39;Level::SetFactoryManager()&#39;.
void AddFactoryManager(RCP< const FactoryManagerBase > FactManager)
Add a factory manager.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()