MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_BlockedPFactory_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_BLOCKEDPFACTORY_DEF_HPP_
11 #define MUELU_BLOCKEDPFACTORY_DEF_HPP_
12 
13 #include <Xpetra_MultiVectorFactory.hpp>
14 #include <Xpetra_VectorFactory.hpp>
15 #include <Xpetra_ImportFactory.hpp>
16 #include <Xpetra_ExportFactory.hpp>
17 #include <Xpetra_CrsMatrixWrap.hpp>
18 
20 #include <Xpetra_Map.hpp>
21 #include <Xpetra_MapFactory.hpp>
22 #include <Xpetra_MapExtractor.hpp>
24 
26 #include "MueLu_FactoryBase.hpp"
27 #include "MueLu_FactoryManager.hpp"
28 #include "MueLu_Monitor.hpp"
29 #include "MueLu_HierarchyUtils.hpp"
30 
31 namespace MueLu {
32 
33 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35  RCP<ParameterList> validParamList = rcp(new ParameterList());
36 
37  validParamList->set<RCP<const FactoryBase> >("A", null, "Generating factory of the matrix A (block matrix)");
38  validParamList->set<bool>("backwards", false, "Forward/backward order");
39 
40  return validParamList;
41 }
42 
43 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
45  Input(fineLevel, "A");
46 
47  const ParameterList& pL = GetParameterList();
48  const bool backwards = pL.get<bool>("backwards");
49 
50  const int numFactManagers = FactManager_.size();
51  for (int k = 0; k < numFactManagers; k++) {
52  int i = (backwards ? numFactManagers - 1 - k : k);
53  const RCP<const FactoryManagerBase>& factManager = FactManager_[i];
54 
55  SetFactoryManager fineSFM(rcpFromRef(fineLevel), factManager);
56  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), factManager);
57 
58  if (!restrictionMode_)
59  coarseLevel.DeclareInput("P", factManager->GetFactory("P").get(), this);
60  else
61  coarseLevel.DeclareInput("R", factManager->GetFactory("R").get(), this);
62  }
63 }
64 
65 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
66 void BlockedPFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildP(Level& /* fineLevel */, Level& /* coarseLevel */) const {}
67 
68 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
70  FactoryMonitor m(*this, "Build", coarseLevel);
71 
72  RCP<Matrix> Ain = Get<RCP<Matrix> >(fineLevel, "A");
73 
74  RCP<BlockedCrsMatrix> A = rcp_dynamic_cast<BlockedCrsMatrix>(Ain);
75  TEUCHOS_TEST_FOR_EXCEPTION(A.is_null(), Exceptions::BadCast, "Input matrix A is not a BlockedCrsMatrix.");
76 
77  const int numFactManagers = FactManager_.size();
78 
79  // Plausibility check
80  TEUCHOS_TEST_FOR_EXCEPTION(A->Rows() != as<size_t>(numFactManagers), Exceptions::RuntimeError,
81  "Number of block rows [" << A->Rows() << "] does not match the number of SubFactorManagers [" << numFactManagers << "]");
82  TEUCHOS_TEST_FOR_EXCEPTION(A->Cols() != as<size_t>(numFactManagers), Exceptions::RuntimeError,
83  "Number of block cols [" << A->Cols() << "] does not match the number of SubFactorManagers [" << numFactManagers << "]");
84 
85  // Build blocked prolongator
86  std::vector<RCP<Matrix> > subBlockP(numFactManagers);
87  std::vector<RCP<const Map> > subBlockPRangeMaps(numFactManagers);
88  std::vector<RCP<const Map> > subBlockPDomainMaps(numFactManagers);
89 
90  std::vector<GO> fullRangeMapVector;
91  std::vector<GO> fullDomainMapVector;
92 
93  RCP<const MapExtractor> rangeAMapExtractor = A->getRangeMapExtractor();
94  RCP<const MapExtractor> domainAMapExtractor = A->getDomainMapExtractor();
95 
96  const ParameterList& pL = GetParameterList();
97  const bool backwards = pL.get<bool>("backwards");
98 
99  // Build and store the subblocks and the corresponding range and domain
100  // maps. Since we put together the full range and domain map from the
101  // submaps, we do not have to use the maps from blocked A
102  for (int k = 0; k < numFactManagers; k++) {
103  int i = (backwards ? numFactManagers - 1 - k : k);
104  if (restrictionMode_)
105  GetOStream(Runtime1) << "Generating R for block " << k << "/" << numFactManagers << std::endl;
106  else
107  GetOStream(Runtime1) << "Generating P for block " << k << "/" << numFactManagers << std::endl;
108 
109  const RCP<const FactoryManagerBase>& factManager = FactManager_[i];
110 
111  SetFactoryManager fineSFM(rcpFromRef(fineLevel), factManager);
112  SetFactoryManager coarseSFM(rcpFromRef(coarseLevel), factManager);
113 
114  if (!restrictionMode_)
115  subBlockP[i] = coarseLevel.Get<RCP<Matrix> >("P", factManager->GetFactory("P").get());
116  else
117  subBlockP[i] = coarseLevel.Get<RCP<Matrix> >("R", factManager->GetFactory("R").get());
118 
119  // Check if prolongator/restrictor operators have strided maps
120  TEUCHOS_TEST_FOR_EXCEPTION(subBlockP[i]->IsView("stridedMaps") == false, Exceptions::BadCast,
121  "subBlock P operator [" << i << "] has no strided map information.");
122 
123  // Append strided row map (= range map) to list of range maps.
124  // TAW the row map GIDs extracted here represent the actual row map GIDs.
125  // No support for nested operators! (at least if Thyra style gids are used)
126  RCP<const StridedMap> strPartialMap = Teuchos::rcp_dynamic_cast<const StridedMap>(subBlockP[i]->getRowMap("stridedMaps"));
127  std::vector<size_t> stridedRgData = strPartialMap->getStridingData();
128  subBlockPRangeMaps[i] = StridedMapFactory::Build(
129  subBlockP[i]->getRangeMap(), // actual global IDs (Thyra or Xpetra)
130  stridedRgData,
131  strPartialMap->getStridedBlockId(),
132  strPartialMap->getOffset());
133  // subBlockPRangeMaps[i] = subBlockP[i]->getRowMap("stridedMaps");
134 
135  // Use plain range map to determine the DOF ids
136  ArrayView<const GO> nodeRangeMap = subBlockPRangeMaps[i]->getLocalElementList();
137  fullRangeMapVector.insert(fullRangeMapVector.end(), nodeRangeMap.begin(), nodeRangeMap.end());
138 
139  // Append strided col map (= domain map) to list of range maps.
140  RCP<const StridedMap> strPartialMap2 = Teuchos::rcp_dynamic_cast<const StridedMap>(subBlockP[i]->getColMap("stridedMaps"));
141  std::vector<size_t> stridedRgData2 = strPartialMap2->getStridingData();
142  subBlockPDomainMaps[i] = StridedMapFactory::Build(
143  subBlockP[i]->getDomainMap(), // actual global IDs (Thyra or Xpetra)
144  stridedRgData2,
145  strPartialMap2->getStridedBlockId(),
146  strPartialMap2->getOffset());
147  // subBlockPDomainMaps[i] = subBlockP[i]->getColMap("stridedMaps");
148 
149  // Use plain domain map to determine the DOF ids
150  ArrayView<const GO> nodeDomainMap = subBlockPDomainMaps[i]->getLocalElementList();
151  fullDomainMapVector.insert(fullDomainMapVector.end(), nodeDomainMap.begin(), nodeDomainMap.end());
152  }
153 
154  // check if GIDs for full maps have to be sorted:
155  // For the Thyra mode ordering they do not have to be sorted since the GIDs are
156  // numbered as 0...n1,0...,n2 (starting with zero for each subblock). The MapExtractor
157  // generates unique GIDs during the construction.
158  // For Xpetra style, the GIDs have to be reordered. Such that one obtains a ordered
159  // list of GIDs in an increasing ordering. In Xpetra, the GIDs are all unique through
160  // out all submaps.
161  bool bDoSortRangeGIDs = rangeAMapExtractor->getThyraMode() ? false : true;
162  bool bDoSortDomainGIDs = domainAMapExtractor->getThyraMode() ? false : true;
163 
164  if (bDoSortRangeGIDs) {
165  sort(fullRangeMapVector.begin(), fullRangeMapVector.end());
166  fullRangeMapVector.erase(std::unique(fullRangeMapVector.begin(), fullRangeMapVector.end()), fullRangeMapVector.end());
167  }
168  if (bDoSortDomainGIDs) {
169  sort(fullDomainMapVector.begin(), fullDomainMapVector.end());
170  fullDomainMapVector.erase(std::unique(fullDomainMapVector.begin(), fullDomainMapVector.end()), fullDomainMapVector.end());
171  }
172 
173  // extract map index base from maps of blocked A
174  GO rangeIndexBase = 0;
175  GO domainIndexBase = 0;
176  if (!restrictionMode_) {
177  // Prolongation mode: just use index base of range and domain map of A
178  rangeIndexBase = A->getRangeMap()->getIndexBase();
179  domainIndexBase = A->getDomainMap()->getIndexBase();
180 
181  } else {
182  // Restriction mode: switch range and domain map for blocked restriction operator
183  rangeIndexBase = A->getDomainMap()->getIndexBase();
184  domainIndexBase = A->getRangeMap()->getIndexBase();
185  }
186 
187  // Build full range map.
188  // If original range map has striding information, then transfer it to the
189  // new range map
190  RCP<const StridedMap> stridedRgFullMap = rcp_dynamic_cast<const StridedMap>(rangeAMapExtractor->getFullMap());
191  RCP<const Map> fullRangeMap = Teuchos::null;
192 
193  ArrayView<GO> fullRangeMapGIDs(fullRangeMapVector.size() ? &fullRangeMapVector[0] : 0, fullRangeMapVector.size());
194  if (stridedRgFullMap != Teuchos::null) {
195  std::vector<size_t> stridedData = stridedRgFullMap->getStridingData();
196  fullRangeMap = StridedMapFactory::Build(
197  A->getRangeMap()->lib(),
199  fullRangeMapGIDs,
200  rangeIndexBase,
201  stridedData,
202  A->getRangeMap()->getComm(),
203  -1, /* the full map vector should always have strided block id -1! */
204  stridedRgFullMap->getOffset());
205  } else {
206  fullRangeMap = MapFactory::Build(
207  A->getRangeMap()->lib(),
209  fullRangeMapGIDs,
210  rangeIndexBase,
211  A->getRangeMap()->getComm());
212  }
213 
214  ArrayView<GO> fullDomainMapGIDs(fullDomainMapVector.size() ? &fullDomainMapVector[0] : 0, fullDomainMapVector.size());
215  RCP<const StridedMap> stridedDoFullMap = rcp_dynamic_cast<const StridedMap>(domainAMapExtractor->getFullMap());
216  RCP<const Map> fullDomainMap = null;
217  if (stridedDoFullMap != null) {
218  TEUCHOS_TEST_FOR_EXCEPTION(stridedDoFullMap == Teuchos::null, Exceptions::BadCast,
219  "MueLu::BlockedPFactory::Build: full map in domain map extractor has no striding information!");
220 
221  std::vector<size_t> stridedData2 = stridedDoFullMap->getStridingData();
222  fullDomainMap = StridedMapFactory::Build(
223  A->getDomainMap()->lib(),
225  fullDomainMapGIDs,
226  domainIndexBase,
227  stridedData2,
228  A->getDomainMap()->getComm(),
229  -1, /* the full map vector should always have strided block id -1! */
230  stridedDoFullMap->getOffset());
231  } else {
232  fullDomainMap = MapFactory::Build(
233  A->getDomainMap()->lib(),
235  fullDomainMapGIDs,
236  domainIndexBase,
237  A->getDomainMap()->getComm());
238  }
239 
240  // Build map extractors
241  RCP<const MapExtractor> rangeMapExtractor = MapExtractorFactory::Build(fullRangeMap, subBlockPRangeMaps, rangeAMapExtractor->getThyraMode());
242  RCP<const MapExtractor> domainMapExtractor = MapExtractorFactory::Build(fullDomainMap, subBlockPDomainMaps, domainAMapExtractor->getThyraMode());
243 
244  RCP<BlockedCrsMatrix> P = rcp(new BlockedCrsMatrix(rangeMapExtractor, domainMapExtractor, 10));
245  for (size_t i = 0; i < subBlockPRangeMaps.size(); i++)
246  for (size_t j = 0; j < subBlockPRangeMaps.size(); j++)
247  if (i == j) {
248  RCP<CrsMatrixWrap> crsOpii = rcp_dynamic_cast<CrsMatrixWrap>(subBlockP[i]);
250  "Block [" << i << "," << j << "] must be of type CrsMatrixWrap.");
251  P->setMatrix(i, i, crsOpii);
252  } else {
253  P->setMatrix(i, j, Teuchos::null);
254  }
255 
256  P->fillComplete();
257 
258  // Level Set
259  if (!restrictionMode_) {
260  // Prolongation mode
261  coarseLevel.Set("P", rcp_dynamic_cast<Matrix>(P), this);
262  // Stick the CoarseMap on the level if somebody wants it (useful for repartitioning)
263  coarseLevel.Set("CoarseMap", P->getBlockedDomainMap(), this);
264  } else {
265  // Restriction mode
266  // We do not have to transpose the blocked R operator since the subblocks
267  // on the diagonal are already valid R subblocks
268  coarseLevel.Set("R", Teuchos::rcp_dynamic_cast<Matrix>(P), this);
269  }
270 }
271 
272 } // namespace MueLu
273 
274 #endif /* MUELU_BLOCKEDPFACTORY_DEF_HPP_ */
Exception indicating invalid cast attempted.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level-&gt;Get&lt; RCP&lt;Matrix&gt; &gt;(&quot;A&quot;, factory) if factory == NULL =&gt; use default factory.
GlobalOrdinal GO
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)
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)
virtual const RCP< const FactoryBase > GetFactory(const std::string &varName) const =0
Get.
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
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
void BuildP(Level &fineLevel, Level &coarseLevel) const
Abstract Build method.
Exception throws to report errors in the internal logical of the program.
An exception safe way to call the method &#39;Level::SetFactoryManager()&#39;.
Description of what is happening (more verbose)
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
void Build(Level &fineLevel, Level &coarseLevel) const
Build method.