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