Teko Version of the Day
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
27using Teuchos::RCP;
28using Teuchos::rcp_dynamic_cast;
29using Teuchos::rcp_const_cast;
30
31namespace Teko
32{
33
34namespace NS
35{
36
37// Empty constructor.
38InvModALStrategy::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.
46InvModALStrategy::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...
54InvModALStrategy::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...
63InvModALStrategy::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...
72InvModALStrategy::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".
81LinearOp InvModALStrategy::getInvA11p(BlockPreconditionerState & state) const
82{
83 return state.getInverse("invA11p");
84}
85
86LinearOp InvModALStrategy::getInvA22p(BlockPreconditionerState & state) const
87{
88 return state.getInverse("invA22p");
89}
90
91LinearOp InvModALStrategy::getInvA33p(BlockPreconditionerState & state) const
92{
93 return state.getInverse("invA33p");
94}
95
96LinearOp InvModALStrategy::getInvS(BlockPreconditionerState & state) const
97{
98 return state.getInverse("invS");
99}
100
101// Set pressure mass matrix.
102void InvModALStrategy::setPressureMassMatrix(const LinearOp & pressureMassMatrix)
103{
104 pressureMassMatrix_ = pressureMassMatrix;
105}
106
107// Set gamma.
108void InvModALStrategy::setGamma(double gamma)
109{
110 TEUCHOS_ASSERT(gamma > 0.0);
111 gamma_ = gamma;
112}
113
114void 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.
152void 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.
265void 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 scale(const double alpha, MultiVector &x)
Scale a multivector by a constant.
@ 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 rebuildInverse(const InverseFactory &factory, const LinearOp &A, const LinearOp &precOp, InverseLinearOp &invA)
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A, const LinearOp &precOp)