Stratimikos  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
27 namespace {
28 
29 
30 const std::string AOOLOWSF_epetraPrecOp_str
31 = "AOOLOWSF::epetraPrecOp";
32 const std::string AOOLOWSF_aztec_epetra_epetraFwdOp_str
33 = "AOOLOWSF::aztec_epetra_epetraFwdOp";
34 const std::string AOOLOWSF_aztec_epetra_epetraAdjOp_str
35 = "AOOLOWSF::aztec_epetra_epetraAdjOp";
36 const std::string AOOLOWSF_rowmatrix_epetraFwdOp_str
37 = "AOOLOWSF::rowmatrix_epetraFwdOp";
38 const std::string AOOLOWSF_rowmatrix_epetraPrecOp_str
39 = "AOOLOWSF::rowmatrix_epetraPrecOp";
40 const std::string AOOLOWSF_aztec_fwd_epetra_epetraPrecOp_str
41 = "AOOLOWSF::aztec_fwd_epetra_epetraPrecOp";
42 const std::string AOOLOWSF_aztec_adj_epetra_epetraPrecOp_str
43 = "AOOLOWSF::aztec_adj_epetra_epetraPrecOp";
44 const std::string AOOLOWSF_setPrecondtionerOperator_str
45 = "AOOLOWSF::setPrecondtionerOperator";
46 const std::string AOOLOWSF_constructedAztecPreconditoner_str
47 = "AOOLOWSF::constructedAztecPreconditoner";
48 
49 
50 const std::string ForwardSolve_name = "Forward Solve";
51 const std::string AdjointSolve_name = "Adjoint Solve";
52 const std::string MaxIterations_name = "Max Iterations";
53 const int MaxIterations_default = 400;
54 const std::string Tolerance_name = "Tolerance";
55 const double Tolerance_default = 1e-6;
56 const std::string OutputEveryRhs_name = "Output Every RHS";
57 const bool OutputEveryRhs_default = false;
58 const std::string AztecOO_Settings_name = "AztecOO Settings";
59 
60 
61 } // namespace
62 
63 
64 namespace Thyra {
65 
66 
67 // Constructors/initializers/accessors
68 
69 
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 
91 {
92  return true;
93 }
94 
95 
98  const std::string &precFactoryName
99  )
100 {
101  TEUCHOS_TEST_FOR_EXCEPT(!precFactory.get());
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 
120 {
121  return precFactory_;
122 }
123 
124 
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 
148 {
150 }
151 
152 
154  const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
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,
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) {
185  return true;
187  return useAztecPrec_;
188  default:
190  }
192 }
193 
194 
196  const Teuchos::RCP<const LinearOpSourceBase<double> > &fwdOpSrc,
197  const Teuchos::RCP<const PreconditionerBase<double> > &prec,
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,
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 
222  Teuchos::RCP<const LinearOpSourceBase<double> > *fwdOpSrc,
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
233  // Extract and unset the fwdOP and approxFwdOp objects
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()) {
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
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  }
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 
296 {
297  return paramList_;
298 }
299 
300 
303 {
304  Teuchos::RCP<Teuchos::ParameterList> _paramList = paramList_;
305  paramList_ = Teuchos::null;
306  return _paramList;
307 }
308 
309 
312 {
313  return paramList_;
314 }
315 
316 
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 
345 AztecOOLinearOpWithSolveFactory::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  );
357  aztecParamList = getValidAztecOOParameters();
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);
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 
390 void AztecOOLinearOpWithSolveFactory::updateThisValidParamList()
391 {
392  thisValidParamList_ = Teuchos::rcp(
393  new Teuchos::ParameterList(*generateAndGetValidParameters())
394  );
395  if(precFactory_.get()) {
397  precFactoryValidParamList = precFactory_->getValidParameters();
398  if(precFactoryValidParamList.get()) {
399  thisValidParamList_->sublist(precFactoryName_).setParameters(
400  *precFactoryValidParamList);
401  }
402  }
403  Teuchos::setupVerboseObjectSublist(&*thisValidParamList_);
404 }
405 
406 
407 void 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;
424  typedef EpetraExt::ProductOperator PO;
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 
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  //
447  tmpFwdOp = fwdOpSrc->getOp(),
448  tmpApproxFwdOp = ( approxFwdOpSrc.get() ? approxFwdOpSrc->getOp() : Teuchos::null );
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  );
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  //
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();
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
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));
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  );
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
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  }
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!
684  bool old_isExternalPrec;
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 };
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
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 ) {
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  );
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 ) {
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  );
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 };
940  theEpetraOpsTransp[]
941  = { overall_epetra_epetraPrecOpTransp==NOTRANS
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
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:
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 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
void initializeAndReuseOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, LinearOpWithSolveBase< double > *Op) const
bool is_null(const boost::shared_ptr< T > &p)
EOpTransp
void unwrap(const LinearOpBase< Scalar > &Op, Scalar *scalar, EOpTransp *transp, const LinearOpBase< Scalar > **origOp)
Teuchos::RCP< const Teuchos::ParameterList > getParameterList() const
T & get(const std::string &name, T def_value)
RCP< const LinearOpSourceBase< double > > extract_fwdOpSrc()
Extract the forward LinearOpBase&lt;double&gt; object so that it can be modified.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
bool isExternalPrec() const
Determine if the preconditioner was external or not.
T_To & dyn_cast(T_From &from)
AztecOOLinearOpWithSolveFactory(Teuchos::RCP< Teuchos::ParameterList > const &paramList=Teuchos::null)
Construct uninitialized.
void initializeApproxPreconditionedOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, const Teuchos::RCP< const LinearOpSourceBase< double > > &approxFwdOpSrc, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
EOpTransp real_trans(EOpTransp transp)
T * get() const
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
bool supportsPreconditionerInputType(const EPreconditionerInputType precOpType) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
bool isCompatible(const LinearOpSourceBase< double > &fwdOpSrc) const
bool isSublist(const std::string &name) const
EAdjointEpetraOp
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList()
EOpTransp trans_trans(EOpTransp trans1, EOpTransp trans2)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
int DestroyPreconditioner()
void unsetPreconditionerFactory(Teuchos::RCP< PreconditionerFactoryBase< double > > *precFactory, std::string *precFactoryName)
void initializeOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
T * getPtr(const std::string &name)
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)
Teuchos::RCP< PreconditionerFactoryBase< double > > getPreconditionerFactory() const
void validateParameters(ParameterList const &validParamList, int const depth=1000, EValidateUsed const validateUsed=VALIDATE_USED_ENABLED, EValidateDefaults const validateDefaults=VALIDATE_DEFAULTS_ENABLED) const
ParameterList & setParameters(const ParameterList &source)
ESupportSolveUse
void initializePreconditionedOp(const Teuchos::RCP< const LinearOpSourceBase< double > > &fwdOpSrc, const Teuchos::RCP< const PreconditionerBase< double > > &prec, LinearOpWithSolveBase< double > *Op, const ESupportSolveUse supportSolveUse) const
#define TEUCHOS_UNREACHABLE_RETURN(dummyReturnVal)
RCP< const PreconditionerBase< double > > extract_prec()
Extract the preconditioner.
EApplyEpetraOpAs
EPreconditionerInputType
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
virtual Teuchos::RCP< const LinearOpBase< Scalar > > getOp() const =0
void setPreconditionerFactory(const Teuchos::RCP< PreconditionerFactoryBase< double > > &precFactory, const std::string &precFactoryName)
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
Teuchos::RCP< LinearOpWithSolveBase< double > > createOp() const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
std::string typeName(const T &t)
Concrete LinearOpWithSolveBase subclass implemented using AztecOO.
RCP< const LinearOpSourceBase< double > > extract_approxFwdOpSrc()
Extract the approximate forward LinearOpBase&lt;double&gt; object used to build the preconditioner.

Generated on Fri Dec 20 2024 09:21:59 for Stratimikos by doxygen 1.8.5