Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_SIMPLEPreconditionerFactory.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Teko: A package for block and physics based preconditioning
4 //
5 // Copyright 2010 NTESS and the Teko contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teko_SIMPLEPreconditionerFactory.hpp"
11 
12 #include "Teko_Utilities.hpp"
13 #include "Teko_InverseFactory.hpp"
14 #include "Teko_BlockLowerTriInverseOp.hpp"
15 #include "Teko_BlockUpperTriInverseOp.hpp"
16 #include <stdexcept>
17 #ifdef TEKO_HAVE_EPETRA
18 #include "Teko_DiagonalPreconditionerFactory.hpp"
19 #endif
20 
21 #include "Teuchos_Time.hpp"
22 
23 using Teuchos::RCP;
24 
25 namespace Teko {
26 namespace NS {
27 
28 // Constructor definition
29 SIMPLEPreconditionerFactory ::SIMPLEPreconditionerFactory(const RCP<InverseFactory>& inverse,
30  double alpha)
31  : invVelFactory_(inverse),
32  invPrsFactory_(inverse),
33  alpha_(alpha),
34  fInverseType_(Diagonal),
35  useMass_(false) {}
36 
37 SIMPLEPreconditionerFactory ::SIMPLEPreconditionerFactory(const RCP<InverseFactory>& invVFact,
38  const RCP<InverseFactory>& invPFact,
39  double alpha)
40  : invVelFactory_(invVFact),
41  invPrsFactory_(invPFact),
42  alpha_(alpha),
43  fInverseType_(Diagonal),
44  useMass_(false) {}
45 
46 SIMPLEPreconditionerFactory::SIMPLEPreconditionerFactory()
47  : alpha_(1.0), fInverseType_(Diagonal), useMass_(false) {}
48 
49 // Use the factory to build the preconditioner (this is where the work goes)
51  BlockedLinearOp& blockOp, BlockPreconditionerState& state) const {
52  Teko_DEBUG_SCOPE("SIMPLEPreconditionerFactory::buildPreconditionerOperator", 10);
53  Teko_DEBUG_EXPR(Teuchos::Time timer(""));
54 
55  int rows = blockRowCount(blockOp);
56  int cols = blockColCount(blockOp);
57 
58  TEUCHOS_ASSERT(rows == 2); // sanity checks
59  TEUCHOS_ASSERT(cols == 2);
60 
61  bool buildExplicitSchurComplement = true;
62 
63  // extract subblocks
64  const LinearOp F = getBlock(0, 0, blockOp);
65  const LinearOp Bt = getBlock(0, 1, blockOp);
66  const LinearOp B = getBlock(1, 0, blockOp);
67  const LinearOp C = getBlock(1, 1, blockOp);
68 
69  LinearOp matF = F;
70  if (useMass_) {
71  TEUCHOS_ASSERT(massMatrix_ != Teuchos::null);
72  matF = massMatrix_;
73  }
74 
75  // get approximation of inv(F) name H
76  std::string fApproxStr = "<error>";
77  LinearOp H;
78  if (fInverseType_ == NotDiag) {
79  H = buildInverse(*customHFactory_, matF);
80  fApproxStr = customHFactory_->toString();
81 
82  // since H is now implicit, we must build an implicit Schur complement
83  buildExplicitSchurComplement = false;
84  } else if (fInverseType_ == BlkDiag) {
85 #ifdef TEKO_HAVE_EPETRA
86  // Block diagonal approximation for H
88  DiagonalPrecondState Hstate;
89  Hfact.initializeFromParameterList(BlkDiagList_);
90  H = Hfact.buildPreconditionerOperator(matF, Hstate);
91 
92  /*
93  // Get a FECrsMarix out of the BDP
94  RCP<Epetra_FECrsMatrix> Hcrs=rcp(Hstate.BDP_->CreateFECrsMatrix());
95  H=Thyra::epetraLinearOp(Hcrs);
96  */
97 
98  buildExplicitSchurComplement = true; // NTS: Do I need this?
99  // Answer - no, but it is documenting whats going on here.
100 #else
101  throw std::logic_error(
102  "SIMPLEPreconditionerFactory fInverseType_ == "
103  "BlkDiag but EPETRA is turned off!");
104 #endif
105 
106  } else {
107  // get generic diagonal
108  H = getInvDiagonalOp(matF, fInverseType_);
109  fApproxStr = getDiagonalName(fInverseType_);
110  }
111 
112  // adjust H for time scaling if it is a mass matrix
113  if (useMass_) {
114  RCP<const Teuchos::ParameterList> pl = state.getParameterList();
115 
116  if (pl->isParameter("stepsize")) {
117  // get the step size
118  double stepsize = pl->get<double>("stepsize");
119 
120  // scale by stepsize only if it is larger than 0
121  if (stepsize > 0.0) H = scale(stepsize, H);
122  }
123  }
124 
125  // build approximate Schur complement: hatS = -C + B*H*Bt
126  LinearOp HBt, hatS;
127 
128  if (buildExplicitSchurComplement) {
129  ModifiableLinearOp& mHBt = state.getModifiableOp("HBt");
130  ModifiableLinearOp& mhatS = state.getModifiableOp("hatS");
131  ModifiableLinearOp& BHBt = state.getModifiableOp("BHBt");
132 
133  // build H*Bt
134  mHBt = explicitMultiply(H, Bt, mHBt);
135  HBt = mHBt;
136 
137  // build B*H*Bt
138  BHBt = explicitMultiply(B, HBt, BHBt);
139 
140  // build C-B*H*Bt
141  mhatS = explicitAdd(C, scale(-1.0, BHBt), mhatS);
142  hatS = mhatS;
143  } else {
144  // build an implicit Schur complement
145  HBt = multiply(H, Bt);
146 
147  hatS = add(C, scale(-1.0, multiply(B, HBt)));
148  }
149 
150  Teko::ModifiableLinearOp& precInvF = state.getModifiableOp("precInvF");
151  if (precVelFactory_) {
152  if (precInvF == Teuchos::null) {
153  precInvF = precVelFactory_->buildInverse(F);
154  state.addModifiableOp("precInvF", precInvF);
155  } else {
156  Teko::rebuildInverse(*precVelFactory_, F, precInvF);
157  }
158  }
159 
160  // build the inverse for F
161  Teko::ModifiableLinearOp& invF = state.getModifiableOp("invF");
162  if (invF == Teuchos::null) {
163  if (precInvF.is_null()) {
164  invF = Teko::buildInverse(*invVelFactory_, F);
165  } else {
166  invF = Teko::buildInverse(*invVelFactory_, F, precInvF);
167  }
168  } else {
169  if (precInvF.is_null()) {
170  Teko::rebuildInverse(*invVelFactory_, F, invF);
171  } else {
172  Teko::rebuildInverse(*invVelFactory_, F, precInvF, invF);
173  }
174  }
175 
176  Teko::ModifiableLinearOp& precInvS = state.getModifiableOp("precInvS");
177  if (precPrsFactory_) {
178  if (precInvS == Teuchos::null) {
179  precInvS = precPrsFactory_->buildInverse(hatS);
180  state.addModifiableOp("precInvS", precInvS);
181  } else {
182  Teko::rebuildInverse(*precPrsFactory_, hatS, precInvS);
183  }
184  }
185 
186  // build the approximate Schur complement
187  Teko::ModifiableLinearOp& invS = state.getModifiableOp("invS");
188  if (invS == Teuchos::null) {
189  if (precInvS == Teuchos::null) {
190  invS = Teko::buildInverse(*invPrsFactory_, hatS);
191  } else {
192  invS = Teko::buildInverse(*invPrsFactory_, hatS, precInvS);
193  }
194  } else {
195  if (precInvS == Teuchos::null) {
196  Teko::rebuildInverse(*invPrsFactory_, hatS, invS);
197  } else {
198  Teko::rebuildInverse(*invPrsFactory_, hatS, precInvS, invS);
199  }
200  }
201 
202  std::vector<LinearOp> invDiag(2); // vector storing inverses
203 
204  // build lower triangular inverse matrix
205  BlockedLinearOp L = zeroBlockedOp(blockOp);
206  setBlock(1, 0, L, B);
207  endBlockFill(L);
208 
209  invDiag[0] = invF;
210  invDiag[1] = invS;
211  LinearOp invL = createBlockLowerTriInverseOp(L, invDiag);
212 
213  // build upper triangular matrix
214  BlockedLinearOp U = zeroBlockedOp(blockOp);
215  setBlock(0, 1, U, scale(1.0 / alpha_, HBt));
216  endBlockFill(U);
217 
218  invDiag[0] = identity(rangeSpace(invF));
219  invDiag[1] = scale(alpha_, identity(rangeSpace(invS)));
220  LinearOp invU = createBlockUpperTriInverseOp(U, invDiag);
221 
222  // return implicit product operator
223  return multiply(invU, invL, "SIMPLE_" + fApproxStr);
224 }
225 
227 void SIMPLEPreconditionerFactory::initializeFromParameterList(const Teuchos::ParameterList& pl) {
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 = "", precVStr = "", precPStr = "";
237  alpha_ = 1.0;
238 
239  // "parse" the parameter list
240  if (pl.isParameter("Inverse Type")) invStr = pl.get<std::string>("Inverse Type");
241  if (pl.isParameter("Inverse Velocity Type"))
242  invVStr = pl.get<std::string>("Inverse Velocity Type");
243  if (pl.isParameter("Preconditioner Velocity Type"))
244  precVStr = pl.get<std::string>("Preconditioner Velocity Type");
245  if (pl.isParameter("Inverse Pressure Type"))
246  invPStr = pl.get<std::string>("Inverse Pressure Type");
247  if (pl.isParameter("Preconditioner Pressure Type"))
248  precPStr = pl.get<std::string>("Preconditioner Pressure Type");
249  if (pl.isParameter("Alpha")) alpha_ = pl.get<double>("Alpha");
250  if (pl.isParameter("Explicit Velocity Inverse Type")) {
251  std::string fInverseStr = pl.get<std::string>("Explicit Velocity Inverse Type");
252 
253  // build inverse types
254  fInverseType_ = getDiagonalType(fInverseStr);
255  if (fInverseType_ == NotDiag) customHFactory_ = invLib->getInverseFactory(fInverseStr);
256 
257  // Grab the sublist if we're using the block diagonal
258  if (fInverseType_ == BlkDiag) BlkDiagList_ = pl.sublist("H options");
259  }
260  if (pl.isParameter("Use Mass Scaling")) useMass_ = pl.get<bool>("Use Mass Scaling");
261 
262  Teko_DEBUG_MSG_BEGIN(5) DEBUG_STREAM << "SIMPLE Parameters: " << std::endl;
263  DEBUG_STREAM << " inv type = \"" << invStr << "\"" << std::endl;
264  DEBUG_STREAM << " inv v type = \"" << invVStr << "\"" << std::endl;
265  DEBUG_STREAM << " prec v type = \"" << precVStr << "\"" << std::endl;
266  DEBUG_STREAM << " inv p type = \"" << invPStr << "\"" << std::endl;
267  DEBUG_STREAM << " prec p type = \"" << precPStr << "\"" << 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 defined(Teko_ENABLE_Amesos)
277  if (invStr == "") invStr = "Amesos";
278 #elif defined(Teko_ENABLE_Amesos2)
279  if (invStr == "") invStr = "Amesos2";
280 #endif
281 
282  if (invVStr == "") invVStr = invStr;
283  if (invPStr == "") invPStr = invStr;
284 
285  // two inverse factory objects
286  RCP<InverseFactory> invVFact, invPFact;
287 
288  // build velocity inverse factory
289  invVFact = invLib->getInverseFactory(invVStr);
290  invPFact = invVFact; // by default these are the same
291  if (invVStr != invPStr) // if different, build pressure inverse factory
292  invPFact = invLib->getInverseFactory(invPStr);
293 
294  RCP<InverseFactory> precVFact, precPFact;
295  if (precVStr != "") precVFact = invLib->getInverseFactory(precVStr);
296 
297  if (precPStr != "") precPFact = invLib->getInverseFactory(precPStr);
298 
299  // based on parameter type build a strategy
300  invVelFactory_ = invVFact;
301  invPrsFactory_ = invPFact;
302 
303  precVelFactory_ = precVFact;
304  precPrsFactory_ = precPFact;
305 
306  if (useMass_) {
307  Teuchos::RCP<Teko::RequestHandler> rh = getRequestHandler();
308  rh->preRequest<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix"));
309  Teko::LinearOp mass = rh->request<Teko::LinearOp>(Teko::RequestMesg("Velocity Mass Matrix"));
310  setMassMatrix(mass);
311  }
312 }
313 
315 Teuchos::RCP<Teuchos::ParameterList> SIMPLEPreconditionerFactory::getRequestedParameters() const {
316  Teuchos::RCP<Teuchos::ParameterList> result;
317  Teuchos::RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList());
318 
319  // grab parameters from F solver
320  {
321  RCP<Teuchos::ParameterList> vList = invVelFactory_->getRequestedParameters();
322  if (vList != Teuchos::null) {
323  Teuchos::ParameterList::ConstIterator itr;
324  for (itr = vList->begin(); itr != vList->end(); ++itr) pl->setEntry(itr->first, itr->second);
325  result = pl;
326  }
327  }
328 
329  if (precVelFactory_ != Teuchos::null) {
330  RCP<Teuchos::ParameterList> vList = precVelFactory_->getRequestedParameters();
331  if (vList != Teuchos::null) {
332  Teuchos::ParameterList::ConstIterator itr;
333  for (itr = vList->begin(); itr != vList->end(); ++itr) pl->setEntry(itr->first, itr->second);
334  result = pl;
335  }
336  }
337 
338  // grab parameters from S solver
339  {
340  RCP<Teuchos::ParameterList> pList = invPrsFactory_->getRequestedParameters();
341  if (pList != Teuchos::null) {
342  Teuchos::ParameterList::ConstIterator itr;
343  for (itr = pList->begin(); itr != pList->end(); ++itr) pl->setEntry(itr->first, itr->second);
344  result = pl;
345  }
346  }
347 
348  if (precPrsFactory_ != Teuchos::null) {
349  RCP<Teuchos::ParameterList> pList = precPrsFactory_->getRequestedParameters();
350  if (pList != Teuchos::null) {
351  Teuchos::ParameterList::ConstIterator itr;
352  for (itr = pList->begin(); itr != pList->end(); ++itr) pl->setEntry(itr->first, itr->second);
353  result = pl;
354  }
355  }
356 
357  // grab parameters from S solver
358  if (customHFactory_ != Teuchos::null) {
359  RCP<Teuchos::ParameterList> hList = customHFactory_->getRequestedParameters();
360  if (hList != Teuchos::null) {
361  Teuchos::ParameterList::ConstIterator itr;
362  for (itr = hList->begin(); itr != hList->end(); ++itr) pl->setEntry(itr->first, itr->second);
363  result = pl;
364  }
365  }
366 
367  return result;
368 }
369 
371 bool SIMPLEPreconditionerFactory::updateRequestedParameters(const Teuchos::ParameterList& pl) {
372  Teko_DEBUG_SCOPE("InvLSCStrategy::updateRequestedParameters", 10);
373  bool result = true;
374 
375  // update requested parameters in solvers
376  result &= invVelFactory_->updateRequestedParameters(pl);
377  result &= invPrsFactory_->updateRequestedParameters(pl);
378  if (precVelFactory_) result &= precVelFactory_->updateRequestedParameters(pl);
379  if (precPrsFactory_) result &= precPrsFactory_->updateRequestedParameters(pl);
380  if (customHFactory_ != Teuchos::null) result &= customHFactory_->updateRequestedParameters(pl);
381 
382  return result;
383 }
384 
385 } // end namespace NS
386 } // 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.
virtual void addModifiableOp(const std::string &name, const Teko::ModifiableLinearOp &mlo)
Add a named operator to the state object.
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.