Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_InvModALStrategy.cpp
1 /*
2  * Author: Zhen Wang
3  * Email: wangz@ornl.gov
4  * zhen.wang@alum.emory.edu
5  */
6 
7 #include "Thyra_DefaultDiagonalLinearOp.hpp"
8 #include "Thyra_EpetraThyraWrappers.hpp"
9 #include "Thyra_get_Epetra_Operator.hpp"
10 #include "Thyra_EpetraLinearOp.hpp"
11 #include "Thyra_DefaultAddedLinearOp_def.hpp"
12 #include "Thyra_DefaultIdentityLinearOp_decl.hpp"
13 
14 #include "Epetra_Vector.h"
15 #include "Epetra_Map.h"
16 
17 #include "EpetraExt_RowMatrixOut.h"
18 #include "EpetraExt_MultiVectorOut.h"
19 
20 #include "Teuchos_Time.hpp"
21 
22 #include "Teko_Utilities.hpp"
23 
24 #include "Teko_InvModALStrategy.hpp"
25 #include "Teko_ModALPreconditionerFactory.hpp"
26 
27 using Teuchos::RCP;
28 using Teuchos::rcp_dynamic_cast;
29 using Teuchos::rcp_const_cast;
30 
31 namespace Teko
32 {
33 
34 namespace NS
35 {
36 
37 // Empty constructor.
38 InvModALStrategy::InvModALStrategy() :
39  invFactoryA_(Teuchos::null), invFactoryS_(Teuchos::null),
40  pressureMassMatrix_(Teuchos::null), gamma_(0.05),
41  scaleType_(Diagonal), isSymmetric_(true)
42 {
43 }
44 
45 // If there is only one InverseFactory, use it for all solves.
46 InvModALStrategy::InvModALStrategy(const Teuchos::RCP<InverseFactory> & factory) :
47  invFactoryA_(factory), invFactoryS_(factory),
48  pressureMassMatrix_(Teuchos::null), gamma_(0.05),
49  scaleType_(Diagonal), isSymmetric_(true)
50 {
51 }
52 
53 // If there are two InverseFactory's...
54 InvModALStrategy::InvModALStrategy(const Teuchos::RCP<InverseFactory> & invFactoryA,
55  const Teuchos::RCP<InverseFactory> & invFactoryS) :
56  invFactoryA_(invFactoryA), invFactoryS_(invFactoryS),
57  pressureMassMatrix_(Teuchos::null), gamma_(0.05),
58  scaleType_(Diagonal), isSymmetric_(true)
59 {
60 }
61 
62 // If there are two InverseFactory's...
63 InvModALStrategy::InvModALStrategy(const Teuchos::RCP<InverseFactory> & invFactory,
64  LinearOp & pressureMassMatrix) :
65  invFactoryA_(invFactory), invFactoryS_(invFactory),
66  pressureMassMatrix_(pressureMassMatrix), gamma_(0.05),
67  scaleType_(Diagonal), isSymmetric_(true)
68 {
69 }
70 
71 // If there are two InverseFactory's...
72 InvModALStrategy::InvModALStrategy(const Teuchos::RCP<InverseFactory> & invFactoryA,
73  const Teuchos::RCP<InverseFactory> & invFactoryS, LinearOp & pressureMassMatrix) :
74  invFactoryA_(invFactoryA), invFactoryS_(invFactoryS),
75  pressureMassMatrix_(pressureMassMatrix), gamma_(0.05),
76  scaleType_(Diagonal), isSymmetric_(true)
77 {
78 }
79 
80 // Return "inverses".
81 LinearOp InvModALStrategy::getInvA11p(BlockPreconditionerState & state) const
82 {
83  return state.getInverse("invA11p");
84 }
85 
86 LinearOp InvModALStrategy::getInvA22p(BlockPreconditionerState & state) const
87 {
88  return state.getInverse("invA22p");
89 }
90 
91 LinearOp InvModALStrategy::getInvA33p(BlockPreconditionerState & state) const
92 {
93  return state.getInverse("invA33p");
94 }
95 
96 LinearOp InvModALStrategy::getInvS(BlockPreconditionerState & state) const
97 {
98  return state.getInverse("invS");
99 }
100 
101 // Set pressure mass matrix.
102 void InvModALStrategy::setPressureMassMatrix(const LinearOp & pressureMassMatrix)
103 {
104  pressureMassMatrix_ = pressureMassMatrix;
105 }
106 
107 // Set gamma.
108 void InvModALStrategy::setGamma(double gamma)
109 {
110  TEUCHOS_ASSERT(gamma > 0.0);
111  gamma_ = gamma;
112 }
113 
114 void InvModALStrategy::buildState(const BlockedLinearOp & alOp,
115  BlockPreconditionerState & state) const
116 {
117  Teko_DEBUG_SCOPE("InvModALStrategy::buildState", 10);
118 
119  ModALPrecondState * modALState = dynamic_cast<ModALPrecondState*>(&state);
120  TEUCHOS_ASSERT(modALState != NULL);
121 
122  // if necessary save state information
123  if(not modALState->isInitialized())
124  {
125  Teko_DEBUG_EXPR(Teuchos::Time timer(""));
126 
127  {
128  // construct operators
129  Teko_DEBUG_SCOPE("ModAL::buildState: Initializing state object", 1);
130  Teko_DEBUG_EXPR(timer.start(true));
131 
132  initializeState(alOp, modALState);
133 
134  Teko_DEBUG_EXPR(timer.stop());
135  Teko_DEBUG_MSG("ModAL::buildState: BuildOpsTime = " << timer.totalElapsedTime(), 1);
136  }
137 
138  {
139  // Build the inverses
140  Teko_DEBUG_SCOPE("ModAL::buildState: Computing inverses", 1);
141  Teko_DEBUG_EXPR(timer.start(true));
142 
143  computeInverses(alOp, modALState);
144 
145  Teko_DEBUG_EXPR(timer.stop());
146  Teko_DEBUG_MSG("ModAL::buildState: BuildInvTime = " << timer.totalElapsedTime(), 1);
147  }
148  }
149 }
150 
151 // Initialize the state object using the ALOperator.
152 void InvModALStrategy::initializeState(const BlockedLinearOp & alOp,
153  ModALPrecondState *state) const
154 {
155  Teko_DEBUG_SCOPE("InvModALStrategy::initializeState", 10);
156 
157  // Extract sub-matrices from blocked linear operator.
158  int dim = blockRowCount(alOp) - 1;
159  TEUCHOS_ASSERT(dim == 2 || dim == 3);
160 
161  LinearOp lpA11 = getBlock(0, 0, alOp);
162  LinearOp lpA22 = getBlock(1, 1, alOp);
163  LinearOp lpA33, lpB1, lpB2, lpB3, lpB1t, lpB2t, lpB3t, lpC;
164 
165  // 2D problem.
166  if(dim == 2)
167  {
168  lpB1 = getBlock(2, 0, alOp);
169  lpB2 = getBlock(2, 1, alOp);
170  lpB1t = getBlock(0, 2, alOp);
171  lpB2t = getBlock(1, 2, alOp);
172  lpC = getBlock(2, 2, alOp);
173  }
174  // 3D problem.
175  else if(dim == 3)
176  {
177  lpA33 = getBlock(2, 2, alOp);
178  lpB1 = getBlock(3, 0, alOp);
179  lpB2 = getBlock(3, 1, alOp);
180  lpB3 = getBlock(3, 2, alOp);
181  lpB1t = getBlock(0, 3, alOp);
182  lpB2t = getBlock(1, 3, alOp);
183  lpB3t = getBlock(2, 3, alOp);
184  lpC = getBlock(3, 3, alOp);
185  }
186 
187  // For problems using stabilized finite elements,
188  // lpB1t, lpB2t and lpB3t are added linear operators. Extract original operators.
189  LinearOp B1t = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpB1t))->getOp(0);
190  LinearOp B2t = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpB2t))->getOp(0);
191  LinearOp B3t;
192  if(dim == 3)
193  {
194  B3t = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpB3t))->getOp(0);
195  }
196 
197  //std::cout << Teuchos::describe(*lpC, Teuchos::VERB_EXTREME) << std::endl;
198  // Check whether the finite elements are stable or not.
199  state->isStabilized_ =(not isZeroOp(lpC));
200  //state->isStabilized_ = false;
201  //std::cout << state->isStabilized_ << std::endl;
202 
203  state->pressureMassMatrix_ = pressureMassMatrix_;
204  // If pressure mass matrix is not set, use identity.
205  if(state->pressureMassMatrix_ == Teuchos::null)
206  {
207  Teko_DEBUG_MSG("InvModALStrategy::initializeState(): Build identity type \""
208  << getDiagonalName(scaleType_) << "\"", 1);
209  state->invPressureMassMatrix_ = Thyra::identity<double>(lpB1->range());
210  }
211  // If the inverse of the pressure mass matrix is not set,
212  // build it from the pressure mass matrix.
213  else if(state->invPressureMassMatrix_ == Teuchos::null)
214  {
215  Teko_DEBUG_MSG("ModAL::initializeState(): Build Scaling <mass> type \""
216  << getDiagonalName(scaleType_) << "\"", 1);
217  state->invPressureMassMatrix_ = getInvDiagonalOp(pressureMassMatrix_, scaleType_);
218  }
219  // Else "invPressureMassMatrix_" should be set and there is no reason to rebuild it
220  state->gamma_ = gamma_;
221  //S_ = scale(1.0/gamma_, pressureMassMatrix_);
222  std::cout << Teuchos::describe(*(state->invPressureMassMatrix_), Teuchos::VERB_EXTREME) << std::endl;
223 
224  // Build state variables: B_1^T*W^{-1}*B_1, A11p, etc.
225  // B_1^T*W^{-1}*B_1 may not change so save it in the state.
226  if(state->B1tMpB1_ == Teuchos::null)
227  state->B1tMpB1_ = explicitMultiply(B1t, state->invPressureMassMatrix_, lpB1, state->B1tMpB1_);
228  // Get the(1,1) block of the non-augmented matrix.
229  // Recall alOp is augmented. So lpA11 = A11 + gamma B_1^T W^{-1} B_1.
230  // Cast lpA11 as an added linear operator and get the first item.
231  LinearOp A11 = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpA11))->getOp(0);
232  state->A11p_ = explicitAdd(A11, scale(state->gamma_, state->B1tMpB1_), state->A11p_);
233  //std::cout << Teuchos::describe(*(state->B1tMpB1_), Teuchos::VERB_EXTREME) << std::endl;
234  Teko_DEBUG_MSG("Computed A11p", 10);
235 
236  if(state->B2tMpB2_ == Teuchos::null)
237  state->B2tMpB2_ = explicitMultiply(B2t, state->invPressureMassMatrix_, lpB2, state->B2tMpB2_);
238  LinearOp A22 = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpA22))->getOp(0);
239  state->A22p_ = explicitAdd(A22, scale(state->gamma_, state->B2tMpB2_), state->A22p_);
240  Teko_DEBUG_MSG("Computed A22p", 10);
241 
242  if(dim == 3)
243  {
244  if(state->B3tMpB3_ == Teuchos::null)
245  state->B3tMpB3_ = explicitMultiply(B3t, state->invPressureMassMatrix_, lpB3, state->B3tMpB3_);
246  LinearOp A33 = (rcp_dynamic_cast<const Thyra::DefaultAddedLinearOp<double> >(lpA33))->getOp(0);
247  state->A33p_ = explicitAdd(A33, scale(state->gamma_, state->B3tMpB3_), state->A33p_);
248  Teko_DEBUG_MSG("Computed A33p", 10);
249  }
250 
251  // Inverse the Schur complement.
252  if(state->isStabilized_)
253  {
254  if(state->S_ == Teuchos::null)
255  {
256  state->S_ = explicitAdd(scale(-1.0, lpC), scale(1.0/state->gamma_, pressureMassMatrix_), state->S_);
257  }
258  Teko_DEBUG_MSG("Computed S", 10);
259  }
260 
261  state->setInitialized(true);
262 }
263 
264 // Compute inverses.
265 void InvModALStrategy::computeInverses(const BlockedLinearOp & alOp,
266  ModALPrecondState *state) const
267 {
268  int dim = blockRowCount(alOp) - 1;
269  TEUCHOS_ASSERT(dim == 2 || dim == 3);
270 
271  Teko_DEBUG_SCOPE("InvModALStrategy::computeInverses", 10);
272  Teko_DEBUG_EXPR(Teuchos::Time invTimer(""));
273 
274  //(re)build the inverse of A11
275  Teko_DEBUG_MSG("ModAL::computeInverses(): Building inv(A11)", 1);
276  Teko_DEBUG_EXPR(invTimer.start(true));
277 
278  InverseLinearOp invA11p = state->getInverse("invA11p");
279  if(invA11p == Teuchos::null)
280  {
281  invA11p = buildInverse(*invFactoryA_, state->A11p_);
282  state->addInverse("invA11p", invA11p);
283  }
284  else
285  {
286  rebuildInverse(*invFactoryA_, state->A11p_, invA11p);
287  }
288 
289  Teko_DEBUG_EXPR(invTimer.stop());
290  Teko_DEBUG_MSG("ModAL::computeInverses GetInvA11 = " << invTimer.totalElapsedTime(), 1);
291 
292  //(re)build the inverse of A22
293  Teko_DEBUG_MSG("ModAL::computeInverses(): Building inv(A22)", 2);
294  Teko_DEBUG_EXPR(invTimer.start(true));
295 
296  InverseLinearOp invA22p = state->getInverse("invA22p");
297  if(invA22p == Teuchos::null)
298  {
299  invA22p = buildInverse(*invFactoryA_, state->A22p_);
300  state->addInverse("invA22p", invA22p);
301  }
302  else
303  {
304  rebuildInverse(*invFactoryA_, state->A22p_, invA22p);
305  }
306 
307  Teko_DEBUG_EXPR(invTimer.stop());
308  Teko_DEBUG_MSG("ModAL::computeInverses(): GetInvA22 = " << invTimer.totalElapsedTime(), 2);
309 
310  //(re)build the inverse of A33
311  if(dim == 3)
312  {
313  Teko_DEBUG_MSG("ModAL::computeInverses Building inv(A33)", 3);
314  Teko_DEBUG_EXPR(invTimer.start(true));
315 
316  InverseLinearOp invA33p = state->getInverse("invA33p");
317  if(invA33p == Teuchos::null)
318  {
319  invA33p = buildInverse(*invFactoryA_, state->A33p_);
320  state->addInverse("invA33p", invA33p);
321  }
322  else
323  {
324  rebuildInverse(*invFactoryA_, state->A33p_, invA33p);
325  }
326 
327  Teko_DEBUG_EXPR(invTimer.stop());
328  Teko_DEBUG_MSG("ModAL::computeInverses GetInvA33 = " << invTimer.totalElapsedTime(), 3);
329  }
330 
331  //(re)build the inverse of S
332  Teko_DEBUG_MSG("ModAL::computeInverses Building inv(S)", 4);
333  Teko_DEBUG_EXPR(invTimer.start(true));
334 
335  // There are two ways to "invert" S.
336  // The following method construct invS by InverseFactory invFactoryS_.
337  // The other way is to use diagonal approximation,
338  // which is done in ModALPreconditionerFactory.cpp.
339  if(state->isStabilized_)
340  {
341  InverseLinearOp invS = state->getInverse("invS");
342  if(invS == Teuchos::null)
343  {
344  invS = buildInverse(*invFactoryS_, state->S_);
345  state->addInverse("invS", invS);
346  }
347  else
348  {
349  rebuildInverse(*invFactoryS_, state->S_, invS);
350  }
351  }
352 
353  Teko_DEBUG_EXPR(invTimer.stop());
354  Teko_DEBUG_MSG("ModAL::computeInverses GetInvS = " << invTimer.totalElapsedTime(), 4);
355 
356 }
357 
358 } // end namespace NS
359 
360 } // end namespace Teko
void rebuildInverse(const InverseFactory &factory, const LinearOp &A, InverseLinearOp &invA)
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A)
Build an inverse operator using a factory and a linear operator.