MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_SchurComplementFactory_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_SCHURCOMPLEMENTFACTORY_DEF_HPP_
47 #define MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_
48 
50 #include <Xpetra_MultiVectorFactory.hpp>
51 #include <Xpetra_VectorFactory.hpp>
52 #include <Xpetra_MatrixFactory.hpp>
53 #include <Xpetra_Matrix.hpp>
54 #include <Xpetra_MatrixMatrix.hpp>
56 #include <Xpetra_CrsMatrixWrap.hpp>
57 #include <Xpetra_CrsMatrix.hpp>
58 
59 #include "MueLu_Level.hpp"
60 #include "MueLu_Monitor.hpp"
62 
63 namespace MueLu {
64 
65 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
67  RCP<ParameterList> validParamList = rcp(new ParameterList());
68 
69  const SC one = Teuchos::ScalarTraits<SC>::one();
70 
71  validParamList->set<RCP<const FactoryBase>>("A", NoFactory::getRCP(), "Generating factory of the matrix A used for building Schur complement (must be a 2x2 blocked operator)");
72  validParamList->set<RCP<const FactoryBase>>("Ainv", Teuchos::null, "Generating factory of the inverse matrix used in the Schur complement");
73 
74  validParamList->set<SC>("omega", one, "Scaling parameter in S = A(1,1) - 1/omega A(1,0) Ainv A(0,1)");
75 
76  return validParamList;
77 }
78 
79 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81  Input(currentLevel, "A");
82 
83  // Get default or user-given inverse approximation factory
84  RCP<const FactoryBase> AinvFact = GetFactory("Ainv");
85  currentLevel.DeclareInput("Ainv", AinvFact.get(), this);
86 }
87 
88 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
90  FactoryMonitor m(*this, "Build", currentLevel);
91 
92  RCP<Matrix> A = Get<RCP<Matrix>>(currentLevel, "A");
93  RCP<BlockedCrsMatrix> bA = rcp_dynamic_cast<BlockedCrsMatrix>(A);
94 
96  "MueLu::SchurComplementFactory::Build: input matrix A is not of type BlockedCrsMatrix!");
97  TEUCHOS_TEST_FOR_EXCEPTION(bA->Rows() != 2 || bA->Cols() != 2, Exceptions::RuntimeError,
98  "MueLu::SchurComplementFactory::Build: input matrix A is a " << bA->Rows() << "x" << bA->Cols() << " block matrix. We expect a 2x2 blocked operator.");
99 
100  // Calculate Schur Complement
101  RCP<Matrix> Ainv = currentLevel.Get<RCP<Matrix>>("Ainv", this->GetFactory("Ainv").get());
102  RCP<Matrix> S = ComputeSchurComplement(bA, Ainv);
103 
104  GetOStream(Statistics1) << "S has " << S->getGlobalNumRows() << "x" << S->getGlobalNumCols() << " rows and columns." << std::endl;
105 
106  // NOTE: "A" generated by this factory is actually the Schur complement
107  // matrix, but it is required as all smoothers expect "A"
108  Set(currentLevel, "A", S);
109 }
110 
111 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
114  using STS = Teuchos::ScalarTraits<SC>;
115  const SC zero = STS::zero(), one = STS::one();
116 
117  RCP<Matrix> A01 = bA->getMatrix(0, 1);
118  RCP<Matrix> A10 = bA->getMatrix(1, 0);
119  RCP<Matrix> A11 = bA->getMatrix(1, 1);
120 
121  RCP<BlockedCrsMatrix> bA01 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A01);
122  const bool isBlocked = (bA01 == Teuchos::null ? false : true);
123 
124  const ParameterList& pL = GetParameterList();
125  const SC omega = pL.get<Scalar>("omega");
126 
128  "MueLu::SchurComplementFactory::Build: Scaling parameter omega must not be zero to avoid division by zero.");
129 
130  RCP<Matrix> S = Teuchos::null; // Schur complement
131  RCP<Matrix> D = Teuchos::null; // temporary result for A10*Ainv*A01
132 
133  // only if the off-diagonal blocks A10 and A01 are non-zero we have to do the MM multiplication
134  if (A01.is_null() == false && A10.is_null() == false) {
135  // scale with -1/omega
136  Ainv->scale(Teuchos::as<Scalar>(-one / omega));
137 
138  // build Schur complement operator
139  if (!isBlocked) {
140  RCP<ParameterList> myparams = rcp(new ParameterList);
141  myparams->set("compute global constants", true);
142 
143  // -1/omega*Ainv*A01
144  TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(Ainv->getDomainMap())) == false, Exceptions::RuntimeError,
145  "MueLu::SchurComplementFactory::Build: RangeMap of A01 and domain map of Ainv are not the same.");
146  RCP<Matrix> C = MatrixMatrix::Multiply(*Ainv, false, *A01, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
147 
148  // -1/omega*A10*Ainv*A01
149  TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(A10->getDomainMap())) == false, Exceptions::RuntimeError,
150  "MueLu::SchurComplementFactory::Build: RangeMap of A10 and domain map A01 are not the same.");
151  D = MatrixMatrix::Multiply(*A10, false, *C, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
152  } else {
153  // nested blocking
154  auto bA10 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A10);
155  auto bAinv = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Ainv);
156  TEUCHOS_TEST_FOR_EXCEPTION(bAinv == Teuchos::null, Exceptions::RuntimeError,
157  "MueLu::SchurComplementFactory::Build: Casting Ainv to BlockedCrsMatrix not possible.");
158 
159  // -1/omega*bAinv*bA01
160  TEUCHOS_TEST_FOR_EXCEPTION(bA01->Rows() != bAinv->Cols(), Exceptions::RuntimeError,
161  "MueLu::SchurComplementFactory::Build: Block rows and cols of bA01 and bAinv are not compatible.");
162  RCP<BlockedCrsMatrix> C = MatrixMatrix::TwoMatrixMultiplyBlock(*bAinv, false, *bA01, false, GetOStream(Statistics2));
163 
164  // -1/omega*A10*Ainv*A01
165  TEUCHOS_TEST_FOR_EXCEPTION(bA10->Rows() != bA01->Cols(), Exceptions::RuntimeError,
166  "MueLu::SchurComplementFactory::Build: Block rows and cols of bA10 and bA01 are not compatible.");
167  D = MatrixMatrix::TwoMatrixMultiplyBlock(*bA10, false, *C, false, GetOStream(Statistics2));
168  }
169  if (!A11.is_null()) {
170  MatrixMatrix::TwoMatrixAdd(*A11, false, one, *D, false, one, S, GetOStream(Statistics2));
171  S->fillComplete();
172 
173  TEUCHOS_TEST_FOR_EXCEPTION(A11->getRangeMap()->isSameAs(*(S->getRangeMap())) == false, Exceptions::RuntimeError,
174  "MueLu::SchurComplementFactory::Build: RangeMap of A11 and S are not the same.");
175  TEUCHOS_TEST_FOR_EXCEPTION(A11->getDomainMap()->isSameAs(*(S->getDomainMap())) == false, Exceptions::RuntimeError,
176  "MueLu::SchurComplementFactory::Build: DomainMap of A11 and S are not the same.");
177  } else {
178  S = MatrixFactory::BuildCopy(D);
179  }
180  } else {
181  if (!A11.is_null()) {
182  S = MatrixFactory::BuildCopy(A11);
183  } else {
184  S = MatrixFactory::Build(A11->getRowMap(), 10 /*A11->getLocalMaxNumRowEntries()*/);
185  S->fillComplete(A11->getDomainMap(), A11->getRangeMap());
186  }
187  }
188 
189  // Check whether Schur complement operator is a 1x1 block matrix.
190  // If so, unwrap it and return the CrsMatrix based Matrix object
191  // We need this, as single-block smoothers expect it this way.
192  // In case of Thyra GIDs we obtain a Schur complement operator in Thyra GIDs
193  // This may make some special handling in feeding the SchurComplement solver Apply routine
194  // necessary!
195  if (isBlocked) {
196  RCP<BlockedCrsMatrix> bS = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(S);
197 
198  if (bS != Teuchos::null && bS->Rows() == 1 && bS->Cols() == 1) {
199  RCP<Matrix> temp = bS->getCrsMatrix();
200  S.swap(temp);
201  }
202  }
203 
204  return S;
205 }
206 
207 } // namespace MueLu
208 
209 #endif /* MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_ */
Exception indicating invalid cast attempted.
RCP< Matrix > ComputeSchurComplement(RCP< BlockedCrsMatrix > &bA, RCP< Matrix > &Ainv) const
Schur complement calculation method.
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 swap(RCP< T > &r_ptr)
T * get() const
void DeclareInput(Level &currentLevel) const
Input.
Print even more statistics.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultScalar Scalar
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void Build(Level &currentLevel) const
Build an object with this factory.
Scalar SC
Exception throws to report errors in the internal logical of the program.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
static const RCP< const NoFactory > getRCP()
Static Get() functions.
bool is_null() const