MueLu Version of the Day
Loading...
Searching...
No Matches
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
13#include <Xpetra_BlockedCrsMatrix.hpp>
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>
19#include <Xpetra_TripleMatrixMultiply.hpp>
20#include <Xpetra_CrsMatrixWrap.hpp>
21#include <Xpetra_CrsMatrix.hpp>
22
23#include "MueLu_Level.hpp"
24#include "MueLu_Monitor.hpp"
26
27namespace MueLu {
28
29template <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
43template <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
52template <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
59 TEUCHOS_TEST_FOR_EXCEPTION(bA.is_null(), Exceptions::BadCast,
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
75template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
76RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, 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
91 TEUCHOS_TEST_FOR_EXCEPTION(omega == zero, Exceptions::RuntimeError,
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_ */
MueLu::DefaultScalar Scalar
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.
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)....
static const RCP< const NoFactory > getRCP()
Static Get() functions.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &currentLevel) const
Input.
void Build(Level &currentLevel) const
Build an object with this factory.
RCP< Matrix > ComputeSchurComplement(RCP< BlockedCrsMatrix > &bA, RCP< Matrix > &Ainv) const
Schur complement calculation method.
Namespace for MueLu classes and methods.
@ Statistics2
Print even more statistics.
@ Statistics1
Print more statistics.