Teko Version of the Day
Teko_SIMPLEPreconditionerFactory.cpp
1/*
2// @HEADER
3//
4// ***********************************************************************
5//
6// Teko: A package for block and physics based preconditioning
7// Copyright 2010 Sandia Corporation
8//
9// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
10// the U.S. Government retains certain rights in this software.
11//
12// Redistribution and use in source and binary forms, with or without
13// modification, are permitted provided that the following conditions are
14// met:
15//
16// 1. Redistributions of source code must retain the above copyright
17// notice, this list of conditions and the following disclaimer.
18//
19// 2. Redistributions in binary form must reproduce the above copyright
20// notice, this list of conditions and the following disclaimer in the
21// documentation and/or other materials provided with the distribution.
22//
23// 3. Neither the name of the Corporation nor the names of the
24// contributors may be used to endorse or promote products derived from
25// this software without specific prior written permission.
26//
27// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
28// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
31// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38//
39// Questions? Contact Eric C. Cyr (eccyr@sandia.gov)
40//
41// ***********************************************************************
42//
43// @HEADER
44
45*/
46
47#include "Teko_SIMPLEPreconditionerFactory.hpp"
48
49#include "Teko_Utilities.hpp"
50#include "Teko_InverseFactory.hpp"
51#include "Teko_BlockLowerTriInverseOp.hpp"
52#include "Teko_BlockUpperTriInverseOp.hpp"
53#include "Teko_DiagonalPreconditionerFactory.hpp"
54
55#include "Teuchos_Time.hpp"
56#include "Epetra_FECrsGraph.h"
57#include "Epetra_FECrsMatrix.h"
58#include "EpetraExt_PointToBlockDiagPermute.h"
59#include "EpetraExt_MatrixMatrix.h"
60#include "Thyra_EpetraOperatorWrapper.hpp"
61#include "Thyra_EpetraLinearOp.hpp"
62
63
64using Teuchos::RCP;
65
66namespace Teko {
67namespace NS {
68
69// Constructor definition
71 ::SIMPLEPreconditionerFactory(const RCP<InverseFactory> & inverse,
72 double alpha)
73 : invVelFactory_(inverse), invPrsFactory_(inverse), alpha_(alpha), fInverseType_(Diagonal), useMass_(false)
74{ }
75
76SIMPLEPreconditionerFactory
77 ::SIMPLEPreconditionerFactory(const RCP<InverseFactory> & invVFact,
78 const RCP<InverseFactory> & invPFact,
79 double alpha)
80 : invVelFactory_(invVFact), invPrsFactory_(invPFact), alpha_(alpha), fInverseType_(Diagonal), useMass_(false)
81{ }
82
83SIMPLEPreconditionerFactory::SIMPLEPreconditionerFactory()
84 : alpha_(1.0), fInverseType_(Diagonal), useMass_(false)
85{ }
86
87// Use the factory to build the preconditioner (this is where the work goes)
89 ::buildPreconditionerOperator(BlockedLinearOp & blockOp,
90 BlockPreconditionerState & state) const
91{
92 Teko_DEBUG_SCOPE("SIMPLEPreconditionerFactory::buildPreconditionerOperator",10);
93 Teko_DEBUG_EXPR(Teuchos::Time timer(""));
94
95 int rows = blockRowCount(blockOp);
96 int cols = blockColCount(blockOp);
97
98 TEUCHOS_ASSERT(rows==2); // sanity checks
99 TEUCHOS_ASSERT(cols==2);
100
101 bool buildExplicitSchurComplement = true;
102
103 // extract subblocks
104 const LinearOp F = getBlock(0,0,blockOp);
105 const LinearOp Bt = getBlock(0,1,blockOp);
106 const LinearOp B = getBlock(1,0,blockOp);
107 const LinearOp C = getBlock(1,1,blockOp);
108
109 LinearOp matF = F;
110 if(useMass_) {
111 TEUCHOS_ASSERT(massMatrix_!=Teuchos::null);
112 matF = massMatrix_;
113 }
114
115 // get approximation of inv(F) name H
116 std::string fApproxStr = "<error>";
117 LinearOp H;
118 if(fInverseType_==NotDiag) {
119 H = buildInverse(*customHFactory_,matF);
120 fApproxStr = customHFactory_->toString();
121
122 // since H is now implicit, we must build an implicit Schur complement
123 buildExplicitSchurComplement = false;
124 }
125 else if(fInverseType_==BlkDiag) {
126 // Block diagonal approximation for H
129 Hfact.initializeFromParameterList(BlkDiagList_);
130 H = Hfact.buildPreconditionerOperator(matF,Hstate);
131
132/*
133 // Get a FECrsMarix out of the BDP
134 RCP<Epetra_FECrsMatrix> Hcrs=rcp(Hstate.BDP_->CreateFECrsMatrix());
135 H=Thyra::epetraLinearOp(Hcrs);
136*/
137
138 buildExplicitSchurComplement = true; // NTS: Do I need this?
139 // Answer - no, but it is documenting whats going on here.
140 }
141 else {
142 // get generic diagonal
143 H = getInvDiagonalOp(matF,fInverseType_);
144 fApproxStr = getDiagonalName(fInverseType_);
145 }
146
147 // adjust H for time scaling if it is a mass matrix
148 if(useMass_) {
149 RCP<const Teuchos::ParameterList> pl = state.getParameterList();
150
151 if(pl->isParameter("stepsize")) {
152 // get the step size
153 double stepsize = pl->get<double>("stepsize");
154
155 // scale by stepsize only if it is larger than 0
156 if(stepsize>0.0)
157 H = scale(stepsize,H);
158 }
159 }
160
161 // build approximate Schur complement: hatS = -C + B*H*Bt
162 LinearOp HBt, hatS;
163
164 if(buildExplicitSchurComplement) {
165 ModifiableLinearOp & mHBt = state.getModifiableOp("HBt");
166 ModifiableLinearOp & mhatS = state.getModifiableOp("hatS");
167 ModifiableLinearOp & BHBt = state.getModifiableOp("BHBt");
168
169 // build H*Bt
170 mHBt = explicitMultiply(H,Bt,mHBt);
171 HBt = mHBt;
172
173 // build B*H*Bt
174 BHBt = explicitMultiply(B,HBt,BHBt);
175
176 // build C-B*H*Bt
177 mhatS = explicitAdd(C,scale(-1.0,BHBt),mhatS);
178 hatS = mhatS;
179 }
180 else {
181 // build an implicit Schur complement
182 HBt = multiply(H,Bt);
183
184 hatS = add(C,scale(-1.0,multiply(B,HBt)));
185 }
186
187 // build the inverse for F
188 ModifiableLinearOp & invF = state.getModifiableOp("invF");
189 if(invF==Teuchos::null)
190 invF = buildInverse(*invVelFactory_,F);
191 else
192 rebuildInverse(*invVelFactory_,F,invF);
193
194 // build the approximate Schur complement
195 ModifiableLinearOp & invS = state.getModifiableOp("invS");
196 if(invS==Teuchos::null)
197 invS = buildInverse(*invPrsFactory_,hatS);
198 else
199 rebuildInverse(*invPrsFactory_,hatS,invS);
200
201 std::vector<LinearOp> invDiag(2); // vector storing inverses
202
203 // build lower triangular inverse matrix
204 BlockedLinearOp L = zeroBlockedOp(blockOp);
205 setBlock(1,0,L,B);
206 endBlockFill(L);
207
208 invDiag[0] = invF;
209 invDiag[1] = invS;
210 LinearOp invL = createBlockLowerTriInverseOp(L,invDiag);
211
212 // build upper triangular matrix
213 BlockedLinearOp U = zeroBlockedOp(blockOp);
214 setBlock(0,1,U,scale(1.0/alpha_,HBt));
215 endBlockFill(U);
216
217 invDiag[0] = identity(rangeSpace(invF));
218 invDiag[1] = scale(alpha_,identity(rangeSpace(invS)));
219 LinearOp invU = createBlockUpperTriInverseOp(U,invDiag);
220
221 // return implicit product operator
222 return multiply(invU,invL,"SIMPLE_"+fApproxStr);
223}
224
226void SIMPLEPreconditionerFactory::initializeFromParameterList(const Teuchos::ParameterList & pl)
227{
228 RCP<const InverseLibrary> invLib = getInverseLibrary();
229
230 // default conditions
231 useMass_ = false;
232 customHFactory_ = Teuchos::null;
233 fInverseType_ = Diagonal;
234
235 // get string specifying inverse
236 std::string invStr="", invVStr="", invPStr="";
237 alpha_ = 1.0;
238
239 // "parse" the parameter list
240 if(pl.isParameter("Inverse Type"))
241 invStr = pl.get<std::string>("Inverse Type");
242 if(pl.isParameter("Inverse Velocity Type"))
243 invVStr = pl.get<std::string>("Inverse Velocity Type");
244 if(pl.isParameter("Inverse Pressure Type"))
245 invPStr = pl.get<std::string>("Inverse Pressure Type");
246 if(pl.isParameter("Alpha"))
247 alpha_ = pl.get<double>("Alpha");
248 if(pl.isParameter("Explicit Velocity Inverse Type")) {
249 std::string fInverseStr = pl.get<std::string>("Explicit Velocity Inverse Type");
250
251 // build inverse types
252 fInverseType_ = getDiagonalType(fInverseStr);
253 if(fInverseType_==NotDiag)
254 customHFactory_ = invLib->getInverseFactory(fInverseStr);
255
256 // Grab the sublist if we're using the block diagonal
257 if(fInverseType_==BlkDiag)
258 BlkDiagList_=pl.sublist("H options");
259 }
260 if(pl.isParameter("Use Mass Scaling"))
261 useMass_ = pl.get<bool>("Use Mass Scaling");
262
263 Teko_DEBUG_MSG_BEGIN(5)
264 DEBUG_STREAM << "SIMPLE Parameters: " << std::endl;
265 DEBUG_STREAM << " inv type = \"" << invStr << "\"" << std::endl;
266 DEBUG_STREAM << " inv v type = \"" << invVStr << "\"" << std::endl;
267 DEBUG_STREAM << " inv p type = \"" << invPStr << "\"" << std::endl;
268 DEBUG_STREAM << " alpha = " << alpha_ << std::endl;
269 DEBUG_STREAM << " use mass = " << useMass_ << std::endl;
270 DEBUG_STREAM << " vel scaling = " << getDiagonalName(fInverseType_) << std::endl;
271 DEBUG_STREAM << "SIMPLE Parameter list: " << std::endl;
272 pl.print(DEBUG_STREAM);
273 Teko_DEBUG_MSG_END()
274
275 // set defaults as needed
276 if(invStr=="") invStr = "Amesos";
277 if(invVStr=="") invVStr = invStr;
278 if(invPStr=="") invPStr = invStr;
279
280 // two inverse factory objects
281 RCP<InverseFactory> invVFact, invPFact;
282
283 // build velocity inverse factory
284 invVFact = invLib->getInverseFactory(invVStr);
285 invPFact = invVFact; // by default these are the same
286 if(invVStr!=invPStr) // if different, build pressure inverse factory
287 invPFact = invLib->getInverseFactory(invPStr);
288
289 // based on parameter type build a strategy
290 invVelFactory_ = invVFact;
291 invPrsFactory_ = invPFact;
292
293 if(useMass_) {
294 Teuchos::RCP<Teko::RequestHandler> rh = getRequestHandler();
295 rh->preRequest<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix"));
296 Teko::LinearOp mass
297 = rh->request<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix"));
298 setMassMatrix(mass);
299 }
300}
301
303Teuchos::RCP<Teuchos::ParameterList> SIMPLEPreconditionerFactory::getRequestedParameters() const
304{
305 Teuchos::RCP<Teuchos::ParameterList> result;
306 Teuchos::RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList());
307
308 // grab parameters from F solver
309 RCP<Teuchos::ParameterList> vList = invVelFactory_->getRequestedParameters();
310 if(vList!=Teuchos::null) {
311 Teuchos::ParameterList::ConstIterator itr;
312 for(itr=vList->begin();itr!=vList->end();++itr)
313 pl->setEntry(itr->first,itr->second);
314 result = pl;
315 }
316
317 // grab parameters from S solver
318 RCP<Teuchos::ParameterList> pList = invPrsFactory_->getRequestedParameters();
319 if(pList!=Teuchos::null) {
320 Teuchos::ParameterList::ConstIterator itr;
321 for(itr=pList->begin();itr!=pList->end();++itr)
322 pl->setEntry(itr->first,itr->second);
323 result = pl;
324 }
325
326 // grab parameters from S solver
327 if(customHFactory_!=Teuchos::null) {
328 RCP<Teuchos::ParameterList> hList = customHFactory_->getRequestedParameters();
329 if(hList!=Teuchos::null) {
330 Teuchos::ParameterList::ConstIterator itr;
331 for(itr=hList->begin();itr!=hList->end();++itr)
332 pl->setEntry(itr->first,itr->second);
333 result = pl;
334 }
335 }
336
337 return result;
338}
339
341bool SIMPLEPreconditionerFactory::updateRequestedParameters(const Teuchos::ParameterList & pl)
342{
343 Teko_DEBUG_SCOPE("InvLSCStrategy::updateRequestedParameters",10);
344 bool result = true;
345
346 // update requested parameters in solvers
347 result &= invVelFactory_->updateRequestedParameters(pl);
348 result &= invPrsFactory_->updateRequestedParameters(pl);
349 if(customHFactory_!=Teuchos::null)
350 result &= customHFactory_->updateRequestedParameters(pl);
351
352 return result;
353}
354
355} // end namespace NS
356} // end namespace Teko
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A)
Build an inverse operator using a factory and a linear operator.
void rebuildInverse(const InverseFactory &factory, const LinearOp &A, InverseLinearOp &invA)
void scale(const double alpha, MultiVector &x)
Scale a multivector by a constant.
@ BlkDiag
Specifies that a block diagonal approximation is to be used.
@ NotDiag
For user convenience, if Teko recieves this value, exceptions will be thrown
@ Diagonal
Specifies that just the diagonal is used.
int blockRowCount(const BlockedLinearOp &blo)
Get the row count in a block linear operator.
MultiVector getBlock(int i, const BlockedMultiVector &bmv)
Get the ith block from a BlockedMultiVector object.
void setBlock(int i, int j, BlockedLinearOp &blo, const LinearOp &lo)
Set the i,j block in a BlockedLinearOp object.
VectorSpace rangeSpace(const LinearOp &lo)
Get the range space of a linear operator.
int blockColCount(const BlockedLinearOp &blo)
Get the column count in a block linear operator.
void endBlockFill(BlockedLinearOp &blo)
Notify the blocked operator that the fill stage is completed.
An implementation of a state object for block preconditioners.
Preconditioner factory for building explcit inverse of diagonal operators. This includes block operat...
virtual void initializeFromParameterList(const Teuchos::ParameterList &pl)
Initialize from a parameter list.
LinearOp buildPreconditionerOperator(LinearOp &lo, PreconditionerState &state) const
LinearOp buildPreconditionerOperator(BlockedLinearOp &blo, BlockPreconditionerState &state) const
Function that is called to build the preconditioner for the linear operator that is passed in.
virtual bool updateRequestedParameters(const Teuchos::ParameterList &pl)
For assisting in construction of the preconditioner.
virtual void initializeFromParameterList(const Teuchos::ParameterList &pl)
Initialize from a parameter list.
virtual void setMassMatrix(Teko::LinearOp &mass)
Set the mass matrix for this factory.
virtual Teuchos::RCP< Teuchos::ParameterList > getRequestedParameters() const
For assisting in construction of the preconditioner.
Teuchos::RCP< const InverseLibrary > getInverseLibrary() const
Get the inverse library used by this preconditioner factory.
Teuchos::RCP< RequestHandler > getRequestHandler() const
Get the request handler with pointers to the appropriate callbacks.
virtual Teko::ModifiableLinearOp & getModifiableOp(const std::string &name)
Add a named operator to the state object.