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 // 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_SCHURCOMPLEMENTFACTORY_DEF_HPP_
11 #define MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_
12 
14 #include <Xpetra_MultiVectorFactory.hpp>
15 #include <Xpetra_VectorFactory.hpp>
16 #include <Xpetra_MatrixFactory.hpp>
17 #include <Xpetra_Matrix.hpp>
18 #include <Xpetra_MatrixMatrix.hpp>
20 #include <Xpetra_CrsMatrixWrap.hpp>
21 #include <Xpetra_CrsMatrix.hpp>
22 
23 #include "MueLu_Level.hpp"
24 #include "MueLu_Monitor.hpp"
26 
27 namespace MueLu {
28 
29 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31  RCP<ParameterList> validParamList = rcp(new ParameterList());
32 
33  const SC one = Teuchos::ScalarTraits<SC>::one();
34 
35  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)");
36  validParamList->set<RCP<const FactoryBase>>("Ainv", Teuchos::null, "Generating factory of the inverse matrix used in the Schur complement");
37 
38  validParamList->set<SC>("omega", one, "Scaling parameter in S = A(1,1) - 1/omega A(1,0) Ainv A(0,1)");
39 
40  return validParamList;
41 }
42 
43 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
45  Input(currentLevel, "A");
46 
47  // Get default or user-given inverse approximation factory
48  RCP<const FactoryBase> AinvFact = GetFactory("Ainv");
49  currentLevel.DeclareInput("Ainv", AinvFact.get(), this);
50 }
51 
52 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
54  FactoryMonitor m(*this, "Build", currentLevel);
55 
56  RCP<Matrix> A = Get<RCP<Matrix>>(currentLevel, "A");
57  RCP<BlockedCrsMatrix> bA = rcp_dynamic_cast<BlockedCrsMatrix>(A);
58 
60  "MueLu::SchurComplementFactory::Build: input matrix A is not of type BlockedCrsMatrix!");
61  TEUCHOS_TEST_FOR_EXCEPTION(bA->Rows() != 2 || bA->Cols() != 2, Exceptions::RuntimeError,
62  "MueLu::SchurComplementFactory::Build: input matrix A is a " << bA->Rows() << "x" << bA->Cols() << " block matrix. We expect a 2x2 blocked operator.");
63 
64  // Calculate Schur Complement
65  RCP<Matrix> Ainv = currentLevel.Get<RCP<Matrix>>("Ainv", this->GetFactory("Ainv").get());
66  RCP<Matrix> S = ComputeSchurComplement(bA, Ainv);
67 
68  GetOStream(Statistics1) << "S has " << S->getGlobalNumRows() << "x" << S->getGlobalNumCols() << " rows and columns." << std::endl;
69 
70  // NOTE: "A" generated by this factory is actually the Schur complement
71  // matrix, but it is required as all smoothers expect "A"
72  Set(currentLevel, "A", S);
73 }
74 
75 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
78  using STS = Teuchos::ScalarTraits<SC>;
79  const SC zero = STS::zero(), one = STS::one();
80 
81  RCP<Matrix> A01 = bA->getMatrix(0, 1);
82  RCP<Matrix> A10 = bA->getMatrix(1, 0);
83  RCP<Matrix> A11 = bA->getMatrix(1, 1);
84 
85  RCP<BlockedCrsMatrix> bA01 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A01);
86  const bool isBlocked = (bA01 == Teuchos::null ? false : true);
87 
88  const ParameterList& pL = GetParameterList();
89  const SC omega = pL.get<Scalar>("omega");
90 
92  "MueLu::SchurComplementFactory::Build: Scaling parameter omega must not be zero to avoid division by zero.");
93 
94  RCP<Matrix> S = Teuchos::null; // Schur complement
95  RCP<Matrix> D = Teuchos::null; // temporary result for A10*Ainv*A01
96 
97  // only if the off-diagonal blocks A10 and A01 are non-zero we have to do the MM multiplication
98  if (A01.is_null() == false && A10.is_null() == false) {
99  // scale with -1/omega
100  Ainv->scale(Teuchos::as<Scalar>(-one / omega));
101 
102  // build Schur complement operator
103  if (!isBlocked) {
104  RCP<ParameterList> myparams = rcp(new ParameterList);
105  myparams->set("compute global constants", true);
106 
107  // -1/omega*Ainv*A01
108  TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(Ainv->getDomainMap())) == false, Exceptions::RuntimeError,
109  "MueLu::SchurComplementFactory::Build: RangeMap of A01 and domain map of Ainv are not the same.");
110  RCP<Matrix> C = MatrixMatrix::Multiply(*Ainv, false, *A01, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
111 
112  // -1/omega*A10*Ainv*A01
113  TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(A10->getDomainMap())) == false, Exceptions::RuntimeError,
114  "MueLu::SchurComplementFactory::Build: RangeMap of A10 and domain map A01 are not the same.");
115  D = MatrixMatrix::Multiply(*A10, false, *C, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
116  } else {
117  // nested blocking
118  auto bA10 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A10);
119  auto bAinv = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Ainv);
120  TEUCHOS_TEST_FOR_EXCEPTION(bAinv == Teuchos::null, Exceptions::RuntimeError,
121  "MueLu::SchurComplementFactory::Build: Casting Ainv to BlockedCrsMatrix not possible.");
122 
123  // -1/omega*bAinv*bA01
124  TEUCHOS_TEST_FOR_EXCEPTION(bA01->Rows() != bAinv->Cols(), Exceptions::RuntimeError,
125  "MueLu::SchurComplementFactory::Build: Block rows and cols of bA01 and bAinv are not compatible.");
126  RCP<BlockedCrsMatrix> C = MatrixMatrix::TwoMatrixMultiplyBlock(*bAinv, false, *bA01, false, GetOStream(Statistics2));
127 
128  // -1/omega*A10*Ainv*A01
129  TEUCHOS_TEST_FOR_EXCEPTION(bA10->Rows() != bA01->Cols(), Exceptions::RuntimeError,
130  "MueLu::SchurComplementFactory::Build: Block rows and cols of bA10 and bA01 are not compatible.");
131  D = MatrixMatrix::TwoMatrixMultiplyBlock(*bA10, false, *C, false, GetOStream(Statistics2));
132  }
133  if (!A11.is_null()) {
134  MatrixMatrix::TwoMatrixAdd(*A11, false, one, *D, false, one, S, GetOStream(Statistics2));
135  S->fillComplete();
136 
137  TEUCHOS_TEST_FOR_EXCEPTION(A11->getRangeMap()->isSameAs(*(S->getRangeMap())) == false, Exceptions::RuntimeError,
138  "MueLu::SchurComplementFactory::Build: RangeMap of A11 and S are not the same.");
139  TEUCHOS_TEST_FOR_EXCEPTION(A11->getDomainMap()->isSameAs(*(S->getDomainMap())) == false, Exceptions::RuntimeError,
140  "MueLu::SchurComplementFactory::Build: DomainMap of A11 and S are not the same.");
141  } else {
142  S = MatrixFactory::BuildCopy(D);
143  }
144  } else {
145  if (!A11.is_null()) {
146  S = MatrixFactory::BuildCopy(A11);
147  } else {
148  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
149  "MueLu::SchurComplementFactory::Build: Constructing Schur complement for matrix with zero block row or column.");
150  }
151  }
152 
153  // Check whether Schur complement operator is a 1x1 block matrix.
154  // If so, unwrap it and return the CrsMatrix based Matrix object
155  // We need this, as single-block smoothers expect it this way.
156  // In case of Thyra GIDs we obtain a Schur complement operator in Thyra GIDs
157  // This may make some special handling in feeding the SchurComplement solver Apply routine
158  // necessary!
159  if (isBlocked) {
160  RCP<BlockedCrsMatrix> bS = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(S);
161 
162  if (bS != Teuchos::null && bS->Rows() == 1 && bS->Cols() == 1) {
163  RCP<Matrix> temp = bS->getCrsMatrix();
164  S.swap(temp);
165  }
166  }
167 
168  return S;
169 }
170 
171 } // namespace MueLu
172 
173 #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)
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
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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:63
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.
static const RCP< const NoFactory > getRCP()
Static Get() functions.
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()
bool is_null() const