Teko  Version of the Day
 All Classes Files Functions Variables Pages
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 
64 using Teuchos::RCP;
65 
66 namespace Teko {
67 namespace 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 
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 
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
128  DiagonalPrecondState Hstate;
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 
226 void 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 
303 Teuchos::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 
341 bool 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
void rebuildInverse(const InverseFactory &factory, const LinearOp &A, InverseLinearOp &invA)
virtual bool updateRequestedParameters(const Teuchos::ParameterList &pl)
For assisting in construction of the preconditioner.
Preconditioner factory for building explcit inverse of diagonal operators. This includes block operat...
An implementation of a state object for block preconditioners.
virtual void setMassMatrix(Teko::LinearOp &mass)
Set the mass matrix for this factory.
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A)
Build an inverse operator using a factory and a linear operator.
virtual void initializeFromParameterList(const Teuchos::ParameterList &pl)
Initialize from a parameter list.
virtual void initializeFromParameterList(const Teuchos::ParameterList &pl)
Initialize from a parameter list.
Teuchos::RCP< const InverseLibrary > getInverseLibrary() const
Get the inverse library used by this preconditioner factory.
virtual Teuchos::RCP< Teuchos::ParameterList > getRequestedParameters() const
For assisting in construction of the preconditioner.
LinearOp buildPreconditionerOperator(BlockedLinearOp &blo, BlockPreconditionerState &state) const
Function that is called to build the preconditioner for the linear operator that is passed in...
Teuchos::RCP< RequestHandler > getRequestHandler() const
Get the request handler with pointers to the appropriate callbacks.
LinearOp buildPreconditionerOperator(LinearOp &lo, PreconditionerState &state) const
virtual Teko::ModifiableLinearOp & getModifiableOp(const std::string &name)
Add a named operator to the state object.