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 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_REBALANCEBLOCKRESTRICTIONFACTORY_DEF_HPP_
11 #define MUELU_REBALANCEBLOCKRESTRICTIONFACTORY_DEF_HPP_
12 
13 #include <Teuchos_Tuple.hpp>
14 
15 #include "Xpetra_MultiVector.hpp"
16 #include "Xpetra_MultiVectorFactory.hpp"
17 #include "Xpetra_Vector.hpp"
18 #include "Xpetra_VectorFactory.hpp"
19 #include <Xpetra_Matrix.hpp>
21 #include <Xpetra_MapFactory.hpp>
22 #include <Xpetra_MapExtractor.hpp>
24 #include <Xpetra_MatrixFactory.hpp>
25 #include <Xpetra_Import.hpp>
26 #include <Xpetra_ImportFactory.hpp>
27 
29 
30 #include "MueLu_HierarchyUtils.hpp"
32 #include "MueLu_Level.hpp"
33 #include "MueLu_MasterList.hpp"
34 #include "MueLu_Monitor.hpp"
35 #include "MueLu_PerfUtils.hpp"
36 
37 namespace MueLu {
38 
39 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
41  RCP<ParameterList> validParamList = rcp(new ParameterList());
42 
43 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
44  SET_VALID_ENTRY("repartition: use subcommunicators");
45 #undef SET_VALID_ENTRY
46 
47  // validParamList->set< RCP<const FactoryBase> >("repartition: use subcommunicators", Teuchos::null, "test");
48 
49  validParamList->set<RCP<const FactoryBase> >("R", Teuchos::null, "Factory of the restriction operator that need to be rebalanced (only used if type=Restriction)");
50  validParamList->set<RCP<const FactoryBase> >("Importer", Teuchos::null, "Generating factory of the matrix Importer for rebalancing");
51  validParamList->set<RCP<const FactoryBase> >("SubImporters", Teuchos::null, "Generating factory of the matrix sub-Importers for rebalancing");
52  validParamList->set<RCP<const FactoryBase> >("Nullspace", Teuchos::null, "Generating factory of the Nullspace operator");
53 
54  return validParamList;
55 }
56 
57 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
59  FactManager_.push_back(FactManager);
60 }
61 
62 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
64  Input(coarseLevel, "R");
65 
66  std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
67  for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
68  SetFactoryManager fineSFM(rcpFromRef(fineLevel), *it);
69  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), *it);
70 
71  if (!UseSingleSourceImporters_) coarseLevel.DeclareInput("Importer", (*it)->GetFactory("Importer").get(), this);
72  coarseLevel.DeclareInput("Nullspace", (*it)->GetFactory("Nullspace").get(), this);
73  }
74 
75  // Use the non-manager path if the maps / importers are generated in one place
76  if (UseSingleSourceImporters_) {
77  Input(coarseLevel, "SubImporters");
78  }
79 }
80 
81 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83  FactoryMonitor m(*this, "Build", coarseLevel);
84 
85  RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
86 
87  Teuchos::RCP<Matrix> originalTransferOp = Teuchos::null;
88  originalTransferOp = Get<RCP<Matrix> >(coarseLevel, "R");
89 
91  Teuchos::rcp_dynamic_cast<Xpetra::BlockedCrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(originalTransferOp);
92  TEUCHOS_TEST_FOR_EXCEPTION(bOriginalTransferOp == Teuchos::null, Exceptions::BadCast, "MueLu::RebalanceBlockTransferFactory::Build: input matrix P or R is not of type BlockedCrsMatrix! error.");
93 
94  RCP<const MapExtractor> rangeMapExtractor = bOriginalTransferOp->getRangeMapExtractor();
95  RCP<const MapExtractor> domainMapExtractor = bOriginalTransferOp->getDomainMapExtractor();
96 
97  // restrict communicator?
98  bool bRestrictComm = false;
99  const ParameterList &pL = GetParameterList();
100  if (pL.get<bool>("repartition: use subcommunicators") == true)
101  bRestrictComm = true;
102 
103  // check if GIDs for full maps have to be sorted:
104  // For the Thyra mode ordering they do not have to be sorted since the GIDs are
105  // numbered as 0...n1,0...,n2 (starting with zero for each subblock). The MapExtractor
106  // generates unique GIDs during the construction.
107  // For Xpetra style, the GIDs have to be reordered. Such that one obtains a ordered
108  // list of GIDs in an increasing ordering. In Xpetra, the GIDs are all unique through
109  // out all submaps.
110  bool bThyraRangeGIDs = rangeMapExtractor->getThyraMode();
111  bool bThyraDomainGIDs = domainMapExtractor->getThyraMode();
112 
113  // rebuild rebalanced blocked P operator
114  std::vector<GO> fullRangeMapVector;
115  std::vector<GO> fullDomainMapVector;
116  std::vector<RCP<const Map> > subBlockRRangeMaps;
117  std::vector<RCP<const Map> > subBlockRDomainMaps;
118  subBlockRRangeMaps.reserve(bOriginalTransferOp->Rows()); // reserve size for block P operators
119  subBlockRDomainMaps.reserve(bOriginalTransferOp->Cols()); // reserve size for block P operators
120 
121  std::vector<Teuchos::RCP<Matrix> > subBlockRebR;
122  subBlockRebR.reserve(bOriginalTransferOp->Cols());
123 
124  std::vector<RCP<const Import> > importers = std::vector<RCP<const Import> >(bOriginalTransferOp->Rows(), Teuchos::null);
125  if (UseSingleSourceImporters_) {
126  importers = Get<std::vector<RCP<const Import> > >(coarseLevel, "SubImporters");
127  }
128 
129  int curBlockId = 0;
130  Teuchos::RCP<const Import> rebalanceImporter;
131  std::vector<Teuchos::RCP<const FactoryManagerBase> >::const_iterator it;
132  for (it = FactManager_.begin(); it != FactManager_.end(); ++it) {
133  // begin SubFactoryManager environment
134  SetFactoryManager fineSFM(rcpFromRef(fineLevel), *it);
135  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), *it);
136 
137  if (UseSingleSourceImporters_)
138  rebalanceImporter = importers[curBlockId];
139  else
140  rebalanceImporter = coarseLevel.Get<Teuchos::RCP<const Import> >("Importer", (*it)->GetFactory("Importer").get());
141 
142  // extract matrix block
143  Teuchos::RCP<Matrix> Rii = bOriginalTransferOp->getMatrix(curBlockId, curBlockId);
144 
145  // TODO run this only in the debug version
146  TEUCHOS_TEST_FOR_EXCEPTION(bThyraRangeGIDs == true && Rii->getRowMap()->getMinAllGlobalIndex() != 0,
148  "MueLu::RebalanceBlockRestrictionFactory::Build: inconsistent Thyra GIDs. Thyra global ids for block range " << curBlockId << " start with " << Rii->getRowMap()->getMinAllGlobalIndex() << " but should start with 0");
149  TEUCHOS_TEST_FOR_EXCEPTION(bThyraDomainGIDs == true && Rii->getColMap()->getMinAllGlobalIndex() != 0,
151  "MueLu::RebalanceBlockRestrictionFactory::Build: inconsistent Thyra GIDs. Thyra global ids for block domain " << curBlockId << " start with " << Rii->getColMap()->getMinAllGlobalIndex() << " but should start with 0");
152 
153  Teuchos::RCP<Matrix> rebRii;
154  if (rebalanceImporter != Teuchos::null) {
155  std::stringstream ss;
156  ss << "Rebalancing restriction block R(" << curBlockId << "," << curBlockId << ")";
157  SubFactoryMonitor m1(*this, ss.str(), coarseLevel);
158  {
159  SubFactoryMonitor subM(*this, "Rebalancing restriction -- fusedImport", coarseLevel);
160  // Note: The 3rd argument says to use originalR's domain map.
161 
162  RCP<Map> dummy;
163  rebRii = MatrixFactory::Build(Rii, *rebalanceImporter, dummy, rebalanceImporter->getTargetMap());
164  }
165 
166  RCP<ParameterList> params = rcp(new ParameterList());
167  params->set("printLoadBalancingInfo", true);
168  std::stringstream ss2;
169  ss2 << "R(" << curBlockId << "," << curBlockId << ") rebalanced:";
170  GetOStream(Statistics0) << PerfUtils::PrintMatrixInfo(*rebRii, ss2.str(), params);
171  } else {
172  rebRii = Rii;
173  RCP<ParameterList> params = rcp(new ParameterList());
174  params->set("printLoadBalancingInfo", true);
175  std::stringstream ss2;
176  ss2 << "R(" << curBlockId << "," << curBlockId << ") not rebalanced:";
177  GetOStream(Statistics0) << PerfUtils::PrintMatrixInfo(*rebRii, ss2.str(), params);
178  }
179 
180  // fix striding information for rebalanced diagonal block rebRii
181  Teuchos::RCP<const StridedMap> orig_stridedRgMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rangeMapExtractor->getMap(Teuchos::as<size_t>(curBlockId), rangeMapExtractor->getThyraMode()));
182  Teuchos::RCP<const Map> stridedRgMap = Teuchos::null;
183  if (orig_stridedRgMap != Teuchos::null) {
184  std::vector<size_t> stridingData = orig_stridedRgMap->getStridingData();
185  Teuchos::ArrayView<const GlobalOrdinal> nodeRangeMapii = rebRii->getRangeMap()->getLocalElementList();
186  stridedRgMap = StridedMapFactory::Build(
187  originalTransferOp->getRangeMap()->lib(),
189  nodeRangeMapii,
190  rebRii->getRangeMap()->getIndexBase(),
191  stridingData,
192  originalTransferOp->getRangeMap()->getComm(),
193  orig_stridedRgMap->getStridedBlockId(),
194  orig_stridedRgMap->getOffset());
195  } else
196  stridedRgMap = Rii->getRangeMap();
197 
198  Teuchos::RCP<const StridedMap> orig_stridedDoMap = Teuchos::rcp_dynamic_cast<const StridedMap>(domainMapExtractor->getMap(Teuchos::as<size_t>(curBlockId), domainMapExtractor->getThyraMode()));
199  Teuchos::RCP<const Map> stridedDoMap = Teuchos::null;
200  if (orig_stridedDoMap != Teuchos::null) {
201  std::vector<size_t> stridingData = orig_stridedDoMap->getStridingData();
202  Teuchos::ArrayView<const GlobalOrdinal> nodeDomainMapii = rebRii->getDomainMap()->getLocalElementList();
203  stridedDoMap = StridedMapFactory::Build(
204  originalTransferOp->getDomainMap()->lib(),
206  nodeDomainMapii,
207  rebRii->getDomainMap()->getIndexBase(),
208  stridingData,
209  originalTransferOp->getDomainMap()->getComm(),
210  orig_stridedDoMap->getStridedBlockId(),
211  orig_stridedDoMap->getOffset());
212  } else
213  stridedDoMap = Rii->getDomainMap();
214 
215  if (bRestrictComm) {
216  stridedRgMap->removeEmptyProcesses();
217  stridedDoMap->removeEmptyProcesses();
218  }
219 
220  TEUCHOS_TEST_FOR_EXCEPTION(stridedRgMap == Teuchos::null, Exceptions::RuntimeError, "MueLu::RebalanceBlockRestrictionFactory::Build: failed to generate striding information. error.");
221  TEUCHOS_TEST_FOR_EXCEPTION(stridedDoMap == Teuchos::null, Exceptions::RuntimeError, "MueLu::RebalanceBlockRestrictionFactory::Build: failed to generate striding information. error.");
222 
223  // replace stridedMaps view in diagonal sub block
224  if (rebRii->IsView("stridedMaps")) rebRii->RemoveView("stridedMaps");
225  rebRii->CreateView("stridedMaps", stridedRgMap, stridedDoMap);
226 
227  // store rebalanced subblock
228  subBlockRebR.push_back(rebRii);
229 
230  // append strided row map (= range map) to list of range maps.
231  Teuchos::RCP<const Map> rangeMapii = rebRii->getRowMap("stridedMaps");
232  subBlockRRangeMaps.push_back(rangeMapii);
233  Teuchos::ArrayView<const GlobalOrdinal> nodeRangeMapii = rebRii->getRangeMap()->getLocalElementList();
234  // append the GIDs in the end. Do not sort if we have Thyra style GIDs
235  fullRangeMapVector.insert(fullRangeMapVector.end(), nodeRangeMapii.begin(), nodeRangeMapii.end());
236  if (bThyraRangeGIDs == false)
237  sort(fullRangeMapVector.begin(), fullRangeMapVector.end());
238 
239  // append strided col map (= domain map) to list of range maps.
240  Teuchos::RCP<const Map> domainMapii = rebRii->getColMap("stridedMaps");
241  subBlockRDomainMaps.push_back(domainMapii);
242  Teuchos::ArrayView<const GlobalOrdinal> nodeDomainMapii = rebRii->getDomainMap()->getLocalElementList();
243  // append the GIDs in the end. Do not sort if we have Thyra style GIDs
244  fullDomainMapVector.insert(fullDomainMapVector.end(), nodeDomainMapii.begin(), nodeDomainMapii.end());
245  if (bThyraDomainGIDs == false)
246  sort(fullDomainMapVector.begin(), fullDomainMapVector.end());
247 
249 
250  // rebalance null space
251  // This rebalances the null space partial vector associated with the current block (generated by the NullspaceFactory
252  // associated with the block)
253  if (rebalanceImporter != Teuchos::null) { // rebalance null space
254  std::stringstream ss2;
255  ss2 << "Rebalancing nullspace block(" << curBlockId << "," << curBlockId << ")";
256  SubFactoryMonitor subM(*this, ss2.str(), coarseLevel);
257 
258  RCP<MultiVector> nullspace = coarseLevel.Get<RCP<MultiVector> >("Nullspace", (*it)->GetFactory("Nullspace").get());
259  RCP<MultiVector> permutedNullspace = MultiVectorFactory::Build(rebalanceImporter->getTargetMap(), nullspace->getNumVectors());
260  permutedNullspace->doImport(*nullspace, *rebalanceImporter, Xpetra::INSERT);
261 
262  // TODO subcomm enabled everywhere or nowhere
263  if (bRestrictComm)
264  permutedNullspace->replaceMap(permutedNullspace->getMap()->removeEmptyProcesses());
265 
266  coarseLevel.Set<RCP<MultiVector> >("Nullspace", permutedNullspace, (*it)->GetFactory("Nullspace").get());
267 
268  } // end rebalance null space
269  else { // do nothing
270  RCP<MultiVector> nullspace = coarseLevel.Get<RCP<MultiVector> >("Nullspace", (*it)->GetFactory("Nullspace").get());
271  coarseLevel.Set<RCP<MultiVector> >("Nullspace", nullspace, (*it)->GetFactory("Nullspace").get());
272  }
273 
275 
276  curBlockId++;
277  } // end for loop
278 
279  // extract map index base from maps of blocked P
280  GO rangeIndexBase = originalTransferOp->getRangeMap()->getIndexBase();
281  GO domainIndexBase = originalTransferOp->getDomainMap()->getIndexBase();
282 
283  // check this
284  Teuchos::ArrayView<GO> fullRangeMapGIDs(fullRangeMapVector.size() ? &fullRangeMapVector[0] : 0, fullRangeMapVector.size());
285  Teuchos::RCP<const StridedMap> stridedRgFullMap = Teuchos::rcp_dynamic_cast<const StridedMap>(rangeMapExtractor->getFullMap());
286  Teuchos::RCP<const Map> fullRangeMap = Teuchos::null;
287  if (stridedRgFullMap != Teuchos::null) {
288  std::vector<size_t> stridedData = stridedRgFullMap->getStridingData();
289  fullRangeMap =
290  StridedMapFactory::Build(
291  originalTransferOp->getRangeMap()->lib(),
293  fullRangeMapGIDs,
294  rangeIndexBase,
295  stridedData,
296  originalTransferOp->getRangeMap()->getComm(),
297  stridedRgFullMap->getStridedBlockId(),
298  stridedRgFullMap->getOffset());
299  } else {
300  fullRangeMap =
301  MapFactory::Build(
302  originalTransferOp->getRangeMap()->lib(),
304  fullRangeMapGIDs,
305  rangeIndexBase,
306  originalTransferOp->getRangeMap()->getComm());
307  }
308 
309  Teuchos::ArrayView<GO> fullDomainMapGIDs(fullDomainMapVector.size() ? &fullDomainMapVector[0] : 0, fullDomainMapVector.size());
310  Teuchos::RCP<const StridedMap> stridedDoFullMap = Teuchos::rcp_dynamic_cast<const StridedMap>(domainMapExtractor->getFullMap());
311  Teuchos::RCP<const Map> fullDomainMap = Teuchos::null;
312  if (stridedDoFullMap != Teuchos::null) {
313  TEUCHOS_TEST_FOR_EXCEPTION(stridedDoFullMap == Teuchos::null, Exceptions::BadCast, "MueLu::BlockedPFactory::Build: full map in domain map extractor has no striding information! error.");
314  std::vector<size_t> stridedData2 = stridedDoFullMap->getStridingData();
315  fullDomainMap =
316  StridedMapFactory::Build(
317  originalTransferOp->getDomainMap()->lib(),
319  fullDomainMapGIDs,
320  domainIndexBase,
321  stridedData2,
322  originalTransferOp->getDomainMap()->getComm(),
323  stridedDoFullMap->getStridedBlockId(),
324  stridedDoFullMap->getOffset());
325  } else {
326  fullDomainMap =
327  MapFactory::Build(
328  originalTransferOp->getDomainMap()->lib(),
330  fullDomainMapGIDs,
331  domainIndexBase,
332  originalTransferOp->getDomainMap()->getComm());
333  }
334 
335  if (bRestrictComm) {
336  fullRangeMap->removeEmptyProcesses();
337  fullDomainMap->removeEmptyProcesses();
338  }
339 
340  // build map extractors
341  Teuchos::RCP<const MapExtractor> rebrangeMapExtractor =
342  MapExtractorFactory::Build(fullRangeMap, subBlockRRangeMaps, bThyraRangeGIDs);
343  Teuchos::RCP<const MapExtractor> rebdomainMapExtractor =
344  MapExtractorFactory::Build(fullDomainMap, subBlockRDomainMaps, bThyraDomainGIDs);
345 
346  Teuchos::RCP<BlockedCrsMatrix> bRebR = Teuchos::rcp(new BlockedCrsMatrix(rebrangeMapExtractor, rebdomainMapExtractor, 10));
347  for (size_t i = 0; i < subBlockRRangeMaps.size(); i++) {
348  Teuchos::RCP<CrsMatrixWrap> crsOpii = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(subBlockRebR[i]);
349  bRebR->setMatrix(i, i, crsOpii);
350  }
351 
352  bRebR->fillComplete();
353 
354  Set(coarseLevel, "R", Teuchos::rcp_dynamic_cast<Matrix>(bRebR)); // do nothing // TODO remove this!
355 
356 } // Build
357 
358 } // namespace MueLu
359 
360 #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)
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
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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:63
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()