Stratimikos Version of the Day
Loading...
Searching...
No Matches
Thyra_AztecOOLinearOpWithSolveFactory.cpp
1// @HEADER
2// *****************************************************************************
3// Stratimikos: Thyra-based strategies for linear solvers
4//
5// Copyright 2006 NTESS and the Stratimikos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef SUN_CXX
11
12
13#include "Thyra_AztecOOLinearOpWithSolveFactory.hpp"
14#include "Thyra_AztecOOLinearOpWithSolve.hpp"
15#include "Thyra_PreconditionerFactoryHelpers.hpp"
16#include "Thyra_EpetraOperatorViewExtractorStd.hpp"
17#include "Thyra_ScaledAdjointLinearOpBase.hpp"
18#include "Thyra_EpetraLinearOpBase.hpp"
19#include "Thyra_EpetraOperatorWrapper.hpp"
21#include "Teuchos_VerboseObjectParameterListHelpers.hpp"
22#include "Teuchos_ParameterList.hpp"
23#include "Teuchos_dyn_cast.hpp"
24#include "AztecOOParameterList.hpp"
25
26
27namespace {
28
29
30const std::string AOOLOWSF_epetraPrecOp_str
31= "AOOLOWSF::epetraPrecOp";
32const std::string AOOLOWSF_aztec_epetra_epetraFwdOp_str
33= "AOOLOWSF::aztec_epetra_epetraFwdOp";
34const std::string AOOLOWSF_aztec_epetra_epetraAdjOp_str
35= "AOOLOWSF::aztec_epetra_epetraAdjOp";
36const std::string AOOLOWSF_rowmatrix_epetraFwdOp_str
37= "AOOLOWSF::rowmatrix_epetraFwdOp";
38const std::string AOOLOWSF_rowmatrix_epetraPrecOp_str
39= "AOOLOWSF::rowmatrix_epetraPrecOp";
40const std::string AOOLOWSF_aztec_fwd_epetra_epetraPrecOp_str
41= "AOOLOWSF::aztec_fwd_epetra_epetraPrecOp";
42const std::string AOOLOWSF_aztec_adj_epetra_epetraPrecOp_str
43= "AOOLOWSF::aztec_adj_epetra_epetraPrecOp";
44const std::string AOOLOWSF_setPrecondtionerOperator_str
45= "AOOLOWSF::setPrecondtionerOperator";
46const std::string AOOLOWSF_constructedAztecPreconditoner_str
47= "AOOLOWSF::constructedAztecPreconditoner";
48
49
50const std::string ForwardSolve_name = "Forward Solve";
51const std::string AdjointSolve_name = "Adjoint Solve";
52const std::string MaxIterations_name = "Max Iterations";
53const int MaxIterations_default = 400;
54const std::string Tolerance_name = "Tolerance";
55const double Tolerance_default = 1e-6;
56const std::string OutputEveryRhs_name = "Output Every RHS";
57const bool OutputEveryRhs_default = false;
58const std::string AztecOO_Settings_name = "AztecOO Settings";
59
60
61} // namespace
62
63
64namespace Thyra {
65
66
67// Constructors/initializers/accessors
68
69
71 Teuchos::RCP<Teuchos::ParameterList> const& paramList
72 )
73 :epetraFwdOpViewExtractor_(Teuchos::rcp(new EpetraOperatorViewExtractorStd()))
74 ,defaultFwdMaxIterations_(MaxIterations_default)
75 ,defaultFwdTolerance_(Tolerance_default)
76 ,defaultAdjMaxIterations_(MaxIterations_default)
77 ,defaultAdjTolerance_(Tolerance_default)
78 ,outputEveryRhs_(OutputEveryRhs_default)
79 ,useAztecPrec_(false)
80{
81 updateThisValidParamList();
82 if(paramList.get())
83 setParameterList(paramList);
84}
85
86
87// Overridden from LinearOpWithSolveFactoryBase
88
89
94
95
97 const Teuchos::RCP<PreconditionerFactoryBase<double> > &precFactory,
98 const std::string &precFactoryName
99 )
100{
101 TEUCHOS_TEST_FOR_EXCEPT(!precFactory.get());
102 Teuchos::RCP<const Teuchos::ParameterList>
103 precFactoryValidPL = precFactory->getValidParameters();
104 const std::string _precFactoryName =
105 ( precFactoryName != ""
106 ? precFactoryName
107 : ( precFactoryValidPL.get()
108 ? precFactoryValidPL->name()
109 : "GENERIC PRECONDITIONER FACTORY"
110 )
111 );
112 precFactory_ = precFactory;
113 precFactoryName_ = _precFactoryName;
114 updateThisValidParamList();
115}
116
117
118Teuchos::RCP<PreconditionerFactoryBase<double> >
120{
121 return precFactory_;
122}
123
124
126 Teuchos::RCP<PreconditionerFactoryBase<double> > *precFactory,
127 std::string *precFactoryName
128 )
129{
130 if(precFactory) *precFactory = precFactory_;
131 if(precFactoryName) *precFactoryName = precFactoryName_;
132 precFactory_ = Teuchos::null;
133 precFactoryName_ = "";
134 updateThisValidParamList();
135}
136
137
139 const LinearOpSourceBase<double> &fwdOpSrc
140 ) const
141{
142 return epetraFwdOpViewExtractor_->isCompatible(*fwdOpSrc.getOp());
143}
144
145
146Teuchos::RCP<LinearOpWithSolveBase<double> >
148{
149 return Teuchos::rcp(new AztecOOLinearOpWithSolve());
150}
151
152
154 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
155 LinearOpWithSolveBase<double> *Op,
156 const ESupportSolveUse /* supportSolveUse */
157 ) const
158{
159 this->initializeOp_impl(fwdOpSrc,Teuchos::null,Teuchos::null,false,Op);
160}
161
162
164 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
165 LinearOpWithSolveBase<double> *Op
166 ) const
167{
168 this->initializeOp_impl(fwdOpSrc,Teuchos::null,Teuchos::null,true,Op);
169}
170
171
173 const EPreconditionerInputType precOpType
174 ) const
175{
176 const_cast<bool&>(useAztecPrec_) = (
177 paramList_.get()
178 &&
179 paramList_->sublist(ForwardSolve_name).sublist(AztecOO_Settings_name).get(
180 "Aztec Preconditioner","none"
181 )!="none"
182 );
183 switch(precOpType) {
184 case PRECONDITIONER_INPUT_TYPE_AS_OPERATOR:
185 return true;
186 case PRECONDITIONER_INPUT_TYPE_AS_MATRIX:
187 return useAztecPrec_;
188 default:
189 TEUCHOS_TEST_FOR_EXCEPT(true);
190 }
191 TEUCHOS_UNREACHABLE_RETURN(PRECONDITIONER_INPUT_TYPE_AS_OPERATOR);
192}
193
194
196 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
197 const Teuchos::RCP<const PreconditionerBase<double> > &prec,
198 LinearOpWithSolveBase<double> *Op,
199 const ESupportSolveUse /* supportSolveUse */
200 ) const
201{
202 TEUCHOS_TEST_FOR_EXCEPT(prec.get()==NULL);
203 this->initializeOp_impl(fwdOpSrc,prec,Teuchos::null,false,Op);
204}
205
206
208 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
209 const Teuchos::RCP<const LinearOpSourceBase<double> > &approxFwdOpSrc,
210 LinearOpWithSolveBase<double> *Op,
211 const ESupportSolveUse /* supportSolveUse */
212 ) const
213{
214 TEUCHOS_TEST_FOR_EXCEPT(approxFwdOpSrc.get()==NULL);
215 TEUCHOS_TEST_FOR_EXCEPT(approxFwdOpSrc->getOp().get()==NULL);
216 this->initializeOp_impl(fwdOpSrc,Teuchos::null,approxFwdOpSrc,false,Op);
217}
218
219
221 LinearOpWithSolveBase<double> *Op,
222 Teuchos::RCP<const LinearOpSourceBase<double> > *fwdOpSrc,
223 Teuchos::RCP<const PreconditionerBase<double> > *prec,
224 Teuchos::RCP<const LinearOpSourceBase<double> > *approxFwdOpSrc,
225 ESupportSolveUse * /* supportSolveUse */
226 ) const
227{
228#ifdef TEUCHOS_DEBUG
229 TEUCHOS_TEST_FOR_EXCEPT(Op==NULL);
230#endif
232 *aztecOp = &Teuchos::dyn_cast<AztecOOLinearOpWithSolve>(*Op);
233 // Extract and unset the fwdOP and approxFwdOp objects
234 Teuchos::RCP<const LinearOpSourceBase<double> >
235 _fwdOpSrc = aztecOp->extract_fwdOpSrc(), // Will be null if not initialized!
236 _approxFwdOpSrc = aztecOp->extract_approxFwdOpSrc(); // Will be null if not set
237 if(fwdOpSrc) *fwdOpSrc = _fwdOpSrc;
238 if(approxFwdOpSrc) *approxFwdOpSrc = _approxFwdOpSrc;
239 // Only extract and uset the prec object if it is external. If it is
240 // internal, then we need to hold on to this so that we can reinitialize it
241 // later.
242 if(aztecOp->isExternalPrec()) {
243 Teuchos::RCP<const PreconditionerBase<double> >
244 _prec = aztecOp->extract_prec(); // Will be null if not external preconditioner was set
245 if(prec) *prec = _prec;
246 }
247 // ToDo: Extract the Epetra_Operator views what where used to initialize the
248 // forward and adjoint solvers! This is needed to make this totally
249 // stateless.
250}
251
252
253// Overridden from ParameterListAcceptor
254
255
257 Teuchos::RCP<Teuchos::ParameterList> const& paramList
258 )
259{
260 TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==NULL);
261 paramList->validateParameters(*this->getValidParameters());
262 paramList_ = paramList;
263 //
264 outputEveryRhs_ = paramList_->get(OutputEveryRhs_name,OutputEveryRhs_default);
265 // Foward Solve parameters
266 Teuchos::ParameterList
267 &fwdSolvePL = paramList_->sublist(ForwardSolve_name);
268 defaultFwdMaxIterations_ = fwdSolvePL.get(MaxIterations_name,defaultFwdMaxIterations_);
269 defaultFwdTolerance_ = fwdSolvePL.get(Tolerance_name,defaultFwdTolerance_);
270 // Adjoint Solve parameters
271 if( !paramList_->getPtr<Teuchos::ParameterList>(AdjointSolve_name) ) {
272 // If adjoint solve sublist is not set, then use the forward solve parameters
273 paramList_->sublist(AdjointSolve_name).setParameters(fwdSolvePL);
274 }
275 Teuchos::ParameterList
276 &adjSolvePL = paramList_->sublist(AdjointSolve_name);
277 defaultAdjMaxIterations_ = adjSolvePL.get(MaxIterations_name,defaultAdjMaxIterations_);
278 defaultAdjTolerance_ = adjSolvePL.get(Tolerance_name,defaultAdjTolerance_);
279 //
280 if(precFactory_.get()) {
281 // Only reset the PF's PL if the sublist exists or the PF does not already
282 // have a PL. We don't want to overwrite an externally set PL for the PF
283 // if we don't have a nested sublist defined here!
284 const bool nestedPFSublistExists = paramList_->isSublist(precFactoryName_);
285 const bool alreadyHasSublist = !is_null(precFactory_->getParameterList());
286 if( nestedPFSublistExists || !alreadyHasSublist ) {
287 precFactory_->setParameterList(Teuchos::sublist(paramList_,precFactoryName_));
288 }
289 }
290 Teuchos::readVerboseObjectSublist(&*paramList_,this);
291}
292
293
294Teuchos::RCP<Teuchos::ParameterList>
299
300
301Teuchos::RCP<Teuchos::ParameterList>
303{
304 Teuchos::RCP<Teuchos::ParameterList> _paramList = paramList_;
305 paramList_ = Teuchos::null;
306 return _paramList;
307}
308
309
310Teuchos::RCP<const Teuchos::ParameterList>
312{
313 return paramList_;
314}
315
316
317Teuchos::RCP<const Teuchos::ParameterList>
319{
320 return thisValidParamList_;
321}
322
323
324// Public functions overridden from Teuchos::Describable
325
326
328{
329 std::ostringstream oss;
330 oss << "Thyra::AztecOOLinearOpWithSolveFactory{";
331 oss << "precFactory=";
332 if(!is_null(precFactory_))
333 oss << precFactory_->description();
334 else
335 oss << "NULL";
336 oss << "}";
337 return oss.str();
338}
339
340
341// private
342
343
344Teuchos::RCP<const Teuchos::ParameterList>
345AztecOOLinearOpWithSolveFactory::generateAndGetValidParameters()
346{
347 static Teuchos::RCP<Teuchos::ParameterList> validParamList;
348 if(validParamList.get()==NULL) {
349 validParamList = Teuchos::rcp(
350 new Teuchos::ParameterList("AztecOOLinearOpWithSolveFactory"));
351 validParamList->set(
352 OutputEveryRhs_name,OutputEveryRhs_default
353 ,"Determines if output is created for each individual RHS (true or 1) or if output\n"
354 "is just created for an entire set of RHSs (false or 0)."
355 );
356 static Teuchos::RCP<const Teuchos::ParameterList>
357 aztecParamList = getValidAztecOOParameters();
358 Teuchos::ParameterList
359 &fwdSolvePL = validParamList->sublist(
360 ForwardSolve_name, false
361 ,"Gives the options for the forward solve."
362 );
363 fwdSolvePL.set(
364 Tolerance_name,Tolerance_default
365 ,"The tolerence used in the convergence check (see the convergence test\n"
366 "in the sublist \"" + AztecOO_Settings_name + "\")"
367 );
368 fwdSolvePL.set(
369 MaxIterations_name,MaxIterations_default
370 ,"The maximum number of iterations the AztecOO solver is allowed to perform."
371 );
372 fwdSolvePL.sublist(
373 AztecOO_Settings_name,false
374 ,"Sets the parameters on the AztecOO object itself."
375 ).setParameters(*aztecParamList);
376 Teuchos::ParameterList
377 &adjSolvePL = validParamList->sublist(
378 AdjointSolve_name, false
379 ,"The options for the adjoint solve.\n"
380 "If this sublist is missing then the parameters from the\n"
381 "\""+ForwardSolve_name+"\" sublist are used instead."
382 );
383 // Make the adjoint solve have same defaults as forward solve
384 adjSolvePL.setParameters(fwdSolvePL);
385 }
386 return validParamList;
387}
388
389
390void AztecOOLinearOpWithSolveFactory::updateThisValidParamList()
391{
392 thisValidParamList_ = Teuchos::rcp(
393 new Teuchos::ParameterList(*generateAndGetValidParameters())
394 );
395 if(precFactory_.get()) {
396 Teuchos::RCP<const Teuchos::ParameterList>
397 precFactoryValidParamList = precFactory_->getValidParameters();
398 if(precFactoryValidParamList.get()) {
399 thisValidParamList_->sublist(precFactoryName_).setParameters(
400 *precFactoryValidParamList);
401 }
402 }
403 Teuchos::setupVerboseObjectSublist(&*thisValidParamList_);
404}
405
406
407void AztecOOLinearOpWithSolveFactory::initializeOp_impl(
408 const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
409 const Teuchos::RCP<const PreconditionerBase<double> > &prec,
410 const Teuchos::RCP<const LinearOpSourceBase<double> > &approxFwdOpSrc,
411 const bool reusePrec,
412 LinearOpWithSolveBase<double> *Op
413 ) const
414{
415 using Teuchos::RCP;
416 using Teuchos::null;
417 using Teuchos::rcp;
418 using Teuchos::rcp_dynamic_cast;
419 using Teuchos::rcp_const_cast;
420 using Teuchos::set_extra_data;
421 using Teuchos::get_optional_extra_data;
422 using Teuchos::get_optional_nonconst_extra_data;
423 using Teuchos::outArg;
425
426 const Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
427 const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
428 Teuchos::OSTab tab(out);
429 if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_LOW))
430 *out << "\nEntering Thyra::AztecOOLinearOpWithSolveFactory::initializeOp_impl(...) ...\n";
431
432 typedef Teuchos::VerboseObjectTempState<PreconditionerFactoryBase<double> > VOTSPF;
433 VOTSPF precFactoryOutputTempState(precFactory_,out,verbLevel);
434
435#ifdef TEUCHOS_DEBUG
436 TEUCHOS_TEST_FOR_EXCEPT(Op==NULL);
437 TEUCHOS_TEST_FOR_EXCEPT(fwdOpSrc.get()==NULL);
438 TEUCHOS_TEST_FOR_EXCEPT(fwdOpSrc->getOp().get()==NULL);
439#endif
440
441 //
442 // Determine whether the operators are EpetraLinearOp objects. If so, we're
443 // good to go. If not, we need to wrap it as an Epetra_Operator with some
444 // invasive code.
445 //
446 Teuchos::RCP<const LinearOpBase<double> >
447 tmpFwdOp = fwdOpSrc->getOp(),
448 tmpApproxFwdOp = ( approxFwdOpSrc.get() ? approxFwdOpSrc->getOp() : Teuchos::null );
449 Teuchos::RCP<const LinearOpBase<double> > fwdOp;
450 Teuchos::RCP<const LinearOpBase<double> > approxFwdOp;
451 if ( dynamic_cast<const EpetraLinearOpBase*>(tmpFwdOp.get())!=0 )
452 {
453 fwdOp = tmpFwdOp;
454 approxFwdOp = tmpApproxFwdOp;
455 }
456 else
457 {
458 fwdOp = makeEpetraWrapper(tmpFwdOp);
459 if (
460 tmpApproxFwdOp.get()
461 &&
462 dynamic_cast<const EpetraLinearOpBase*>(&*tmpApproxFwdOp.get())
463 )
464 {
465 approxFwdOp = makeEpetraWrapper(tmpApproxFwdOp);
466 }
467 }
468
469 //
470 // Get the AztecOOLinearOpWithSolve object
471 //
472 AztecOOLinearOpWithSolve
473 *aztecOp = &Teuchos::dyn_cast<AztecOOLinearOpWithSolve>(*Op);
474
475 //
476 // Unwrap and get the forward operator or matrix
477 //
478 Teuchos::RCP<const Epetra_Operator> epetra_epetraFwdOp;
479 EOpTransp epetra_epetraFwdOpTransp;
480 EApplyEpetraOpAs epetra_epetraFwdOpApplyAs;
481 EAdjointEpetraOp epetra_epetraFwdOpAdjointSupport;
482 double epetra_epetraFwdOpScalar;
483 epetraFwdOpViewExtractor_->getEpetraOpView(
484 fwdOp,
485 outArg(epetra_epetraFwdOp), outArg(epetra_epetraFwdOpTransp),
486 outArg(epetra_epetraFwdOpApplyAs), outArg(epetra_epetraFwdOpAdjointSupport),
487 outArg(epetra_epetraFwdOpScalar)
488 );
489 TEUCHOS_TEST_FOR_EXCEPTION(
490 epetra_epetraFwdOp.get()==NULL, std::logic_error
491 ,"Error, The input fwdOp object must be fully initialized "
492 "before calling this function!"
493 );
494
495 //
496 // Get the preconditioner object to use
497 //
498 Teuchos::RCP<PreconditionerBase<double> > myPrec;
499 Teuchos::RCP<const PreconditionerBase<double> > precUsed;
500 if (prec.get()) {
501 // We will be used the passed in external preconditioner
502 precUsed = prec;
503 }
504 else if (precFactory_.get() ) {
505 // We will be creating our own preconditioner using an externally set
506 // preconditioner factory
507 myPrec =
508 ( !aztecOp->isExternalPrec()
509 ? Teuchos::rcp_const_cast<PreconditionerBase<double> >(
510 aztecOp->extract_prec())
511 : Teuchos::null
512 );
513 if(myPrec.get()) {
514 // ToDo: Get the forward operator and validate that it is the same
515 // operator that is used here!
516 }
517 else {
518 myPrec = precFactory_->createPrec();
519 }
520 precFactory_->initializePrec(fwdOpSrc,&*myPrec);
521 precUsed = myPrec;
522 }
523
524 //
525 // Unwrap and get the preconditioner operator
526 //
527 RCP<const LinearOpBase<double> > rightPrecOp;
528 if (precUsed.get()) {
529 RCP<const LinearOpBase<double> > unspecified = precUsed->getUnspecifiedPrecOp();
530 RCP<const LinearOpBase<double> > left = precUsed->getLeftPrecOp();
531 RCP<const LinearOpBase<double> > right = precUsed->getRightPrecOp();
532 TEUCHOS_TEST_FOR_EXCEPTION(
533 !( left.get() || right.get() || unspecified.get() ), std::logic_error
534 ,"Error, at least one preconditoner linear operator objects must be set!"
535 );
536 if(unspecified.get()) {
537 rightPrecOp = unspecified;
538 }
539 else {
540 // Set a left, right or split preconditioner
541 TEUCHOS_TEST_FOR_EXCEPTION(
542 left.get(),std::logic_error
543 ,"Error, we can not currently handle a left"
544 " preconditioner with the AztecOO/Thyra adapters!"
545 );
546 rightPrecOp = right;
547 }
548 }
549 double wrappedPrecOpScalar = 0.0;
550 EOpTransp wrappedPrecOpTransp = NOTRANS;
551 RCP<const LinearOpBase<double> > wrappedPrecOp = null;
552 RCP<const EpetraLinearOpBase> epetraPrecOp;
553 Teuchos::RCP<const Epetra_Operator> epetra_epetraPrecOp;
554 EOpTransp epetra_epetraPrecOpTransp;
555 EApplyEpetraOpAs epetra_epetraPrecOpApplyAs;
556 EAdjointEpetraOp epetra_epetraPrecOpAdjointSupport;
557 EOpTransp overall_epetra_epetraPrecOpTransp=NOTRANS;
558 if(rightPrecOp.get()) {
559 RCP<const LinearOpBase<double> > tmpWrappedPrecOp;
560 unwrap(
561 rightPrecOp,&wrappedPrecOpScalar,&wrappedPrecOpTransp,&tmpWrappedPrecOp);
562 if( dynamic_cast<const EpetraLinearOpBase*>(&*tmpWrappedPrecOp) ) {
563 wrappedPrecOp = tmpWrappedPrecOp;
564 }
565 else {
566 wrappedPrecOp = makeEpetraWrapper(tmpWrappedPrecOp);
567 }
568 epetraPrecOp = rcp_dynamic_cast<const EpetraLinearOpBase>(
569 wrappedPrecOp,true);
570 epetraPrecOp->getEpetraOpView(
571 outArg(epetra_epetraPrecOp), outArg(epetra_epetraPrecOpTransp),
572 outArg(epetra_epetraPrecOpApplyAs), outArg(epetra_epetraPrecOpAdjointSupport));
573 TEUCHOS_TEST_FOR_EXCEPTION(
574 epetra_epetraPrecOp.get()==NULL,std::logic_error
575 ,"Error, The input prec object and its embedded preconditioner"
576 " operator must be fully initialized before calling this function!"
577 );
578 // 2007/08/10: rabartl: This next set_extra_data(...) call is likely to be
579 // setting up a circular reference! Since epetra_epetraPrecOp was
580 // gotten from epetraPrecOp, if you set epetraPrecOp as extra data
581 // on the RCP epetra_epetraPrecOp then you have a circular reference!
582 //set_extra_data(
583 // epetraPrecOp, AOOLOWSF_epetraPrecOp_str, &epetra_epetraPrecOp,
584 // Teuchos::POST_DESTROY, false );
585 overall_epetra_epetraPrecOpTransp
586 = trans_trans(
587 real_trans(wrappedPrecOpTransp),
588 real_trans(epetra_epetraPrecOpTransp)
589 );
590 }
591
592 //
593 // Unwrap and get the approximate forward operator to be used to generate a
594 // preconditioner
595 //
596 if(approxFwdOp.get()) {
597 // Note, here we just use the same members data that would be set for an
598 // extenral preconditioner operator since it is not getting used.
599 unwrap(approxFwdOp,&wrappedPrecOpScalar,&wrappedPrecOpTransp,&wrappedPrecOp);
600 epetraPrecOp = rcp_dynamic_cast<const EpetraLinearOpBase>(
601 wrappedPrecOp,true);
602 epetraPrecOp->getEpetraOpView(
603 outArg(epetra_epetraPrecOp), outArg(epetra_epetraPrecOpTransp),
604 outArg(epetra_epetraPrecOpApplyAs), outArg(epetra_epetraPrecOpAdjointSupport)
605 );
606 TEUCHOS_TEST_FOR_EXCEPTION(
607 epetra_epetraPrecOp.get()==NULL,std::logic_error
608 ,"Error, The input approxFwdOp object must be fully initialized"
609 " before calling this function!"
610 );
611 // 2007/08/10: rabartl: This next set_extra_data(...) call is likely to be
612 // setting up a circular reference! Since epetra_epetraPrecOp was
613 // gotten from epetraPrecOp, if you set epetraPrecOp as extra data
614 // on the RCP epetra_epetraPrecOp then you have a circular reference!
615 //set_extra_data(
616 // epetraPrecOp, AOOLOWSF_epetraPrecOp_str, &epetra_epetraPrecOp,
617 // Teuchos::POST_DESTROY, false
618 // );
619 overall_epetra_epetraPrecOpTransp
620 = trans_trans(
621 real_trans(wrappedPrecOpTransp),
622 real_trans(epetra_epetraPrecOpTransp)
623 );
624 }
625
626 //
627 // Determine if the forward and preconditioner operators are a row matrices
628 // or not
629 //
630 RCP<const Epetra_RowMatrix>
631 rowmatrix_epetraFwdOp = rcp_dynamic_cast<const Epetra_RowMatrix>(
632 epetra_epetraFwdOp),
633 rowmatrix_epetraPrecOp = rcp_dynamic_cast<const Epetra_RowMatrix>(
634 epetra_epetraPrecOp);
635 //
636 // Determine the type of preconditoner
637 //
638 // Update useAztecPrec_, input value does not matter
639 this->supportsPreconditionerInputType(PRECONDITIONER_INPUT_TYPE_AS_MATRIX);
640 enum ELocalPrecType {
641 PT_NONE, PT_AZTEC_FROM_OP, PT_AZTEC_FROM_APPROX_FWD_MATRIX,
642 PT_FROM_PREC_OP, PT_UPPER_BOUND
643 };
644 ELocalPrecType localPrecType = PT_UPPER_BOUND;
645 if( precUsed.get()==NULL && approxFwdOp.get()==NULL && !useAztecPrec_ ) {
646 // No preconditioning at all!
647 localPrecType = PT_NONE;
648 }
649 else if( precUsed.get()==NULL && approxFwdOp.get()==NULL && useAztecPrec_ ) {
650 // We are using the forward matrix for the preconditioner using aztec
651 // preconditioners
652 localPrecType = PT_AZTEC_FROM_OP;
653 }
654 else if( approxFwdOp.get() && useAztecPrec_ ) {
655 // The preconditioner comes from the input as a matrix and we are using
656 // aztec preconditioners
657 localPrecType = PT_AZTEC_FROM_APPROX_FWD_MATRIX;
658 }
659 else if( precUsed.get() ) {
660 // The preconditioner comes as an external operator so let's use it as
661 // such
662 localPrecType = PT_FROM_PREC_OP;
663 }
664 TEUCHOS_TEST_FOR_EXCEPTION
665 (localPrecType == PT_UPPER_BOUND, std::logic_error,
666 "AztecOOLinearOpWithSolveFactory::initializeOp_impl(...): "
667 "localPrecType == PT_UPPER_BOUND. This means that previously, "
668 "this value might have been used uninitialized. "
669 "Please report this bug to the Stratimikos developers.");
670
671 //
672 // Determine if aztecOp already contains solvers and if we need to
673 // reinitialize or not
674 //
675 RCP<AztecOO> aztecFwdSolver, aztecAdjSolver;
676 bool startingOver;
677 {
678 // Let's assume that fwdOp, prec and/or approxFwdOp are compatible with
679 // the already created AztecOO objects. If they are not, then the client
680 // should have created a new LOWSB object from scratch!
681 Teuchos::RCP<const LinearOpBase<double> > old_fwdOp;
682 Teuchos::RCP<const LinearOpSourceBase<double> > old_fwdOpSrc;
683 Teuchos::RCP<const PreconditionerBase<double> > old_prec;
684 bool old_isExternalPrec;
685 Teuchos::RCP<const LinearOpSourceBase<double> > old_approxFwdOpSrc;
686 Teuchos::RCP<AztecOO> old_aztecFwdSolver;
687 Teuchos::RCP<AztecOO> old_aztecAdjSolver;
688 double old_aztecSolverScalar;
689 aztecOp->uninitialize(
690 &old_fwdOp
691 ,&old_fwdOpSrc
692 ,&old_prec
693 ,&old_isExternalPrec
694 ,&old_approxFwdOpSrc
695 ,&old_aztecFwdSolver
696 ,NULL
697 ,&old_aztecAdjSolver
698 ,NULL
699 ,&old_aztecSolverScalar
700 );
701 if( old_aztecFwdSolver.get()==NULL ) {
702 // This has never been initialized before
703 startingOver = true;
704 }
705 else {
706 // Let's assume that fwdOp, prec and/or approxFwdOp are compatible with
707 // the already created AztecOO objects. If they are not, then the
708 // client should have created a new LOWSB object from scratch!
709 aztecFwdSolver = old_aztecFwdSolver;
710 aztecAdjSolver = old_aztecAdjSolver;
711 startingOver = false;
712 // We must wipe out the old preconditoner if we are not reusing the
713 // preconditioner
714 Ptr<bool> constructedAztecPreconditioner;
715 if(
716 !reusePrec
717 &&
718 !is_null(constructedAztecPreconditioner = get_optional_nonconst_extra_data<bool>(
719 aztecFwdSolver, "AOOLOWSF::constructedAztecPreconditoner") )
720 &&
721 *constructedAztecPreconditioner
722 )
723 {
724 aztecFwdSolver->DestroyPreconditioner();
725 *constructedAztecPreconditioner = false;
726 }
727 // We must see if we set an external preconditioner but will not do so
728 // again in which case we must blow away AztecOO and start over again!
729 Ptr<bool> setPreconditionerOperator;
730 if(
731 localPrecType != PT_FROM_PREC_OP
732 && !is_null( setPreconditionerOperator = get_optional_nonconst_extra_data<bool>(
733 aztecFwdSolver,"AOOLOWSF::setPreconditonerOperator") )
734 && *setPreconditionerOperator
735 )
736 {
737 // We must start over again since there is no way to unset an external
738 // preconditioner!
739 startingOver = true;
740 }
741 }
742 }
743
744 //
745 // Create the AztecOO solvers if we are starting over
746 //
747 startingOver = true; // ToDo: Remove this and figure out why this is not working!
748 if(startingOver) {
749 // Forward solver
750 aztecFwdSolver = rcp(new AztecOO());
751 aztecFwdSolver->SetAztecOption(AZ_diagnostics,AZ_none); // This was turned off in NOX?
752 aztecFwdSolver->SetAztecOption(AZ_keep_info,1);
753 // Adjoint solver (if supported)
754 if(
755 epetra_epetraFwdOpAdjointSupport==EPETRA_OP_ADJOINT_SUPPORTED
756 &&
757 localPrecType!=PT_AZTEC_FROM_OP && localPrecType!=PT_AZTEC_FROM_APPROX_FWD_MATRIX
758 )
759 {
760 aztecAdjSolver = rcp(new AztecOO());
761 aztecAdjSolver->SetAztecOption(AZ_diagnostics,AZ_none);
762 //aztecAdjSolver->SetAztecOption(AZ_keep_info,1);
763 }
764 }
765
766 //
767 // Set the options on the AztecOO solvers
768 //
769 if( startingOver ) {
770 if(paramList_.get())
771 setAztecOOParameters(
772 &paramList_->sublist(ForwardSolve_name).sublist(AztecOO_Settings_name),
773 &*aztecFwdSolver
774 );
775 if(aztecAdjSolver.get() && paramList_.get())
776 setAztecOOParameters(
777 &paramList_->sublist(AdjointSolve_name).sublist(AztecOO_Settings_name),
778 &*aztecAdjSolver
779 );
780 }
781
782 //
783 // Process the forward operator
784 //
785 RCP<const Epetra_Operator>
786 aztec_epetra_epetraFwdOp,
787 aztec_epetra_epetraAdjOp;
788 // Forward solve
789 RCP<const Epetra_Operator>
790 epetraOps[]
791 = { epetra_epetraFwdOp };
792 Teuchos::ETransp
793 epetraOpsTransp[]
794 = { epetra_epetraFwdOpTransp==NOTRANS ? Teuchos::NO_TRANS : Teuchos::TRANS };
795 PO::EApplyMode
796 epetraOpsApplyMode[]
797 = { epetra_epetraFwdOpApplyAs==EPETRA_OP_APPLY_APPLY
798 ? PO::APPLY_MODE_APPLY
799 : PO::APPLY_MODE_APPLY_INVERSE };
800 if(
801 epetraOpsTransp[0] == Teuchos::NO_TRANS
802 &&
803 epetraOpsApplyMode[0] == PO::APPLY_MODE_APPLY
804 )
805 {
806 aztec_epetra_epetraFwdOp = epetra_epetraFwdOp;
807 }
808 else
809 {
810 aztec_epetra_epetraFwdOp = rcp(
811 new PO(1,epetraOps,epetraOpsTransp,epetraOpsApplyMode));
812 }
813 if(
814 startingOver
815 ||
816 aztec_epetra_epetraFwdOp.get() != aztecFwdSolver->GetUserOperator()
817 )
818 {
819 // Here we will be careful not to reset the forward operator in fears that
820 // it will blow out the internally created stuff.
821 aztecFwdSolver->SetUserOperator(
822 const_cast<Epetra_Operator*>(&*aztec_epetra_epetraFwdOp));
823 set_extra_data(
824 aztec_epetra_epetraFwdOp, AOOLOWSF_aztec_epetra_epetraFwdOp_str,
825 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
826 );
827 }
828 // Adjoint solve
829 if( aztecAdjSolver.get() ) {
830 epetraOpsTransp[0] = (
831 epetra_epetraFwdOpTransp==NOTRANS
832 ? Teuchos::TRANS
833 : Teuchos::NO_TRANS
834 );
835 if(
836 epetraOpsTransp[0] == Teuchos::NO_TRANS
837 &&
838 epetraOpsApplyMode[0] == PO::APPLY_MODE_APPLY
839 )
840 {
841 aztec_epetra_epetraAdjOp = epetra_epetraFwdOp;
842 }
843 else {
844 aztec_epetra_epetraAdjOp = rcp(
845 new PO(1,epetraOps,epetraOpsTransp,epetraOpsApplyMode));
846 }
847 aztecAdjSolver->SetUserOperator(
848 const_cast<Epetra_Operator*>(&*aztec_epetra_epetraAdjOp));
849 set_extra_data(
850 aztec_epetra_epetraAdjOp, AOOLOWSF_aztec_epetra_epetraAdjOp_str,
851 Teuchos::inOutArg(aztecAdjSolver), Teuchos::POST_DESTROY, false
852 );
853 }
854
855 //
856 // Process the preconditioner
857 //
858 RCP<const Epetra_Operator>
859 aztec_fwd_epetra_epetraPrecOp,
860 aztec_adj_epetra_epetraPrecOp;
861 bool setAztecPreconditioner = false;
862 switch(localPrecType) {
863 case PT_NONE: {
864 //
865 // No preconditioning at all!
866 //
867 break;
868 }
869 case PT_AZTEC_FROM_OP: {
870 //
871 // We are using the forward matrix for the preconditioner using aztec
872 // preconditioners
873 //
874 if( startingOver || !reusePrec ) {
875 TEUCHOS_TEST_FOR_EXCEPTION(
876 rowmatrix_epetraFwdOp.get()==NULL, std::logic_error,
877 "AztecOOLinearOpWithSolveFactory::initializeOp_impl(...): "
878 "Error, There is no preconditioner given by client, but the client "
879 "passed in an Epetra_Operator for the forward operator of type \'"
880 <<typeName(*epetra_epetraFwdOp)<<"\' that does not "
881 "support the Epetra_RowMatrix interface!"
882 );
883 TEUCHOS_TEST_FOR_EXCEPTION(
884 epetra_epetraFwdOpTransp!=NOTRANS, std::logic_error,
885 "AztecOOLinearOpWithSolveFactory::initializeOp_impl(...):"
886 " Error, There is no preconditioner given by client and the client "
887 "passed in an Epetra_RowMatrix for the forward operator but the "
888 "overall transpose is not NOTRANS and therefore we can can just "
889 "hand this over to aztec without making a copy which is not supported here!"
890 );
891 aztecFwdSolver->SetPrecMatrix(
892 const_cast<Epetra_RowMatrix*>(&*rowmatrix_epetraFwdOp));
893 set_extra_data(
894 rowmatrix_epetraFwdOp, AOOLOWSF_rowmatrix_epetraFwdOp_str,
895 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
896 );
897 }
898 setAztecPreconditioner = true;
899 break;
900 }
901 case PT_AZTEC_FROM_APPROX_FWD_MATRIX: {
902 //
903 // The preconditioner comes from the input as a matrix and we are using
904 // aztec preconditioners
905 //
906 if( startingOver || !reusePrec ) {
907 TEUCHOS_TEST_FOR_EXCEPTION(
908 rowmatrix_epetraPrecOp.get()==NULL, std::logic_error
909 ,"AztecOOLinearOpWithSolveFactor::initializeOp_impl(...): The client "
910 "passed in an Epetra_Operator for the preconditioner matrix of type \'"
911 <<typeName(*epetra_epetraPrecOp)<<"\' that does not "
912 "support the Epetra_RowMatrix interface!"
913 );
914 TEUCHOS_TEST_FOR_EXCEPTION(
915 overall_epetra_epetraPrecOpTransp!=NOTRANS, std::logic_error
916 ,"AztecOOLinearOpWithSolveFactor::initializeOp_impl(...): Error, The client "
917 "passed in an Epetra_RowMatrix for the preconditoner matrix but the overall "
918 "transpose is not NOTRANS and therefore we can can just "
919 "hand this over to aztec without making a copy which is not supported here!"
920 );
921 aztecFwdSolver->SetPrecMatrix(
922 const_cast<Epetra_RowMatrix*>(&*rowmatrix_epetraPrecOp));
923 set_extra_data(
924 rowmatrix_epetraPrecOp, AOOLOWSF_rowmatrix_epetraPrecOp_str,
925 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
926 );
927 }
928 setAztecPreconditioner = true;
929 break;
930 }
931 case PT_FROM_PREC_OP: {
932 //
933 // The preconditioner comes as an operator so let's use it as such
934 //
935 // Forward solve
936 RCP<const Epetra_Operator>
937 theEpetraOps[]
938 = { epetra_epetraPrecOp };
939 Teuchos::ETransp
940 theEpetraOpsTransp[]
941 = { overall_epetra_epetraPrecOpTransp==NOTRANS
942 ? Teuchos::NO_TRANS
943 : Teuchos::TRANS };
944 // Here we must toggle the apply mode since aztecoo applies the
945 // preconditioner using ApplyInverse(...)
946 PO::EApplyMode
947 theEpetraOpsApplyMode[]
948 = { epetra_epetraPrecOpApplyAs==EPETRA_OP_APPLY_APPLY
949 ? PO::APPLY_MODE_APPLY_INVERSE
950 : PO::APPLY_MODE_APPLY };
951 if(
952 theEpetraOpsTransp[0] == Teuchos::NO_TRANS
953 &&
954 epetra_epetraPrecOpApplyAs==EPETRA_OP_APPLY_APPLY_INVERSE
955 )
956 {
957 aztec_fwd_epetra_epetraPrecOp = epetra_epetraPrecOp;
958 }
959 else {
960 aztec_fwd_epetra_epetraPrecOp = rcp(new PO(1,theEpetraOps,theEpetraOpsTransp,theEpetraOpsApplyMode));
961 }
962 aztecFwdSolver->SetPrecOperator(
963 const_cast<Epetra_Operator*>(&*aztec_fwd_epetra_epetraPrecOp));
964 set_extra_data(
965 aztec_fwd_epetra_epetraPrecOp, AOOLOWSF_aztec_fwd_epetra_epetraPrecOp_str,
966 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
967 );
968 // Adjoint solve
969 if(
970 aztecAdjSolver.get()
971 &&
972 epetra_epetraPrecOpAdjointSupport == EPETRA_OP_ADJOINT_SUPPORTED
973 )
974 {
975 theEpetraOpsTransp[0] = (
976 overall_epetra_epetraPrecOpTransp==NOTRANS
977 ? Teuchos::TRANS
978 : Teuchos::NO_TRANS
979 );
980 if(
981 theEpetraOpsTransp[0] == Teuchos::NO_TRANS
982 &&
983 epetra_epetraPrecOpApplyAs==EPETRA_OP_APPLY_APPLY_INVERSE
984 )
985 {
986 aztec_adj_epetra_epetraPrecOp = epetra_epetraPrecOp;
987 }
988 else {
989 aztec_adj_epetra_epetraPrecOp = rcp(
990 new PO(1,theEpetraOps,theEpetraOpsTransp,theEpetraOpsApplyMode));
991 }
992 aztecAdjSolver->SetPrecOperator(
993 const_cast<Epetra_Operator*>(&*aztec_adj_epetra_epetraPrecOp));
994 set_extra_data(
995 aztec_adj_epetra_epetraPrecOp, AOOLOWSF_aztec_adj_epetra_epetraPrecOp_str,
996 Teuchos::inOutArg(aztecAdjSolver), Teuchos::POST_DESTROY, false
997 );
998 set_extra_data<bool>(
999 true, AOOLOWSF_setPrecondtionerOperator_str,
1000 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
1001 );
1002 }
1003 break;
1004 }
1005 default:
1006 TEUCHOS_TEST_FOR_EXCEPT(true);
1007 }
1008
1009 //
1010 // Initialize the interal aztec preconditioner
1011 //
1012 if(setAztecPreconditioner) {
1013 if( startingOver || !reusePrec ) {
1014 double condNumEst = -1.0;
1015 TEUCHOS_TEST_FOR_EXCEPT(0!=aztecFwdSolver->ConstructPreconditioner(condNumEst));
1016 //aztecFwdSolver->SetAztecOption(AZ_pre_calc, AZ_calc);
1017 set_extra_data<bool>(
1018 true, AOOLOWSF_constructedAztecPreconditoner_str,
1019 Teuchos::inOutArg(aztecFwdSolver), Teuchos::POST_DESTROY, false
1020 );
1021 }
1022 else {
1023 //aztecFwdSolver->SetAztecOption(AZ_pre_calc, AZ_reuse);
1024 }
1025 }
1026
1027 //
1028 // Initialize the AztecOOLinearOpWithSolve object and set its options
1029 //
1030 if(aztecAdjSolver.get() && aztecAdjSolver->GetPrecOperator()) {
1031 aztecOp->initialize(
1032 fwdOp, fwdOpSrc,precUsed, prec.get()!=NULL, approxFwdOpSrc,
1033 aztecFwdSolver, true, aztecAdjSolver, true, epetra_epetraFwdOpScalar
1034 );
1035 }
1036 else {
1037 aztecOp->initialize(
1038 fwdOp, fwdOpSrc, precUsed, prec.get()!=NULL, approxFwdOpSrc,
1039 aztecFwdSolver, true, null, false, epetra_epetraFwdOpScalar
1040 );
1041 }
1042 aztecOp->fwdDefaultMaxIterations(defaultFwdMaxIterations_);
1043 aztecOp->fwdDefaultTol(defaultFwdTolerance_);
1044 aztecOp->adjDefaultMaxIterations(defaultAdjMaxIterations_);
1045 aztecOp->adjDefaultTol(defaultAdjTolerance_);
1046 aztecOp->outputEveryRhs(outputEveryRhs_);
1047 aztecOp->setOStream(this->getOStream());
1048 if(!is_null(this->getOverridingOStream()))
1049 aztecOp->setOverridingOStream(this->getOverridingOStream());
1050 aztecOp->setVerbLevel(this->getVerbLevel());
1051
1052#ifdef TEUCHOS_DEBUG
1053 if(paramList_.get())
1054 paramList_->validateParameters(*this->getValidParameters());
1055#endif
1056
1057 if(out.get() && static_cast<int>(verbLevel) > static_cast<int>(Teuchos::VERB_LOW))
1058 *out << "\nLeaving Thyra::AztecOOLinearOpWithSolveFactory::initializeOp_impl(...) ...\n";
1059
1060}
1061
1062
1063} // namespace Thyra
1064
1065
1066#endif // SUN_CXX
void unsetPreconditionerFactory(Teuchos::RCP< PreconditionerFactoryBase< double > > *precFactory, std::string *precFactoryName)
bool isCompatible(const LinearOpSourceBase< double > &fwdOpSrc) const
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)
Teuchos::RCP< PreconditionerFactoryBase< double > > getPreconditionerFactory() const
void initializeApproxPreconditionedOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, const Teuchos::RCP< const LinearOpSourceBase< double > > &approxFwdOpSrc, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
AztecOOLinearOpWithSolveFactory(Teuchos::RCP< Teuchos::ParameterList > const &paramList=Teuchos::null)
Construct uninitialized.
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
void initializeOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
void initializeAndReuseOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, LinearOpWithSolveBase< double > *Op) const
void setPreconditionerFactory(const Teuchos::RCP< PreconditionerFactoryBase< double > > &precFactory, const std::string &precFactoryName)
void uninitializeOp(LinearOpWithSolveBase< double > *Op, Teuchos::RCP< const LinearOpSourceBase< double > > *fwdOpSrc, Teuchos::RCP< const PreconditionerBase< double > > *prec, Teuchos::RCP< const LinearOpSourceBase< double > > *approxFwdOpSrc, ESupportSolveUse *supportSolveUse) const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList()
bool supportsPreconditionerInputType(const EPreconditionerInputType precOpType) const
Teuchos::RCP< LinearOpWithSolveBase< double > > createOp() const
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
void initializePreconditionedOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, const Teuchos::RCP< const PreconditionerBase< double > > &prec, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
Concrete LinearOpWithSolveBase subclass implemented using AztecOO.
RCP< const PreconditionerBase< double > > extract_prec()
Extract the preconditioner.
RCP< const LinearOpSourceBase< double > > extract_fwdOpSrc()
Extract the forward LinearOpBase<double> object so that it can be modified.
bool isExternalPrec() const
Determine if the preconditioner was external or not.
RCP< const LinearOpSourceBase< double > > extract_approxFwdOpSrc()
Extract the approximate forward LinearOpBase<double> object used to build the preconditioner.
NOTRANS

Generated for Stratimikos by doxygen 1.9.8