Thyra_LinearOpWithSolveTester.hpp

00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //    Thyra: Interfaces and Support for Abstract Numerical Algorithms
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #ifndef THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00030 #define THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00031 
00032 #include "Thyra_LinearOpWithSolveTesterDecl.hpp"
00033 #include "Thyra_LinearOpWithSolveBase.hpp"
00034 #include "Thyra_ScaledAdjointLinearOp.hpp"
00035 #include "Thyra_describeLinearOp.hpp"
00036 #include "Thyra_VectorStdOps.hpp"
00037 #include "Thyra_TestingTools.hpp"
00038 
00039 namespace Thyra {
00040 
00041 template<class RangeScalar, class DomainScalar>
00042 LinearOpWithSolveTester<RangeScalar,DomainScalar>::LinearOpWithSolveTester(
00043   const bool                 check_forward_default
00044   ,const RangeScalarMag      forward_default_residual_warning_tol
00045   ,const RangeScalarMag      forward_default_residual_error_tol
00046   ,const DomainScalarMag     forward_default_solution_error_warning_tol
00047   ,const DomainScalarMag     forward_default_solution_error_error_tol
00048   ,const bool                check_forward_residual
00049   ,const RangeScalarMag      forward_residual_solve_tol
00050   ,const RangeScalarMag      forward_residual_slack_warning_tol
00051   ,const RangeScalarMag      forward_residual_slack_error_tol
00052   ,const bool                check_forward_solution_error
00053   ,const RangeScalarMag      forward_solution_error_solve_tol
00054   ,const RangeScalarMag      forward_solution_error_slack_warning_tol
00055   ,const RangeScalarMag      forward_solution_error_slack_error_tol
00056   ,const bool                check_adjoint_default
00057   ,const DomainScalarMag     adjoint_default_residual_warning_tol
00058   ,const DomainScalarMag     adjoint_default_residual_error_tol
00059   ,const RangeScalarMag      adjoint_default_solution_error_warning_tol
00060   ,const RangeScalarMag      adjoint_default_solution_error_error_tol
00061   ,const bool                check_adjoint_residual
00062   ,const DomainScalarMag     adjoint_residual_solve_tol
00063   ,const DomainScalarMag     adjoint_residual_slack_warning_tol
00064   ,const DomainScalarMag     adjoint_residual_slack_error_tol
00065   ,const bool                check_adjoint_solution_error
00066   ,const DomainScalarMag     adjoint_solution_error_solve_tol
00067   ,const DomainScalarMag     adjoint_solution_error_slack_warning_tol
00068   ,const DomainScalarMag     adjoint_solution_error_slack_error_tol
00069   ,const int                 num_random_vectors
00070   ,const bool                show_all_tests
00071   ,const bool                dump_all
00072   )
00073   :check_forward_default_(check_forward_default)
00074   ,forward_default_residual_warning_tol_(forward_default_residual_warning_tol)
00075   ,forward_default_residual_error_tol_(forward_default_residual_error_tol)
00076   ,forward_default_solution_error_warning_tol_(forward_default_solution_error_warning_tol)
00077   ,forward_default_solution_error_error_tol_(forward_default_solution_error_error_tol)
00078   ,check_forward_residual_(check_forward_residual)
00079   ,forward_residual_solve_tol_(forward_residual_solve_tol)
00080   ,forward_residual_slack_warning_tol_(forward_residual_slack_warning_tol)
00081   ,forward_residual_slack_error_tol_(forward_residual_slack_error_tol)
00082   ,check_forward_solution_error_(check_forward_solution_error)
00083   ,forward_solution_error_solve_tol_(forward_solution_error_solve_tol)
00084   ,forward_solution_error_slack_warning_tol_(forward_solution_error_slack_warning_tol)
00085   ,forward_solution_error_slack_error_tol_(forward_solution_error_slack_error_tol)
00086   ,check_adjoint_default_(check_adjoint_default)
00087   ,adjoint_default_residual_warning_tol_(adjoint_default_residual_warning_tol)
00088   ,adjoint_default_residual_error_tol_(adjoint_default_residual_error_tol)
00089   ,adjoint_default_solution_error_warning_tol_(adjoint_default_solution_error_warning_tol)
00090   ,adjoint_default_solution_error_error_tol_(adjoint_default_solution_error_error_tol)
00091   ,check_adjoint_residual_(check_adjoint_residual)
00092   ,adjoint_residual_solve_tol_(adjoint_residual_solve_tol)
00093   ,adjoint_residual_slack_warning_tol_(adjoint_residual_slack_warning_tol)
00094   ,adjoint_residual_slack_error_tol_(adjoint_residual_slack_error_tol)
00095   ,check_adjoint_solution_error_(check_adjoint_solution_error)
00096   ,adjoint_solution_error_solve_tol_(adjoint_solution_error_solve_tol)
00097   ,adjoint_solution_error_slack_warning_tol_(adjoint_solution_error_slack_warning_tol)
00098   ,adjoint_solution_error_slack_error_tol_(adjoint_solution_error_slack_error_tol)
00099   ,num_random_vectors_(num_random_vectors)
00100   ,show_all_tests_(show_all_tests)
00101   ,dump_all_(dump_all)
00102 {}
00103 
00104 template<class RangeScalar, class DomainScalar>
00105 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::turn_off_all_tests()
00106 {
00107   check_forward_default_         = false;
00108   check_forward_residual_        = false;
00109   check_forward_solution_error_  = false;
00110   check_adjoint_default_         = false;
00111   check_adjoint_residual_        = false;
00112   check_adjoint_solution_error_  = false;
00113 }
00114 
00115 template<class RangeScalar, class DomainScalar>
00116 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_solve_tol( const ScalarMag solve_tol )
00117 {
00118   forward_residual_solve_tol_ = solve_tol;
00119   forward_residual_solve_tol_ = solve_tol;
00120   forward_solution_error_solve_tol_ = solve_tol;
00121   adjoint_residual_solve_tol_ = solve_tol;
00122   adjoint_solution_error_solve_tol_ = solve_tol;
00123 }
00124 
00125 template<class RangeScalar, class DomainScalar>
00126 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_warning_tol( const ScalarMag slack_warning_tol )
00127 {
00128   forward_default_residual_warning_tol_ = slack_warning_tol;
00129   forward_default_solution_error_warning_tol_ = slack_warning_tol;
00130   forward_residual_slack_warning_tol_ = slack_warning_tol;
00131   forward_solution_error_slack_warning_tol_ = slack_warning_tol;
00132   adjoint_default_residual_warning_tol_ = slack_warning_tol;
00133   adjoint_default_solution_error_warning_tol_ = slack_warning_tol;
00134   adjoint_residual_slack_warning_tol_ = slack_warning_tol;
00135   adjoint_solution_error_slack_warning_tol_ = slack_warning_tol;
00136 }
00137 
00138 template<class RangeScalar, class DomainScalar>
00139 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_error_tol( const ScalarMag slack_error_tol )
00140 {
00141   forward_default_residual_error_tol_ = slack_error_tol;
00142   forward_default_solution_error_error_tol_ = slack_error_tol;
00143   forward_residual_slack_error_tol_ = slack_error_tol;
00144   forward_solution_error_slack_error_tol_ = slack_error_tol;
00145   adjoint_default_residual_error_tol_ = slack_error_tol;
00146   adjoint_default_solution_error_error_tol_ = slack_error_tol;
00147   adjoint_residual_slack_error_tol_ = slack_error_tol;
00148   adjoint_solution_error_slack_error_tol_ = slack_error_tol;
00149 }
00150   
00151 template<class RangeScalar, class DomainScalar>
00152 bool LinearOpWithSolveTester<RangeScalar,DomainScalar>::check(
00153   const LinearOpWithSolveBase<RangeScalar,DomainScalar>   &op
00154   ,std::ostream                                           *out
00155   ,const std::string                                      &leadingIndent
00156   ,const std::string                                      &indentSpacer
00157   ) const
00158 {
00159 
00160   using std::endl;
00161   using Teuchos::arrayArg;
00162   typedef Teuchos::ScalarTraits<Scalar>        ST;
00163   typedef Teuchos::ScalarTraits<RangeScalar>   DST;
00164   typedef Teuchos::ScalarTraits<DomainScalar>  RST;
00165   bool success = true, result;
00166   const std::string &li = leadingIndent, &is = indentSpacer;
00167   const Teuchos::EVerbosityLevel verbLevel = (dump_all()?Teuchos::VERB_EXTREME:Teuchos::VERB_MEDIUM);
00168   
00169   if(out) {
00170     *out <<endl<<li<< "*** Entering LinearOpWithSolveTester<"<<ST::name()<<">::check(op,...) ...\n";
00171     if(show_all_tests()) {
00172       *out <<endl<<li<< "describe forward op:\n" << Teuchos::describe(op,verbLevel,li,is);
00173       if(op.applyTransposeSupports(CONJ_ELE) && verbLevel==Teuchos::VERB_EXTREME) {
00174         *out <<endl<<li<< "describe adjoint op:\n";
00175         describeLinearOp(
00176           *adjoint(Teuchos::rcp_implicit_cast< const LinearOpBase<RangeScalar,DomainScalar> >(Teuchos::rcp(&op,false)))
00177           ,*out,verbLevel,li,is
00178           );
00179       }
00180     }
00181     else {
00182       *out <<endl<<li<< "describe op: " << op.description() << endl;
00183     }
00184   }
00185   
00186   Teuchos::RefCountPtr<const VectorSpaceBase<RangeScalar> >   range  = op.range();
00187   Teuchos::RefCountPtr<const VectorSpaceBase<DomainScalar> >  domain = op.domain();
00188   
00189   if( check_forward_default() ) {
00190 
00191     if(out) *out <<endl<<li<< "this->check_forward_default()==true: Checking the default forward solve ... ";
00192 
00193     std::ostringstream oss;
00194     if(out) oss.copyfmt(*out);
00195     bool these_results = true;
00196 
00197     oss <<endl<<li<<is<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00198     result = op.solveSupportsConj(NONCONJ_ELE);
00199     if(!result) these_results = false;
00200     oss << passfail(result) << endl;
00201 
00202     if(result) {
00203     
00204       oss
00205         <<endl<<li<<is<< "Checking that the forward default solve matches the forward operator:\n"
00206         <<endl<<li<<is<< "  inv(Op)*Op*v1 == v1"
00207         <<endl<<li<<is<< "          \\___/"
00208         <<endl<<li<<is<< "           v2"
00209         <<endl<<li<<is<< "  \\___________/"
00210         <<endl<<li<<is<< "         v3"
00211         <<endl<<li<<is<< ""
00212         <<endl<<li<<is<< "  v4 = v3-v1"
00213         <<endl<<li<<is<< "  v5 = Op*v3-v2"
00214         <<endl<<li<<is<< ""
00215         <<endl<<li<<is<< "  norm(v4)/norm(v1) <= forward_default_solution_error_error_tol()"
00216         <<endl<<li<<is<< "  norm(v5)/norm(v2) <= forward_default_residual_error_tol()"
00217         <<endl;
00218 
00219       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00220 
00221         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00222       
00223         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00224         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v1 = createMember(domain);
00225         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00226         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00227       
00228         oss <<endl<<li<<is<< "v2 = Op*v1 ...\n" ;
00229         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v2 = createMember(range);
00230         op.apply(NONCONJ_ELE,*v1,&*v2);
00231         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00232 
00233         oss <<endl<<li<<is<< "v3 = inv(Op)*v2 ...\n" ;
00234         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v3 = createMember(domain);
00235         assign(&*v3,DST::zero());
00236         SolveStatus<Scalar> solveStatus = solve(op,NONCONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00237         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00238         oss
00239           <<endl<<li<<is<< "solve status:"
00240           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00241           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<RangeScalar>::achievedTolToString(solveStatus.achievedTol)
00242           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00243           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00244           <<endl;
00245 
00246         oss <<endl<<li<<is<< "v4 = v3 - v1 ...\n" ;
00247         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v4 = createMember(domain);
00248         V_VmV( &*v4, *v3, *v1 );
00249         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00250       
00251         oss <<endl<<li<<is<< "v5 = Op*v3 - v2 ...\n" ;
00252         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v5 = createMember(range);
00253         assign( &*v5, *v2 );
00254         op.apply(NONCONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00255         if(dump_all()) oss <<endl<<li<<is<< "v5 =\n" << describe(*v5,verbLevel,li,is);
00256       
00257         const DomainScalarMag
00258           norm_v1 = norm(*v1),
00259           norm_v4 = norm(*v4),
00260           norm_v4_norm_v1 = norm_v4/norm_v1;
00261 
00262         result = testMaxErr(
00263           "norm(v4)/norm(v1)", norm_v4_norm_v1
00264           ,"forward_default_solution_error_error_tol()", forward_default_solution_error_error_tol()
00265           ,"forward_default_solution_error_warning_tol()", forward_default_solution_error_warning_tol()
00266           ,&oss,li+is
00267           );
00268         if(!result) these_results = false;
00269       
00270         const RangeScalarMag
00271           norm_v2 = norm(*v2),
00272           norm_v5 = norm(*v5),
00273           norm_v5_norm_v2 = norm_v5/norm_v2;
00274 
00275         result = testMaxErr(
00276           "norm(v5)/norm(v2)", norm_v5_norm_v2
00277           ,"forward_default_residual_error_tol()", forward_default_residual_error_tol()
00278           ,"forward_default_residual_warning_tol()", forward_default_residual_warning_tol()
00279           ,&oss,li+is
00280           );
00281         if(!result) these_results = false;
00282 
00283       }
00284     }
00285     else {
00286       oss <<endl<<li<<is<< "Forward operator not supported, skipping check!\n";
00287     }
00288 
00289     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00290 
00291   }
00292   else {
00293     if(out) *out <<endl<<li<< "this->check_forward_default()==false: Skipping the check of the default forward solve!\n";
00294   }
00295   
00296   if( check_forward_residual() ) {
00297 
00298     if(out) *out <<endl<<li<< "this->check_forward_residual()==true: Checking the forward solve with a tolerance on the residual ... ";
00299 
00300     std::ostringstream oss;
00301     if(out) oss.copyfmt(*out);
00302     bool these_results = true;
00303 
00304     oss <<endl<<li<<is<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00305     result = op.solveSupportsConj(NONCONJ_ELE);
00306     if(!result) these_results = false;
00307     oss << passfail(result) << endl;
00308 
00309     if(result) {
00310     
00311       oss
00312         <<endl<<li<<is<< "Checking that the forward solve matches the forward operator to a residual tolerance:\n"
00313         <<endl<<li<<is<< "  v3 = inv(Op)*Op*v1"
00314         <<endl<<li<<is<< "               \\___/"
00315         <<endl<<li<<is<< "                 v2"
00316         <<endl<<li<<is<< ""
00317         <<endl<<li<<is<< "  v4 = Op*v3-v2"
00318         <<endl<<li<<is<< ""
00319         <<endl<<li<<is<< "  norm(v4)/norm(v2) <= forward_residual_solve_tol() + forward_residual_slack_error_tol()"
00320         <<endl;
00321 
00322       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00323 
00324         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00325       
00326         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00327         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v1 = createMember(domain);
00328         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00329         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00330       
00331         oss <<endl<<li<<is<< "v2 = Op*v1 ...\n" ;
00332         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v2 = createMember(range);
00333         op.apply(NONCONJ_ELE,*v1,&*v2);
00334         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00335 
00336         oss <<endl<<li<<is<< "v3 = inv(Op)*v2 ...\n" ;
00337         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v3 = createMember(domain);
00338         SolveCriteria<Scalar> solveCriteria(SOLVE_TOL_REL_RESIDUAL_NORM,forward_residual_solve_tol());
00339         assign(&*v3,DST::zero());
00340         SolveStatus<Scalar> solveStatus = solve<RangeScalar,DomainScalar>(op,NONCONJ_ELE,*v2,&*v3,&solveCriteria);
00341         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00342         oss
00343           <<endl<<li<<is<< "solve status:"
00344           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00345           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<RangeScalar>::achievedTolToString(solveStatus.achievedTol)
00346           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00347           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00348           <<endl;
00349         oss
00350           <<endl<<li<<is<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00351           << passfail(solveStatus.solveStatus==SOLVE_STATUS_CONVERGED)<<endl;
00352       
00353         oss <<endl<<li<<is<< "v4 = Op*v3 - v2 ...\n" ;
00354         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v4 = createMember(range);
00355         assign( &*v4, *v2 );
00356         op.apply(NONCONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00357         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00358       
00359         const RangeScalarMag
00360           norm_v2 = norm(*v2),
00361           norm_v4 = norm(*v4),
00362           norm_v4_norm_v2 = norm_v4/norm_v2;
00363 
00364         result = testMaxErr(
00365           "norm(v4)/norm(v2)", norm_v4_norm_v2
00366           ,"forward_residual_solve_tol()+forward_residual_slack_error_tol()", RangeScalarMag(forward_residual_solve_tol()+forward_residual_slack_error_tol())
00367           ,"forward_residual_solve_tol()_slack_warning_tol()", RangeScalarMag(forward_residual_solve_tol()+forward_residual_slack_warning_tol())
00368           ,&oss,li+is
00369           );
00370         if(!result) these_results = false;
00371 
00372       }
00373     }
00374     else {
00375       oss <<endl<<li<<is<< "Forward operator not supported, skipping check!\n";
00376     }
00377 
00378     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00379 
00380   }
00381   else {
00382     if(out) *out <<endl<<li<< "this->check_forward_residual()==false: Skipping the check of the forward solve with a tolerance on the residual!\n";
00383   }
00384   
00385   if( check_forward_solution_error() ) {
00386 
00387     if(out) *out <<endl<<li<< "this->check_forward_solution_error()==true: Checking the forward solve with a tolerance on the solution error ... ";
00388 
00389     std::ostringstream oss;
00390     if(out) oss.copyfmt(*out);
00391     bool these_results = true;
00392 
00393     oss <<endl<<li<<is<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00394     result = op.solveSupportsConj(NONCONJ_ELE);
00395     if(!result) these_results = false;
00396     oss << passfail(result) << endl;
00397 
00398     if(result) {
00399     
00400       oss
00401         <<endl<<li<<is<< "Checking that the forward solve matches the forward operator to a solution error tolerance:\n"
00402         <<endl<<li<<is<< "  v3 = inv(Op)*Op*v1"
00403         <<endl<<li<<is<< "               \\___/"
00404         <<endl<<li<<is<< "                 v2"
00405         <<endl<<li<<is<< ""
00406         <<endl<<li<<is<< "  v4 = v3-v1"
00407         <<endl<<li<<is<< ""
00408         <<endl<<li<<is<< "  norm(v4)/norm(v1) <= forward_solution_error_solve_tol() + forward_solution_error_slack_error_tol()"
00409         <<endl;
00410 
00411       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00412 
00413         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00414       
00415         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00416         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v1 = createMember(domain);
00417         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00418         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00419       
00420         oss <<endl<<li<<is<< "v2 = Op*v1 ...\n" ;
00421         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v2 = createMember(range);
00422         op.apply(NONCONJ_ELE,*v1,&*v2);
00423         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00424 
00425         oss <<endl<<li<<is<< "v3 = inv(Op)*v2 ...\n" ;
00426         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v3 = createMember(domain);
00427         SolveCriteria<Scalar> solveCriteria(SOLVE_TOL_REL_SOLUTION_ERR_NORM,forward_solution_error_solve_tol());
00428         assign(&*v3,DST::zero());
00429         SolveStatus<Scalar> solveStatus = solve(op,NONCONJ_ELE,*v2,&*v3,&solveCriteria);
00430         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00431         oss
00432           <<endl<<li<<is<< "solve status:"
00433           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00434           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<RangeScalar>::achievedTolToString(solveStatus.achievedTol)
00435           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00436           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00437           <<endl;
00438         oss
00439           <<endl<<li<<is<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00440           << passfail(solveStatus.solveStatus==SOLVE_STATUS_CONVERGED)<<endl;
00441       
00442         oss <<endl<<li<<is<< "v4 = v3 - v1 ...\n" ;
00443         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v4 = createMember(domain);
00444         V_VmV( &*v4, *v3, *v1 );
00445         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00446       
00447         const RangeScalarMag
00448           norm_v1 = norm(*v1),
00449           norm_v4 = norm(*v4),
00450           norm_v4_norm_v1 = norm_v4/norm_v1;
00451 
00452         result = testMaxErr(
00453           "norm(v4)/norm(v1)", norm_v4_norm_v1
00454           ,"forward_solution_error_solve_tol()+forward_solution_error_slack_error_tol()", RangeScalarMag(forward_solution_error_solve_tol()+forward_solution_error_slack_error_tol())
00455           ,"forward_solution_error_solve_tol()+forward_solution_error_slack_warning_tol()", RangeScalarMag(forward_solution_error_solve_tol()+forward_solution_error_slack_warning_tol())
00456           ,&oss,li+is
00457           );
00458         if(!result) these_results = false;
00459 
00460       }
00461     }
00462     else {
00463       oss <<endl<<li<<is<< "Forward operator not supported, skipping check!\n";
00464     }
00465 
00466     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00467 
00468   }
00469   else {
00470     if(out) *out <<endl<<li<< "this->check_forward_solution_error()==false: Skipping the check of the forward solve with a tolerance on the solution_error!\n";
00471   }
00472   
00473   if( check_adjoint_default() ) {
00474 
00475     if(out) *out <<endl<<li<< "this->check_adjoint_default()==true: Checking the default adjoint solve ... ";
00476 
00477     std::ostringstream oss;
00478     if(out) oss.copyfmt(*out);
00479     bool these_results = true;
00480 
00481     oss <<endl<<li<<is<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00482     result = op.solveTransposeSupportsConj(CONJ_ELE);
00483     if(!result) these_results = false;
00484     oss << passfail(result) << endl;
00485 
00486     if(result) {
00487     
00488       oss
00489         <<endl<<li<<is<< "Checking that the adjoint default solve matches the adjoint operator:\n"
00490         <<endl<<li<<is<< "  inv(Op')*Op'*v1 == v1"
00491         <<endl<<li<<is<< "           \\____/"
00492         <<endl<<li<<is<< "             v2"
00493         <<endl<<li<<is<< "  \\_____________/"
00494         <<endl<<li<<is<< "         v3"
00495         <<endl<<li<<is<< ""
00496         <<endl<<li<<is<< "  v4 = v3-v1"
00497         <<endl<<li<<is<< "  v5 = Op'*v3-v2"
00498         <<endl<<li<<is<< ""
00499         <<endl<<li<<is<< "  norm(v4)/norm(v1) <= adjoint_default_solution_error_error_tol()"
00500         <<endl<<li<<is<< "  norm(v5)/norm(v2) <= adjoint_default_residual_error_tol()"
00501         <<endl;
00502 
00503       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00504 
00505         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00506       
00507         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00508         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v1 = createMember(range);
00509         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00510         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00511       
00512         oss <<endl<<li<<is<< "v2 = Op*v1 ...\n" ;
00513         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v2 = createMember(domain);
00514         op.apply(NONCONJ_ELE,*v1,&*v2);
00515         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00516 
00517         oss <<endl<<li<<is<< "v3 = inv(Op)*v2 ...\n" ;
00518         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v3 = createMember(range);
00519         assign(&*v3,DST::zero());
00520         SolveStatus<Scalar> solveStatus = solve(op,NONCONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00521         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00522         oss
00523           <<endl<<li<<is<< "solve status:"
00524           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00525           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<DomainScalar>::achievedTolToString(solveStatus.achievedTol)
00526           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00527           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00528           <<endl;
00529 
00530         oss <<endl<<li<<is<< "v4 = v3 - v1 ...\n" ;
00531         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v4 = createMember(range);
00532         V_VmV( &*v4, *v3, *v1 );
00533         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00534       
00535         oss <<endl<<li<<is<< "v5 = Op*v3 - v2 ...\n" ;
00536         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v5 = createMember(domain);
00537         assign( &*v5, *v2 );
00538         op.apply(NONCONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00539         if(dump_all()) oss <<endl<<li<<is<< "v5 =\n" << describe(*v5,verbLevel,li,is);
00540       
00541         const RangeScalarMag
00542           norm_v1 = norm(*v1),
00543           norm_v4 = norm(*v4),
00544           norm_v4_norm_v1 = norm_v4/norm_v1;
00545 
00546         result = testMaxErr(
00547           "norm(v4)/norm(v1)", norm_v4_norm_v1
00548           ,"adjoint_default_solution_error_error_tol()", adjoint_default_solution_error_error_tol()
00549           ,"adjoint_default_solution_error_warning_tol()", adjoint_default_solution_error_warning_tol()
00550           ,&oss,li+is
00551           );
00552         if(!result) these_results = false;
00553       
00554         const DomainScalarMag
00555           norm_v2 = norm(*v2),
00556           norm_v5 = norm(*v5),
00557           norm_v5_norm_v2 = norm_v5/norm_v2;
00558 
00559         result = testMaxErr(
00560           "norm(v5)/norm(v2)", norm_v5_norm_v2
00561           ,"adjoint_default_residual_error_tol()", adjoint_default_residual_error_tol()
00562           ,"adjoint_default_residual_warning_tol()", adjoint_default_residual_warning_tol()
00563           ,&oss,li+is
00564           );
00565         if(!result) these_results = false;
00566 
00567       }
00568     }
00569     else {
00570       oss <<endl<<li<<is<< "Adjoint operator not supported, skipping check!\n";
00571     }
00572 
00573     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00574 
00575   }
00576   else {
00577     if(out) *out <<endl<<li<< "this->check_adjoint_default()==false: Skipping the check of the adjoint solve with a default tolerance!\n";
00578   }
00579   
00580   if( check_adjoint_residual() ) {
00581 
00582     if(out) *out <<endl<<li<< "this->check_adjoint_residual()==true: Checking the adjoint solve with a tolerance on the residual ... ";
00583     
00584     std::ostringstream oss;
00585     if(out) oss.copyfmt(*out);
00586     bool these_results = true;
00587 
00588     oss <<endl<<li<<is<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00589     result = op.solveTransposeSupportsConj(CONJ_ELE);
00590     if(!result) these_results = false;
00591     oss << passfail(result) << endl;
00592 
00593     if(result) {
00594     
00595       oss
00596         <<endl<<li<<is<< "Checking that the adjoint solve matches the adjoint operator to a residual tolerance:\n"
00597         <<endl<<li<<is<< "  v3 = inv(Op')*Op'*v1"
00598         <<endl<<li<<is<< "                \\____/"
00599         <<endl<<li<<is<< "                  v2"
00600         <<endl<<li<<is<< ""
00601         <<endl<<li<<is<< "  v4 = Op'*v3-v2"
00602         <<endl<<li<<is<< ""
00603         <<endl<<li<<is<< "  norm(v4)/norm(v2) <= adjoint_residual_solve_tol() + adjoint_residual_slack_error_tol()"
00604         <<endl;
00605 
00606       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00607 
00608         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00609       
00610         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00611         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v1 = createMember(range);
00612         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00613         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00614       
00615         oss <<endl<<li<<is<< "v2 = Op'*v1 ...\n" ;
00616         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v2 = createMember(domain);
00617         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00618         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00619 
00620         oss <<endl<<li<<is<< "v3 = inv(Op')*v2 ...\n" ;
00621         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v3 = createMember(range);
00622         SolveCriteria<Scalar> solveCriteria(SOLVE_TOL_REL_RESIDUAL_NORM,adjoint_residual_solve_tol());
00623         assign(&*v3,RST::zero());
00624         SolveStatus<Scalar> solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,&solveCriteria);
00625         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00626         oss
00627           <<endl<<li<<is<< "solve status:"
00628           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00629           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<RangeScalar>::achievedTolToString(solveStatus.achievedTol)
00630           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00631           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00632           <<endl;
00633         oss
00634           <<endl<<li<<is<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00635           << passfail(solveStatus.solveStatus==SOLVE_STATUS_CONVERGED)<<endl;
00636         if(solveStatus.achievedTol==SolveStatus<RangeScalar>::unknownTolerance())
00637           oss <<endl<<li<<is<<"achievedTol==unknownTolerance(): Setting achievedTol = adjoint_residual_solve_tol() = "<<adjoint_residual_solve_tol()<<endl;
00638       
00639         oss <<endl<<li<<is<< "v4 = Op'*v3 - v2 ...\n" ;
00640         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v4 = createMember(domain);
00641         assign( &*v4, *v2 );
00642         op.applyTranspose(CONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00643         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00644       
00645         const DomainScalarMag
00646           norm_v2 = norm(*v2),
00647           norm_v4 = norm(*v4),
00648           norm_v4_norm_v2 = norm_v4/norm_v2;
00649 
00650         result = testMaxErr(
00651           "norm(v4)/norm(v2)", norm_v4_norm_v2
00652           ,"adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol()", DomainScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol())
00653           ,"adjoint_residual_solve_tol()+adjoint_residual_slack_warning_tol()", DomainScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_warning_tol())
00654           ,&oss,li+is
00655           );
00656         if(!result) these_results = false;
00657 
00658       }
00659     }
00660     else {
00661       oss <<endl<<li<<is<< "Adjoint operator not supported, skipping check!\n";
00662     }
00663 
00664     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00665 
00666   }
00667   else {
00668     if(out) *out <<endl<<li<< "this->check_adjoint_residual()==false: Skipping the check of the adjoint solve with a tolerance on the residual!\n";
00669   }
00670   
00671   if( check_adjoint_solution_error() ) {
00672 
00673     if(out) *out <<endl<<li<< "this->check_adjoint_solution_error()==true: Checking the adjoint solve with a tolerance on the solution error ... ";
00674 
00675     std::ostringstream oss;
00676     if(out) oss.copyfmt(*out);
00677     bool these_results = true;
00678 
00679     oss <<endl<<li<<is<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00680     result = op.solveTransposeSupportsConj(CONJ_ELE);
00681     if(!result) these_results = false;
00682     oss << passfail(result) << endl;
00683 
00684     if(result) {
00685     
00686       oss
00687         <<endl<<li<<is<< "Checking that the adjoint solve matches the adjoint operator to a solution error tolerance:\n"
00688         <<endl<<li<<is<< "  v3 = inv(Op')*Op'*v1"
00689         <<endl<<li<<is<< "                \\____/"
00690         <<endl<<li<<is<< "                  v2"
00691         <<endl<<li<<is<< ""
00692         <<endl<<li<<is<< "  v4 = v3-v1"
00693         <<endl<<li<<is<< ""
00694         <<endl<<li<<is<< "  norm(v4)/norm(v1) <= adjoint_solution_error_solve_tol() + adjoint_solution_error_slack_error_tol()"
00695         <<endl;
00696 
00697       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00698 
00699         oss <<endl<<li<<is<< "Random vector tests = " << rand_vec_i << endl;
00700       
00701         oss <<endl<<li<<is<< "v1 = randomize(-1,+1); ...\n" ;
00702         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v1 = createMember(range);
00703         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00704         if(dump_all()) oss <<endl<<li<<is<< "v1 =\n" << describe(*v1,verbLevel,li,is);
00705       
00706         oss <<endl<<li<<is<< "v2 = Op*v1 ...\n" ;
00707         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v2 = createMember(domain);
00708         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00709         if(dump_all()) oss <<endl<<li<<is<< "v2 =\n" << describe(*v2,verbLevel,li,is);
00710 
00711         oss <<endl<<li<<is<< "v3 = inv(Op)*v2 ...\n" ;
00712         Teuchos::RefCountPtr<VectorBase<RangeScalar> > v3 = createMember(range);
00713         SolveCriteria<Scalar> solveCriteria(SOLVE_TOL_REL_SOLUTION_ERR_NORM,adjoint_solution_error_solve_tol());
00714         assign(&*v3,RST::zero());
00715         SolveStatus<Scalar> solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,&solveCriteria);
00716         if(dump_all()) oss <<endl<<li<<is<< "v3 =\n" << describe(*v3,verbLevel,li,is);
00717         oss
00718           <<endl<<li<<is<< "solve status:"
00719           <<endl<<li<<is<<is<< "solveStatus = " << toString(solveStatus.solveStatus)
00720           <<endl<<li<<is<<is<< "achievedTol = " << SolveStatus<DomainScalar>::achievedTolToString(solveStatus.achievedTol)
00721           <<endl<<li<<is<<is<< "iterations  = " << solveStatus.iterations
00722           <<endl<<li<<is<<is<< "message     = \"" << solveStatus.message << "\""
00723           <<endl;
00724         oss
00725           <<endl<<li<<is<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00726           << passfail(solveStatus.solveStatus==SOLVE_STATUS_CONVERGED)<<endl;
00727         if(solveStatus.achievedTol==SolveStatus<DomainScalar>::unknownTolerance())
00728           oss <<endl<<li<<is<<"achievedTol==unknownTolerance(): Setting achievedTol = adjoint_solution_error_solve_tol() = "<<adjoint_solution_error_solve_tol()<<endl;
00729       
00730         oss <<endl<<li<<is<< "v4 = v3 - v1 ...\n" ;
00731         Teuchos::RefCountPtr<VectorBase<DomainScalar> > v4 = createMember(range);
00732         V_VmV( &*v4, *v3, *v1 );
00733         if(dump_all()) oss <<endl<<li<<is<< "v4 =\n" << describe(*v4,verbLevel,li,is);
00734       
00735         const DomainScalarMag
00736           norm_v1 = norm(*v1),
00737           norm_v4 = norm(*v4),
00738           norm_v4_norm_v1 = norm_v4/norm_v1;
00739 
00740         result = testMaxErr(
00741           "norm(v4)/norm(v1)", norm_v4_norm_v1
00742           ,"adjoint_solution_error_solve_tol()+adjoint_solution_error_slack_error_tol()", DomainScalarMag(adjoint_solution_error_solve_tol()+adjoint_solution_error_slack_error_tol())
00743           ,"adjoint_solution_error_solve_tol()+adjoint_solution_error_slack_warning_tol()", DomainScalarMag(adjoint_solution_error_solve_tol()+adjoint_solution_error_slack_warning_tol())
00744           ,&oss,li+is
00745           );
00746         if(!result) these_results = false;
00747 
00748       }
00749     }
00750     else {
00751       oss <<endl<<li<<is<< "Adjoint operator not supported, skipping check!\n";
00752     }
00753 
00754     printTestResults(these_results,oss.str(),show_all_tests(),&success,out);
00755 
00756   }
00757   else {
00758     if(out) *out <<endl<<li<< "this->check_adjoint_solution_error()==false: Skipping the check of the adjoint solve with a tolerance on the solution_error!\n";
00759   }
00760   
00761   if(out) {
00762     if(success)
00763       *out <<endl<<li<<"Congratulations, this LinearOpWithSolveBase object seems to check out!\n";
00764     else
00765       *out <<endl<<li<<"Oh no, at least one of the tests performed with this LinearOpWithSolveBase object failed (see above failures)!\n";
00766     *out <<endl<<li<< "*** Leaving LinearOpWithSolveTester<"<<ST::name()<<">::check(...)\n";
00767   }
00768   
00769   return success;
00770   
00771 }
00772 
00773 } // namespace Thyra
00774 
00775 #endif // THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP

Generated on Thu Sep 18 12:39:52 2008 for Thyra ANA Operator/VectorBase Interfaces and Related Software by doxygen 1.3.9.1