Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_LSCPreconditionerFactory.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_LSCPreconditionerFactory.hpp"
11 
12 #include "Thyra_DefaultMultipliedLinearOp.hpp"
13 #include "Thyra_DefaultAddedLinearOp.hpp"
14 #include "Thyra_DefaultIdentityLinearOp.hpp"
15 #include "Thyra_DefaultZeroLinearOp.hpp"
16 
17 #include "Teko_LU2x2InverseOp.hpp"
18 #include "Teko_Utilities.hpp"
19 #include "Teko_BlockUpperTriInverseOp.hpp"
20 #include "Teko_StaticLSCStrategy.hpp"
21 #include "Teko_InvLSCStrategy.hpp"
22 #include "Teko_PresLaplaceLSCStrategy.hpp"
23 #include "Teko_LSCSIMPLECStrategy.hpp"
24 
25 #include "Teuchos_Time.hpp"
26 
27 namespace Teko {
28 namespace NS {
29 
30 using Teuchos::rcp;
31 using Teuchos::RCP;
32 using Teuchos::rcp_dynamic_cast;
33 
34 using Thyra::add;
35 using Thyra::identity;
36 using Thyra::multiply;
37 
38 // Stabilized constructor
39 LSCPreconditionerFactory::LSCPreconditionerFactory(const LinearOp& invF, const LinearOp& invBQBtmC,
40  const LinearOp& invD, const LinearOp& invMass)
41  : invOpsStrategy_(rcp(new StaticLSCStrategy(invF, invBQBtmC, invD, invMass))),
42  isSymmetric_(true) {}
43 
44 // Stable constructor
45 LSCPreconditionerFactory::LSCPreconditionerFactory(const LinearOp& invF, const LinearOp& invBQBtmC,
46  const LinearOp& invMass)
47  : invOpsStrategy_(rcp(new StaticLSCStrategy(invF, invBQBtmC, invMass))), isSymmetric_(true) {}
48 
49 // fully generic constructor
50 LSCPreconditionerFactory::LSCPreconditionerFactory(const RCP<LSCStrategy>& strategy)
51  : invOpsStrategy_(strategy), isSymmetric_(true) {}
52 
53 LSCPreconditionerFactory::LSCPreconditionerFactory() : isSymmetric_(true) {}
54 
55 // for PreconditionerFactoryBase
57 
58 // initialize a newly created preconditioner object
59 LinearOp LSCPreconditionerFactory::buildPreconditionerOperator(
60  BlockedLinearOp& blockOp, BlockPreconditionerState& state) const {
61  Teko_DEBUG_SCOPE("LSCPreconditionerFactory::buildPreconditionerOperator", 10);
62  Teko_DEBUG_EXPR(Teuchos::Time timer(""));
63  Teko_DEBUG_EXPR(Teuchos::Time totalTimer(""));
64  Teko_DEBUG_EXPR(totalTimer.start());
65 
66  // extract sub-matrices from source operator
67  LinearOp F = blockOp->getBlock(0, 0);
68  LinearOp B = blockOp->getBlock(1, 0);
69  LinearOp Bt = blockOp->getBlock(0, 1);
70 
71  if (not isSymmetric_) Bt = scale(-1.0, adjoint(B));
72 
73  // build what is neccessary for the state object
74  Teko_DEBUG_EXPR(timer.start(true));
75  invOpsStrategy_->buildState(blockOp, state);
76  Teko_DEBUG_EXPR(timer.stop());
77  Teko_DEBUG_MSG("LSCPrecFact::buildPO BuildStateTime = " << timer.totalElapsedTime(), 2);
78 
79  // extract operators from strategy
80  Teko_DEBUG_EXPR(timer.start(true));
81  LinearOp invF = invOpsStrategy_->getInvF(blockOp, state);
82  LinearOp invBQBtmC = invOpsStrategy_->getInvBQBt(blockOp, state);
83  LinearOp invBHBtmC = invOpsStrategy_->getInvBHBt(blockOp, state);
84  LinearOp outerStab = invOpsStrategy_->getOuterStabilization(blockOp, state);
85  LinearOp innerStab = invOpsStrategy_->getInnerStabilization(blockOp, state);
86 
87  // if necessary build an identity mass matrix
88  LinearOp invMass = invOpsStrategy_->getInvMass(blockOp, state);
89  LinearOp HScaling = invOpsStrategy_->getHScaling(blockOp, state);
90  if (invMass == Teuchos::null) invMass = identity<double>(F->range());
91  if (HScaling == Teuchos::null) HScaling = identity<double>(F->range());
92  Teko_DEBUG_EXPR(timer.stop());
93  Teko_DEBUG_MSG("LSCPrecFact::buildPO GetInvTime = " << timer.totalElapsedTime(), 2);
94 
95  // need to build Schur complement, inv(P) = inv(B*Bt)*(B*F*Bt)*inv(B*Bt)
96 
97  // first construct middle operator: M = B * inv(Mass) * F * inv(Mass) * Bt
98  LinearOp M =
99  // (B * inv(Mass) ) * F * (inv(Mass) * Bt)
100  multiply(multiply(B, invMass), F, multiply(HScaling, Bt));
101  if (innerStab != Teuchos::null) // deal with inner stabilization
102  M = add(M, innerStab);
103 
104  // now construct a linear operator schur complement
105  LinearOp invPschur;
106  if (outerStab != Teuchos::null)
107  invPschur = add(multiply(invBQBtmC, M, invBHBtmC), outerStab);
108  else
109  invPschur = multiply(invBQBtmC, M, invBHBtmC);
110 
111  // build the preconditioner operator: Use LDU or upper triangular approximation
112  if (invOpsStrategy_->useFullLDU()) {
113  Teko_DEBUG_EXPR(totalTimer.stop());
114  Teko_DEBUG_MSG("LSCPrecFact::buildPO TotalTime = " << totalTimer.totalElapsedTime(), 2);
115 
116  // solve using a full LDU decomposition
117  return createLU2x2InverseOp(blockOp, invF, invPschur, "LSC-LDU");
118  } else {
119  // build diagonal operations
120  std::vector<LinearOp> invDiag(2);
121  invDiag[0] = invF;
122  invDiag[1] = Thyra::scale(-1.0, invPschur);
123 
124  // get upper triangular matrix
125  BlockedLinearOp U = getUpperTriBlocks(blockOp);
126 
127  Teko_DEBUG_EXPR(totalTimer.stop());
128  Teko_DEBUG_MSG("LSCPrecFact::buildPO TotalTime = " << totalTimer.totalElapsedTime(), 2);
129 
130  // solve using only one inversion of F
131  return createBlockUpperTriInverseOp(U, invDiag, "LSC-Upper");
132  }
133 }
134 
136 void LSCPreconditionerFactory::initializeFromParameterList(const Teuchos::ParameterList& pl) {
137  Teko_DEBUG_SCOPE("LSCPreconditionerFactory::initializeFromParameterList", 10);
138 
139  RCP<const InverseLibrary> invLib = getInverseLibrary();
140 
141  if (pl.isParameter("Is Symmetric")) isSymmetric_ = pl.get<bool>("Is Symmetric");
142 
143  std::string name = "Basic Inverse";
144  if (pl.isParameter("Strategy Name")) name = pl.get<std::string>("Strategy Name");
145  const Teuchos::ParameterEntry* pe = pl.getEntryPtr("Strategy Settings");
146 
147  // check for a mistake in input file
148  if (name != "Basic Inverse" && pe == 0) {
149  RCP<Teuchos::FancyOStream> out = getOutputStream();
150  *out << "LSC Construction failed: ";
151  *out << "Strategy \"" << name << "\" requires a \"Strategy Settings\" sublist" << std::endl;
152  throw std::runtime_error("LSC Construction failed: Strategy Settings not set");
153  }
154 
155  // get the parameter list to construct the strategy
156  Teuchos::RCP<const Teuchos::ParameterList> stratPL = Teuchos::rcpFromRef(pl);
157  if (pe != 0) stratPL = Teuchos::rcpFromRef(pl.sublist("Strategy Settings"));
158 
159  // build the strategy object
160  RCP<LSCStrategy> strategy = buildStrategy(name, *stratPL, invLib, getRequestHandler());
161 
162  // strategy could not be built
163  if (strategy == Teuchos::null) {
164  RCP<Teuchos::FancyOStream> out = getOutputStream();
165  *out << "LSC Construction failed: ";
166  *out << "Strategy \"" << name << "\" could not be constructed" << std::endl;
167  throw std::runtime_error("LSC Construction failed: Strategy could not be constructed");
168  }
169 
170  strategy->setSymmetric(isSymmetric_);
171  invOpsStrategy_ = strategy;
172 }
173 
175 Teuchos::RCP<Teuchos::ParameterList> LSCPreconditionerFactory::getRequestedParameters() const {
176  return invOpsStrategy_->getRequestedParameters();
177 }
178 
180 bool LSCPreconditionerFactory::updateRequestedParameters(const Teuchos::ParameterList& pl) {
181  return invOpsStrategy_->updateRequestedParameters(pl);
182 }
183 
185 // Static members and methods
187 
189 CloneFactory<LSCStrategy> LSCPreconditionerFactory::strategyBuilder_;
190 
203 RCP<LSCStrategy> LSCPreconditionerFactory::buildStrategy(const std::string& name,
204  const Teuchos::ParameterList& settings,
205  const RCP<const InverseLibrary>& invLib,
206  const RCP<RequestHandler>& rh) {
207  Teko_DEBUG_SCOPE("LSCPreconditionerFactory::buildStrategy", 10);
208 
209  // initialize the defaults if necessary
210  if (strategyBuilder_.cloneCount() == 0) initializeStrategyBuilder();
211 
212  // request the preconditioner factory from the CloneFactory
213  Teko_DEBUG_MSG("Building LSC strategy \"" << name << "\"", 1);
214  RCP<LSCStrategy> strategy = strategyBuilder_.build(name);
215 
216  if (strategy == Teuchos::null) return Teuchos::null;
217 
218  // now that inverse library has been set,
219  // pass in the parameter list
220  strategy->setRequestHandler(rh);
221  strategy->initializeFromParameterList(settings, *invLib);
222 
223  return strategy;
224 }
225 
239 void LSCPreconditionerFactory::addStrategy(const std::string& name, const RCP<Cloneable>& clone) {
240  // initialize the defaults if necessary
241  if (strategyBuilder_.cloneCount() == 0) initializeStrategyBuilder();
242 
243  // add clone to builder
244  strategyBuilder_.addClone(name, clone);
245 }
246 
248 void LSCPreconditionerFactory::initializeStrategyBuilder() {
249  RCP<Cloneable> clone;
250 
251  // add various strategies to the factory
252  clone = rcp(new AutoClone<InvLSCStrategy>());
253  strategyBuilder_.addClone("Basic Inverse", clone);
254 
255  // add various strategies to the factory
256  clone = rcp(new AutoClone<PresLaplaceLSCStrategy>());
257  strategyBuilder_.addClone("Pressure Laplace", clone);
258 
259  // add various strategies to the factory
260  clone = rcp(new AutoClone<LSCSIMPLECStrategy>());
261  strategyBuilder_.addClone("SIMPLEC", clone);
262 }
263 
264 } // end namespace NS
265 } // end namespace Teko