MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_SubBlockAFactory_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_SUBBLOCKAFACTORY_DEF_HPP_
48 #define MUELU_SUBBLOCKAFACTORY_DEF_HPP_
49 
51 
53 #include <Xpetra_MapExtractor.hpp>
54 #include <Xpetra_Matrix.hpp>
55 #include <Xpetra_StridedMapFactory.hpp>
56 
57 #include "MueLu_Level.hpp"
58 #include "MueLu_Monitor.hpp"
59 
60 namespace MueLu {
61 
62 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
64  RCP<ParameterList> validParamList = rcp(new ParameterList());
65 
66  validParamList->set<RCP<const FactoryBase>>("A", MueLu::NoFactory::getRCP(), "Generating factory for A.");
67 
68  validParamList->set<int>("block row", 0, "Block row of subblock matrix A");
69  validParamList->set<int>("block col", 0, "Block column of subblock matrix A");
70 
71  validParamList->set<std::string>("Range map: Striding info", "{}", "Striding information for range map");
72  validParamList->set<LocalOrdinal>("Range map: Strided block id", -1, "Strided block id for range map");
73  validParamList->set<std::string>("Domain map: Striding info", "{}", "Striding information for domain map");
74  validParamList->set<LocalOrdinal>("Domain map: Strided block id", -1, "Strided block id for domain map");
75 
76  return validParamList;
77 }
78 
79 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81  Input(currentLevel, "A");
82 }
83 
84 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
86  FactoryMonitor m(*this, "Build", currentLevel);
87 
88  const ParameterList& pL = GetParameterList();
89  size_t row = Teuchos::as<size_t>(pL.get<int>("block row"));
90  size_t col = Teuchos::as<size_t>(pL.get<int>("block col"));
91 
92  RCP<Matrix> Ain = currentLevel.Get<RCP<Matrix>>("A", this->GetFactory("A").get());
93  RCP<BlockedCrsMatrix> A = rcp_dynamic_cast<BlockedCrsMatrix>(Ain);
94 
95  TEUCHOS_TEST_FOR_EXCEPTION(A.is_null(), Exceptions::BadCast, "Input matrix A is not a BlockedCrsMatrix.");
96  TEUCHOS_TEST_FOR_EXCEPTION(row > A->Rows(), Exceptions::RuntimeError, "row [" << row << "] > A.Rows() [" << A->Rows() << "].");
97  TEUCHOS_TEST_FOR_EXCEPTION(col > A->Cols(), Exceptions::RuntimeError, "col [" << col << "] > A.Cols() [" << A->Cols() << "].");
98 
99  // get sub-matrix
100  RCP<Matrix> Op = A->getMatrix(row, col);
101 
102  // Check if it is a BlockedCrsMatrix object
103  // If it is a BlockedCrsMatrix object (most likely a ReorderedBlockedCrsMatrix)
104  // we have to distinguish whether it is a 1x1 leaf block in the ReorderedBlockedCrsMatrix
105  // or a nxm block. If it is a 1x1 leaf block, we "unpack" it and return the underlying
106  // CrsMatrixWrap object.
107  RCP<BlockedCrsMatrix> bOp = rcp_dynamic_cast<BlockedCrsMatrix>(Op);
108  if (bOp != Teuchos::null) {
109  // check if it is a 1x1 leaf block
110  if (bOp->Rows() == 1 && bOp->Cols() == 1) {
111  // return the unwrapped CrsMatrixWrap object underneath
112  Op = bOp->getCrsMatrix();
113  TEUCHOS_TEST_FOR_EXCEPTION(rcp_dynamic_cast<CrsMatrixWrap>(Op) == Teuchos::null, Exceptions::BadCast,
114  "SubBlockAFactory::Build: sub block A[" << row << "," << col << "] must be a single block CrsMatrixWrap object!");
115  } else {
116  // If it is a regular nxm blocked operator, just return it.
117  // We do not set any kind of striding or blocking information as this
118  // usually would not make sense for general blocked operators
119  GetOStream(Statistics1) << "A(" << row << "," << col << ") is a " << bOp->Rows() << "x" << bOp->Cols() << " block matrix" << std::endl;
120  GetOStream(Statistics2) << "with altogether " << bOp->getGlobalNumRows() << "x" << bOp->getGlobalNumCols() << " rows and columns." << std::endl;
121  currentLevel.Set("A", Op, this);
122  return;
123  }
124  }
125 
126  // The sub-block is not a BlockedCrsMatrix object, that is, we expect
127  // it to be of type CrsMatrixWrap allowing direct access to the corresponding
128  // data. For a single block CrsMatrixWrap type matrix we can/should set the
129  // corresponding striding/blocking information for the algorithms to work
130  // properly.
131  //
132  // TAW: In fact, a 1x1 BlockedCrsMatrix object also allows to access the data
133  // directly, but this feature is nowhere really used in the algorithms.
134  // So let's keep checking for the CrsMatrixWrap class to avoid screwing
135  // things up
136  //
137  TEUCHOS_TEST_FOR_EXCEPTION(rcp_dynamic_cast<CrsMatrixWrap>(Op) == Teuchos::null, Exceptions::BadCast,
138  "SubBlockAFactory::Build: sub block A[" << row << "," << col << "] is NOT a BlockedCrsMatrix, but also NOT a CrsMatrixWrap object. This cannot be.");
139 
140  // strided maps for range and domain map of sub matrix
141  RCP<const StridedMap> stridedRangeMap = Teuchos::null;
142  RCP<const StridedMap> stridedDomainMap = Teuchos::null;
143 
144  // check for user-specified striding information from XML file
145  std::vector<size_t> rangeStridingInfo;
146  std::vector<size_t> domainStridingInfo;
147  LocalOrdinal rangeStridedBlockId = 0;
148  LocalOrdinal domainStridedBlockId = 0;
149  bool bRangeUserSpecified = CheckForUserSpecifiedBlockInfo(true, rangeStridingInfo, rangeStridedBlockId);
150  bool bDomainUserSpecified = CheckForUserSpecifiedBlockInfo(false, domainStridingInfo, domainStridedBlockId);
151  TEUCHOS_TEST_FOR_EXCEPTION(bRangeUserSpecified != bDomainUserSpecified, Exceptions::RuntimeError,
152  "MueLu::SubBlockAFactory[" << row << "," << col << "]: the user has to specify either both domain and range map or none.");
153 
154  // extract map information from MapExtractor
155  RCP<const MapExtractor> rangeMapExtractor = A->getRangeMapExtractor();
156  RCP<const MapExtractor> domainMapExtractor = A->getDomainMapExtractor();
157 
158  RCP<const Map> rangeMap = rangeMapExtractor->getMap(row);
159  RCP<const Map> domainMap = domainMapExtractor->getMap(col);
160 
161  // use user-specified striding information if available. Otherwise try to use internal striding information from the submaps!
162  if (bRangeUserSpecified)
163  stridedRangeMap = rcp(new StridedMap(rangeMap, rangeStridingInfo, rangeMap->getIndexBase(), rangeStridedBlockId, 0));
164  else
165  stridedRangeMap = rcp_dynamic_cast<const StridedMap>(rangeMap);
166 
167  if (bDomainUserSpecified)
168  stridedDomainMap = rcp(new StridedMap(domainMap, domainStridingInfo, domainMap->getIndexBase(), domainStridedBlockId, 0));
169  else
170  stridedDomainMap = rcp_dynamic_cast<const StridedMap>(domainMap);
171 
172  // In case that both user-specified and internal striding information from the submaps
173  // does not contain valid striding information, try to extract it from the global maps
174  // in the map extractor.
175  if (stridedRangeMap.is_null()) {
176  RCP<const Map> fullRangeMap = rangeMapExtractor->getFullMap();
177  RCP<const StridedMap> stridedFullRangeMap = rcp_dynamic_cast<const StridedMap>(fullRangeMap);
178  TEUCHOS_TEST_FOR_EXCEPTION(stridedFullRangeMap.is_null(), Exceptions::BadCast, "Full rangeMap is not a strided map.");
179 
180  std::vector<size_t> stridedData = stridedFullRangeMap->getStridingData();
181  if (stridedData.size() == 1 && row > 0) {
182  // We have block matrices. use striding block information 0
183  stridedRangeMap = StridedMapFactory::Build(rangeMap, stridedData, 0, stridedFullRangeMap->getOffset());
184 
185  } else {
186  // We have strided matrices. use striding information of the corresponding block
187  stridedRangeMap = StridedMapFactory::Build(rangeMap, stridedData, row, stridedFullRangeMap->getOffset());
188  }
189  }
190 
191  if (stridedDomainMap.is_null()) {
192  RCP<const Map> fullDomainMap = domainMapExtractor->getFullMap();
193  RCP<const StridedMap> stridedFullDomainMap = rcp_dynamic_cast<const StridedMap>(fullDomainMap);
194  TEUCHOS_TEST_FOR_EXCEPTION(stridedFullDomainMap.is_null(), Exceptions::BadCast, "Full domainMap is not a strided map");
195 
196  std::vector<size_t> stridedData = stridedFullDomainMap->getStridingData();
197  if (stridedData.size() == 1 && col > 0) {
198  // We have block matrices. use striding block information 0
199  stridedDomainMap = StridedMapFactory::Build(domainMap, stridedData, 0, stridedFullDomainMap->getOffset());
200 
201  } else {
202  // We have strided matrices. use striding information of the corresponding block
203  stridedDomainMap = StridedMapFactory::Build(domainMap, stridedData, col, stridedFullDomainMap->getOffset());
204  }
205  }
206 
207  TEUCHOS_TEST_FOR_EXCEPTION(stridedRangeMap.is_null(), Exceptions::BadCast, "rangeMap " << row << " is not a strided map.");
208  TEUCHOS_TEST_FOR_EXCEPTION(stridedDomainMap.is_null(), Exceptions::BadCast, "domainMap " << col << " is not a strided map.");
209 
210  GetOStream(Statistics1) << "A(" << row << "," << col << ") is a single block and has strided maps:"
211  << "\n range map fixed block size = " << stridedRangeMap->getFixedBlockSize() << ", strided block id = " << stridedRangeMap->getStridedBlockId()
212  << "\n domain map fixed block size = " << stridedDomainMap->getFixedBlockSize() << ", strided block id = " << stridedDomainMap->getStridedBlockId() << std::endl;
213  GetOStream(Statistics2) << "A(" << row << "," << col << ") has " << Op->getGlobalNumRows() << "x" << Op->getGlobalNumCols() << " rows and columns." << std::endl;
214 
215  // TODO do we really need that? we moved the code to getMatrix...
216  if (Op->IsView("stridedMaps") == true)
217  Op->RemoveView("stridedMaps");
218  Op->CreateView("stridedMaps", stridedRangeMap, stridedDomainMap);
219 
220  TEUCHOS_TEST_FOR_EXCEPTION(Op->IsView("stridedMaps") == false, Exceptions::RuntimeError, "Failed to set \"stridedMaps\" view.");
221 
222  currentLevel.Set("A", Op, this);
223 }
224 
225 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
227  CheckForUserSpecifiedBlockInfo(bool bRange, std::vector<size_t>& stridingInfo, LocalOrdinal& stridedBlockId) const {
228  const ParameterList& pL = GetParameterList();
229 
230  if (bRange == true)
231  stridedBlockId = pL.get<LocalOrdinal>("Range map: Strided block id");
232  else
233  stridedBlockId = pL.get<LocalOrdinal>("Domain map: Strided block id");
234 
235  // read in stridingInfo from parameter list and fill the internal member variable
236  // read the data only if the parameter "Striding info" exists and is non-empty
237  std::string str;
238  if (bRange == true)
239  str = std::string("Range map: Striding info");
240  else
241  str = std::string("Domain map: Striding info");
242 
243  if (pL.isParameter(str)) {
244  std::string strStridingInfo = pL.get<std::string>(str);
245  if (strStridingInfo.empty() == false) {
246  Array<size_t> arrayVal = Teuchos::fromStringToArray<size_t>(strStridingInfo);
247  stridingInfo = Teuchos::createVector(arrayVal);
248  }
249  }
250 
251  if (stridingInfo.size() > 0) return true;
252  return false;
253 }
254 
255 } // namespace MueLu
256 
257 #endif /* MUELU_SUBBLOCKAFACTORY_DEF_HPP_ */
Exception indicating invalid cast attempted.
MueLu::DefaultLocalOrdinal LocalOrdinal
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.
RCP< const ParameterList > GetValidParameterList() const override
Input.
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)
Print more statistics.
void Build(Level &currentLevel) const override
Build an object with this factory.
bool CheckForUserSpecifiedBlockInfo(bool bRange, std::vector< size_t > &stridingInfo, LocalOrdinal &stridedBlockId) const
Print even more statistics.
bool isParameter(const std::string &name) const
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
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
Exception throws to report errors in the internal logical of the program.
void DeclareInput(Level &currentLevel) const override
Specifies the data that this class needs, and the factories that generate that data.
static const RCP< const NoFactory > getRCP()
Static Get() functions.
bool is_null() const