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 
00030 #ifndef THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00031 #define THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00032 
00033 
00034 #include "Thyra_LinearOpWithSolveTesterDecl.hpp"
00035 #include "Thyra_LinearOpWithSolveBase.hpp"
00036 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
00037 #include "Thyra_describeLinearOp.hpp"
00038 #include "Thyra_VectorStdOps.hpp"
00039 #include "Thyra_TestingTools.hpp"
00040 #include "Teuchos_Time.hpp"
00041 
00042 
00043 namespace Thyra {
00044 
00045 
00046 // Constructors/initializers
00047 
00048 
00049 template<class RangeScalar, class DomainScalar>
00050 LinearOpWithSolveTester<RangeScalar,DomainScalar>::LinearOpWithSolveTester()
00051   :check_forward_default_(check_forward_default_default_),
00052    forward_default_residual_warning_tol_(warning_tol_default_),
00053    forward_default_residual_error_tol_(error_tol_default_),
00054    forward_default_solution_error_warning_tol_(warning_tol_default_),
00055    forward_default_solution_error_error_tol_(error_tol_default_),
00056    check_forward_residual_(check_forward_residual_default_),
00057    forward_residual_solve_tol_(solve_tol_default_),
00058    forward_residual_slack_warning_tol_(slack_warning_tol_default_),
00059    forward_residual_slack_error_tol_(slack_error_tol_default_),
00060    check_adjoint_default_(check_adjoint_default_default_),
00061    adjoint_default_residual_warning_tol_(warning_tol_default_),
00062    adjoint_default_residual_error_tol_(error_tol_default_),
00063    adjoint_default_solution_error_warning_tol_(warning_tol_default_),
00064    adjoint_default_solution_error_error_tol_(error_tol_default_),
00065    check_adjoint_residual_(check_adjoint_residual_default_),
00066    adjoint_residual_solve_tol_(solve_tol_default_),
00067    adjoint_residual_slack_warning_tol_(slack_warning_tol_default_),
00068    adjoint_residual_slack_error_tol_(slack_error_tol_default_),
00069    num_random_vectors_(num_random_vectors_default_),
00070    show_all_tests_(show_all_tests_default_),
00071    dump_all_(dump_all_default_),
00072    num_rhs_(num_rhs_default_)
00073 {}
00074 
00075 
00076 template<class RangeScalar, class DomainScalar>
00077 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::turn_off_all_tests()
00078 {
00079   check_forward_default_ = false;
00080   check_forward_residual_ = false;
00081   check_adjoint_default_ = false;
00082   check_adjoint_residual_ = false;
00083 }
00084 
00085 
00086 template<class RangeScalar, class DomainScalar>
00087 void
00088 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_solve_tol(
00089   const ScalarMag solve_tol )
00090 {
00091   forward_residual_solve_tol_ = solve_tol;
00092   forward_residual_solve_tol_ = solve_tol;
00093   adjoint_residual_solve_tol_ = solve_tol;
00094 }
00095 
00096 
00097 template<class RangeScalar, class DomainScalar>
00098 void
00099 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_warning_tol(
00100   const ScalarMag slack_warning_tol )
00101 {
00102   forward_default_residual_warning_tol_ = slack_warning_tol;
00103   forward_default_solution_error_warning_tol_ = slack_warning_tol;
00104   forward_residual_slack_warning_tol_ = slack_warning_tol;
00105   adjoint_default_residual_warning_tol_ = slack_warning_tol;
00106   adjoint_default_solution_error_warning_tol_ = slack_warning_tol;
00107   adjoint_residual_slack_warning_tol_ = slack_warning_tol;
00108 }
00109 
00110 
00111 template<class RangeScalar, class DomainScalar>
00112 void
00113 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_error_tol(
00114   const ScalarMag slack_error_tol )
00115 {
00116   forward_default_residual_error_tol_ = slack_error_tol;
00117   forward_default_solution_error_error_tol_ = slack_error_tol;
00118   forward_residual_slack_error_tol_ = slack_error_tol;
00119   adjoint_default_residual_error_tol_ = slack_error_tol;
00120   adjoint_default_solution_error_error_tol_ = slack_error_tol;
00121   adjoint_residual_slack_error_tol_ = slack_error_tol;
00122 }
00123 
00124 
00125 // Overridden from ParameterListAcceptor
00126 
00127 
00128 template<class RangeScalar, class DomainScalar>
00129 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::setParameterList(
00130   const RCP<ParameterList>& paramList )
00131 {
00132   using Teuchos::getParameter;
00133   ParameterList &pl = *paramList;
00134   this->setMyParamList(paramList);
00135   paramList->validateParametersAndSetDefaults(*getValidParameters());
00136   set_all_solve_tol(getParameter<ScalarMag>(pl, AllSolveTol_name_));
00137   set_all_slack_warning_tol(getParameter<ScalarMag>(pl, AllSlackWarningTol_name_));
00138   set_all_slack_error_tol(getParameter<ScalarMag>(pl, AllSlackErrorTol_name_));
00139   show_all_tests(getParameter<bool>(pl, ShowAllTests_name_));
00140   dump_all(getParameter<bool>(pl, DumpAll_name_));
00141   // ToDo: Add more parameters as you need them
00142 }
00143 
00144 
00145 template<class RangeScalar, class DomainScalar>
00146 RCP<const ParameterList>
00147 LinearOpWithSolveTester<RangeScalar,DomainScalar>::getValidParameters() const
00148 {
00149   static RCP<const ParameterList> validPL;
00150   if (is_null(validPL) ) {
00151     RCP<ParameterList> pl = Teuchos::parameterList();
00152     pl->set(AllSolveTol_name_, solve_tol_default_,
00153       "Sets all of the solve tolerances to the same value.  Note: This option\n"
00154       "is applied before any specific tolerance which may override it.");
00155     pl->set(AllSlackWarningTol_name_, slack_warning_tol_default_,
00156       "Sets all of the slack warning values to the same value.  Note: This option\n"
00157       "is applied before any specific tolerance which may override it.");
00158     pl->set(AllSlackErrorTol_name_, slack_error_tol_default_,
00159       "Sets all of the slack error values to the same value.  Note: This option\n"
00160       "is applied before any specific tolerance which may override it.");
00161     pl->set(ShowAllTests_name_, false,
00162       "If true, then all tests be traced to the output stream.");
00163     pl->set(DumpAll_name_, false,
00164       "If true, then all qualtities will be dumped to the output stream.  Warning!\n"
00165       "only do this to debug smaller problems as this can create a lot of output");
00166     // ToDo: Add more parameters as you need them (don't forget to test them)
00167     validPL = pl;
00168   }
00169   return validPL;
00170 }
00171 
00172 
00173 // LOWS testing
00174 
00175 
00176 template<class RangeScalar, class DomainScalar>
00177 bool LinearOpWithSolveTester<RangeScalar,DomainScalar>::check(
00178   const LinearOpWithSolveBase<RangeScalar,DomainScalar> &op,
00179   Teuchos::FancyOStream *out_arg ) const
00180 {
00181 
00182   using std::endl;
00183   using Teuchos::arrayArg;
00184   using Teuchos::FancyOStream;
00185   using Teuchos::OSTab;
00186   typedef Teuchos::VerboseObjectTempState<LinearOpWithSolveBase<RangeScalar,DomainScalar> > VOTS;
00187   typedef Teuchos::ScalarTraits<Scalar>        ST;
00188   typedef Teuchos::ScalarTraits<RangeScalar>   DST;
00189   typedef Teuchos::ScalarTraits<DomainScalar>  RST;
00190   bool success = true, result;
00191   const int num_rhs = this->num_rhs();
00192   Teuchos::RCP<FancyOStream> out = Teuchos::rcp(out_arg,false);
00193   const Teuchos::EVerbosityLevel verbLevel = (dump_all()?Teuchos::VERB_EXTREME:Teuchos::VERB_MEDIUM);
00194   Teuchos::Time timer("");
00195 
00196   OSTab tab(out,1,"THYRA");
00197 
00198   if(out.get()) {
00199     *out <<endl<< "*** Entering LinearOpWithSolveTester<"<<ST::name()<<">::check(op,...) ...\n";
00200     if(show_all_tests()) {
00201       *out <<endl<< "describe forward op:\n" << Teuchos::describe(op,verbLevel);
00202       if(op.applyTransposeSupports(CONJ_ELE) && verbLevel==Teuchos::VERB_EXTREME) {
00203         *out <<endl<< "describe adjoint op:\n";
00204         describeLinearOp<RangeScalar,DomainScalar>(
00205           *adjoint(Teuchos::rcp_implicit_cast< const LinearOpBase<RangeScalar,DomainScalar> >(Teuchos::rcp(&op,false)))
00206           ,*out,verbLevel
00207           );
00208       }
00209     }
00210     else {
00211       *out <<endl<< "describe op: " << op.description() << endl;
00212     }
00213   }
00214   
00215   Teuchos::RCP<const VectorSpaceBase<RangeScalar> >   range  = op.range();
00216   Teuchos::RCP<const VectorSpaceBase<DomainScalar> >  domain = op.domain();
00217   
00218   if( check_forward_default() ) {
00219 
00220     if(out.get()) *out <<endl<< "this->check_forward_default()==true: Checking the default forward solve ... ";
00221 
00222     std::ostringstream ossStore;
00223     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00224     if(out.get()) ossStore.copyfmt(*out);
00225     bool these_results = true;
00226 
00227     *oss <<endl<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00228     result = op.solveSupportsConj(NONCONJ_ELE);
00229     if(!result) these_results = false;
00230     *oss << passfail(result) << endl;
00231 
00232     if(result) {
00233     
00234       *oss
00235         <<endl<< "Checking that the forward default solve matches the forward operator:\n"
00236         <<endl<< "  inv(Op)*Op*v1 == v1"
00237         <<endl<< "          \\___/"
00238         <<endl<< "           v2"
00239         <<endl<< "  \\___________/"
00240         <<endl<< "         v3"
00241         <<endl<< ""
00242         <<endl<< "  v4 = v3-v1"
00243         <<endl<< "  v5 = Op*v3-v2"
00244         <<endl<< ""
00245         <<endl<< "  norm(v4)/norm(v1) <= forward_default_solution_error_error_tol()"
00246         <<endl<< "  norm(v5)/norm(v2) <= forward_default_residual_error_tol()"
00247         <<endl;
00248 
00249       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00250 
00251         OSTab tab(oss);
00252 
00253         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00254 
00255         tab.incrTab();
00256       
00257         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00258         Teuchos::RCP<MultiVectorBase<DomainScalar> > v1 = createMembers(domain,num_rhs);
00259         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00260         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00261       
00262         *oss <<endl<< "v2 = Op*v1 ...\n" ;
00263         Teuchos::RCP<MultiVectorBase<RangeScalar> > v2 = createMembers(range,num_rhs);
00264         timer.start(true);
00265         op.apply(NONCONJ_ELE,*v1,&*v2);
00266         timer.stop();
00267         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00268         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00269 
00270         *oss <<endl<< "v3 = inv(Op)*v2 ...\n" ;
00271         Teuchos::RCP<MultiVectorBase<DomainScalar> > v3 = createMembers(domain,num_rhs);
00272         assign(&*v3,DST::zero());
00273         SolveStatus<Scalar> solveStatus;
00274         {
00275           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00276           timer.start(true);
00277           solveStatus = solve(op,NONCONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00278           timer.stop();
00279           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00280         }
00281         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00282         *oss
00283           <<endl<< "solve status:\n";
00284         OSTab(oss).o() << solveStatus;
00285 
00286         *oss <<endl<< "v4 = v3 - v1 ...\n" ;
00287         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(domain,num_rhs);
00288         V_VmV( &*v4, *v3, *v1 );
00289         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00290       
00291         *oss <<endl<< "v5 = Op*v3 - v2 ...\n" ;
00292         Teuchos::RCP<MultiVectorBase<RangeScalar> > v5 = createMembers(range,num_rhs);
00293         assign( &*v5, *v2 );
00294         timer.start(true);
00295         op.apply(NONCONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00296         timer.stop();
00297         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00298         if(dump_all()) *oss <<endl<< "v5 =\n" << describe(*v5,verbLevel);
00299 
00300         std::vector<DomainScalarMag> norms_v1(num_rhs), norms_v4(num_rhs), norms_v4_norms_v1(num_rhs);
00301         norms(*v1,&norms_v1[0]);
00302         norms(*v4,&norms_v4[0]);
00303         std::transform(
00304           norms_v4.begin(),norms_v4.end(),norms_v1.begin(),norms_v4_norms_v1.begin()
00305           ,std::divides<DomainScalarMag>()
00306           );
00307 
00308         result = testMaxErrors(
00309           num_rhs, "norm(v4)/norm(v1)", &norms_v4_norms_v1[0]
00310           ,"forward_default_solution_error_error_tol()", forward_default_solution_error_error_tol()
00311           ,"forward_default_solution_error_warning_tol()", forward_default_solution_error_warning_tol()
00312           ,&*oss
00313           );
00314         if(!result) these_results = false;
00315 
00316         std::vector<RangeScalarMag> norms_v2(num_rhs), norms_v5(num_rhs), norms_v5_norms_v2(num_rhs);
00317         norms(*v2,&norms_v2[0]);
00318         norms(*v5,&norms_v5[0]);
00319         std::transform(
00320           norms_v5.begin(),norms_v5.end(),norms_v2.begin(),norms_v5_norms_v2.begin()
00321           ,std::divides<RangeScalarMag>()
00322           );
00323 
00324         result = testMaxErrors(
00325           num_rhs, "norm(v5)/norm(v2)", &norms_v5_norms_v2[0]
00326           ,"forward_default_residual_error_tol()", forward_default_residual_error_tol()
00327           ,"forward_default_residual_warning_tol()", forward_default_residual_warning_tol()
00328           ,&*oss
00329           );
00330         if(!result) these_results = false;
00331         
00332       }
00333     }
00334     else {
00335       *oss <<endl<< "Forward operator not supported, skipping check!\n";
00336     }
00337 
00338     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00339 
00340   }
00341   else {
00342     if(out.get()) *out <<endl<< "this->check_forward_default()==false: Skipping the check of the default forward solve!\n";
00343   }
00344   
00345   if( check_forward_residual() ) {
00346 
00347     if(out.get()) *out <<endl<< "this->check_forward_residual()==true: Checking the forward solve with a tolerance on the residual ... ";
00348 
00349     std::ostringstream ossStore;
00350     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00351     if(out.get()) ossStore.copyfmt(*out);
00352     bool these_results = true;
00353 
00354     *oss <<endl<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00355     result = op.solveSupportsConj(NONCONJ_ELE);
00356     if(!result) these_results = false;
00357     *oss << passfail(result) << endl;
00358 
00359     if(result) {
00360     
00361       *oss
00362         <<endl<< "Checking that the forward solve matches the forward operator to a residual tolerance:\n"
00363         <<endl<< "  v3 = inv(Op)*Op*v1"
00364         <<endl<< "               \\___/"
00365         <<endl<< "                 v2"
00366         <<endl<< ""
00367         <<endl<< "  v4 = Op*v3-v2"
00368         <<endl<< ""
00369         <<endl<< "  norm(v4)/norm(v2) <= forward_residual_solve_tol() + forward_residual_slack_error_tol()"
00370         <<endl;
00371 
00372       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00373 
00374         OSTab tab(oss);
00375 
00376         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00377 
00378         tab.incrTab();
00379       
00380         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00381         Teuchos::RCP<MultiVectorBase<DomainScalar> > v1 = createMembers(domain,num_rhs);
00382         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00383         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00384       
00385         *oss <<endl<< "v2 = Op*v1 ...\n" ;
00386         Teuchos::RCP<MultiVectorBase<RangeScalar> > v2 = createMembers(range,num_rhs);
00387         timer.start(true);
00388         op.apply(NONCONJ_ELE,*v1,&*v2);
00389         timer.stop();
00390         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00391         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00392 
00393         *oss <<endl<< "v3 = inv(Op)*v2 ...\n" ;
00394         Teuchos::RCP<MultiVectorBase<DomainScalar> > v3 = createMembers(domain,num_rhs);
00395         SolveCriteria<Scalar> solveCriteria(
00396           SolveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
00397           ,forward_residual_solve_tol()
00398           );
00399         assign(&*v3,DST::zero());
00400         SolveStatus<Scalar> solveStatus;
00401         {
00402           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00403           timer.start(true);
00404           solveStatus = solve<RangeScalar,DomainScalar>(op,NONCONJ_ELE,*v2,&*v3,&solveCriteria);
00405           timer.stop();
00406           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00407         }
00408         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00409         *oss
00410           <<endl<< "solve status:\n";
00411         OSTab(oss).o() << solveStatus;
00412         result = solveStatus.solveStatus==SOLVE_STATUS_CONVERGED;
00413         if(!result) these_results = false;
00414         *oss
00415           <<endl<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00416           << passfail(result)<<endl;
00417       
00418         *oss <<endl<< "v4 = Op*v3 - v2 ...\n" ;
00419         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(range,num_rhs);
00420         assign( &*v4, *v2 );
00421         timer.start(true);
00422         op.apply(NONCONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00423         timer.stop();
00424         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00425         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00426 
00427         std::vector<DomainScalarMag> norms_v2(num_rhs), norms_v4(num_rhs), norms_v4_norms_v2(num_rhs);
00428         norms(*v2,&norms_v2[0]);
00429         norms(*v4,&norms_v4[0]);
00430         std::transform(
00431           norms_v4.begin(),norms_v4.end(),norms_v2.begin(),norms_v4_norms_v2.begin()
00432           ,std::divides<DomainScalarMag>()
00433           );
00434 
00435         result = testMaxErrors(
00436           num_rhs, "norm(v4)/norm(v2)", &norms_v4_norms_v2[0]
00437           ,"forward_residual_solve_tol()+forward_residual_slack_error_tol()", DomainScalarMag(forward_residual_solve_tol()+forward_residual_slack_error_tol())
00438           ,"forward_residual_solve_tol()_slack_warning_tol()", DomainScalarMag(forward_residual_solve_tol()+forward_residual_slack_warning_tol())
00439           ,&*oss
00440           );
00441         if(!result) these_results = false;
00442 
00443       }
00444     }
00445     else {
00446       *oss <<endl<< "Forward operator not supported, skipping check!\n";
00447     }
00448 
00449     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00450 
00451   }
00452   else {
00453     if(out.get()) *out <<endl<< "this->check_forward_residual()==false: Skipping the check of the forward solve with a tolerance on the residual!\n";
00454   }
00455   
00456   if( check_adjoint_default() ) {
00457 
00458     if(out.get()) *out <<endl<< "this->check_adjoint_default()==true: Checking the default adjoint solve ... ";
00459 
00460     std::ostringstream ossStore;
00461     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00462     if(out.get()) ossStore.copyfmt(*out);
00463     bool these_results = true;
00464 
00465     *oss <<endl<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00466     result = op.solveTransposeSupportsConj(CONJ_ELE);
00467     if(!result) these_results = false;
00468     *oss << passfail(result) << endl;
00469 
00470     if(result) {
00471     
00472       *oss
00473         <<endl<< "Checking that the adjoint default solve matches the adjoint operator:\n"
00474         <<endl<< "  inv(Op')*Op'*v1 == v1"
00475         <<endl<< "           \\____/"
00476         <<endl<< "             v2"
00477         <<endl<< "  \\_____________/"
00478         <<endl<< "         v3"
00479         <<endl<< ""
00480         <<endl<< "  v4 = v3-v1"
00481         <<endl<< "  v5 = Op'*v3-v2"
00482         <<endl<< ""
00483         <<endl<< "  norm(v4)/norm(v1) <= adjoint_default_solution_error_error_tol()"
00484         <<endl<< "  norm(v5)/norm(v2) <= adjoint_default_residual_error_tol()"
00485         <<endl;
00486 
00487       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00488 
00489         OSTab tab(oss);
00490 
00491         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00492         
00493         tab.incrTab();
00494       
00495         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00496         Teuchos::RCP<MultiVectorBase<RangeScalar> > v1 = createMembers(range,num_rhs);
00497         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00498         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00499       
00500         *oss <<endl<< "v2 = Op'*v1 ...\n" ;
00501         Teuchos::RCP<MultiVectorBase<DomainScalar> > v2 = createMembers(domain,num_rhs);
00502         timer.start(true);
00503         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00504         timer.stop();
00505         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00506         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00507 
00508         *oss <<endl<< "v3 = inv(Op')*v2 ...\n" ;
00509         Teuchos::RCP<MultiVectorBase<RangeScalar> > v3 = createMembers(range,num_rhs);
00510         assign(&*v3,DST::zero());
00511         SolveStatus<Scalar> solveStatus;
00512         {
00513           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00514           timer.start(true);
00515           solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00516           timer.stop();
00517           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00518         }
00519         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00520         *oss
00521           <<endl<< "solve status:\n";
00522         OSTab(oss).o() << solveStatus;
00523 
00524         *oss <<endl<< "v4 = v3 - v1 ...\n" ;
00525         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(range,num_rhs);
00526         V_VmV( &*v4, *v3, *v1 );
00527         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00528       
00529         *oss <<endl<< "v5 = Op'*v3 - v2 ...\n" ;
00530         Teuchos::RCP<MultiVectorBase<DomainScalar> > v5 = createMembers(domain,num_rhs);
00531         assign( &*v5, *v2 );
00532         timer.start(true);
00533         op.applyTranspose(CONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00534         timer.stop();
00535         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00536         if(dump_all()) *oss <<endl<< "v5 =\n" << describe(*v5,verbLevel);
00537 
00538         std::vector<RangeScalarMag> norms_v1(num_rhs), norms_v4(num_rhs), norms_v4_norms_v1(num_rhs);
00539         norms(*v1,&norms_v1[0]);
00540         norms(*v4,&norms_v4[0]);
00541         std::transform(
00542           norms_v4.begin(),norms_v4.end(),norms_v1.begin(),norms_v4_norms_v1.begin()
00543           ,std::divides<RangeScalarMag>()
00544           );
00545 
00546         result = testMaxErrors(
00547           num_rhs, "norm(v4)/norm(v1)", &norms_v4_norms_v1[0]
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
00551           );
00552         if(!result) these_results = false;
00553 
00554         std::vector<DomainScalarMag> norms_v2(num_rhs), norms_v5(num_rhs), norms_v5_norms_v2(num_rhs);
00555         norms(*v2,&norms_v2[0]);
00556         norms(*v5,&norms_v5[0]);
00557         std::transform(
00558           norms_v5.begin(),norms_v5.end(),norms_v2.begin(),norms_v5_norms_v2.begin()
00559           ,std::divides<DomainScalarMag>()
00560           );
00561 
00562         result = testMaxErrors(
00563           num_rhs, "norm(v5)/norm(v2)", &norms_v5_norms_v2[0]
00564           ,"adjoint_default_residual_error_tol()", adjoint_default_residual_error_tol()
00565           ,"adjoint_default_residual_warning_tol()", adjoint_default_residual_warning_tol()
00566           ,&*oss
00567           );
00568         if(!result) these_results = false;
00569 
00570       }
00571     }
00572     else {
00573       *oss <<endl<< "Adjoint operator not supported, skipping check!\n";
00574     }
00575 
00576     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00577 
00578   }
00579   else {
00580     if(out.get()) *out <<endl<< "this->check_adjoint_default()==false: Skipping the check of the adjoint solve with a default tolerance!\n";
00581   }
00582   
00583   if( check_adjoint_residual() ) {
00584 
00585     if(out.get()) *out <<endl<< "this->check_adjoint_residual()==true: Checking the adjoint solve with a tolerance on the residual ... ";
00586     
00587     std::ostringstream ossStore;
00588     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00589     if(out.get()) ossStore.copyfmt(*out);
00590     bool these_results = true;
00591 
00592     *oss <<endl<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00593     result = op.solveTransposeSupportsConj(CONJ_ELE);
00594     if(!result) these_results = false;
00595     *oss << passfail(result) << endl;
00596 
00597     if(result) {
00598     
00599       *oss
00600         <<endl<< "Checking that the adjoint solve matches the adjoint operator to a residual tolerance:\n"
00601         <<endl<< "  v3 = inv(Op')*Op'*v1"
00602         <<endl<< "                \\____/"
00603         <<endl<< "                  v2"
00604         <<endl<< ""
00605         <<endl<< "  v4 = Op'*v3-v2"
00606         <<endl<< ""
00607         <<endl<< "  norm(v4)/norm(v2) <= adjoint_residual_solve_tol() + adjoint_residual_slack_error_tol()"
00608         <<endl;
00609 
00610       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00611 
00612         OSTab tab(oss);
00613 
00614         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00615 
00616         tab.incrTab();
00617       
00618         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00619         Teuchos::RCP<MultiVectorBase<RangeScalar> > v1 = createMembers(range,num_rhs);
00620         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00621         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00622       
00623         *oss <<endl<< "v2 = Op'*v1 ...\n" ;
00624         Teuchos::RCP<MultiVectorBase<DomainScalar> > v2 = createMembers(domain,num_rhs);
00625         timer.start(true);
00626         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00627         timer.stop();
00628         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00629         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00630 
00631         *oss <<endl<< "v3 = inv(Op')*v2 ...\n" ;
00632         Teuchos::RCP<MultiVectorBase<RangeScalar> > v3 = createMembers(range,num_rhs);
00633         SolveCriteria<Scalar> solveCriteria(
00634           SolveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
00635           ,adjoint_residual_solve_tol()
00636           );
00637         assign(&*v3,RST::zero());
00638         SolveStatus<Scalar> solveStatus;
00639         {
00640           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00641           timer.start(true);
00642           solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,&solveCriteria);
00643           timer.stop();
00644           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00645         }
00646         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00647         *oss
00648           <<endl<< "solve status:\n";
00649         OSTab(oss).o() << solveStatus;
00650         result = solveStatus.solveStatus==SOLVE_STATUS_CONVERGED;
00651         if(!result) these_results = false;
00652         *oss
00653           <<endl<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00654           << passfail(result)<<endl;
00655         if(solveStatus.achievedTol==SolveStatus<RangeScalar>::unknownTolerance())
00656           *oss <<endl<<"achievedTol==unknownTolerance(): Setting achievedTol = adjoint_residual_solve_tol() = "<<adjoint_residual_solve_tol()<<endl;
00657       
00658         *oss <<endl<< "v4 = Op'*v3 - v2 ...\n" ;
00659         Teuchos::RCP<MultiVectorBase<DomainScalar> > v4 = createMembers(domain,num_rhs);
00660         assign( &*v4, *v2 );
00661         timer.start(true);
00662         op.applyTranspose(CONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00663         timer.stop();
00664         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00665         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00666 
00667         std::vector<RangeScalarMag> norms_v2(num_rhs), norms_v4(num_rhs), norms_v4_norms_v2(num_rhs);
00668         norms(*v2,&norms_v2[0]);
00669         norms(*v4,&norms_v4[0]);
00670         std::transform(
00671           norms_v4.begin(),norms_v4.end(),norms_v2.begin(),norms_v4_norms_v2.begin()
00672           ,std::divides<RangeScalarMag>()
00673           );
00674 
00675         result = testMaxErrors(
00676           num_rhs, "norm(v4)/norm(v2)", &norms_v4_norms_v2[0],
00677           "adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol()",
00678           RangeScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol()),
00679           "adjoint_residual_solve_tol()_slack_warning_tol()",
00680           RangeScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_warning_tol()),
00681           &*oss
00682           );
00683         if(!result) these_results = false;
00684 
00685       }
00686     }
00687     else {
00688       *oss <<endl<< "Adjoint operator not supported, skipping check!\n";
00689     }
00690 
00691     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00692 
00693   }
00694   else {
00695     if(out.get())
00696       *out <<endl<< "this->check_adjoint_residual()==false: Skipping the check of the adjoint solve with a tolerance on the residual!\n";
00697   }
00698   
00699   if(out.get()) {
00700     if(success)
00701       *out <<endl<<"Congratulations, this LinearOpWithSolveBase object seems to check out!\n";
00702     else
00703       *out <<endl<<"Oh no, at least one of the tests performed with this LinearOpWithSolveBase object failed (see above failures)!\n";
00704     *out <<endl<< "*** Leaving LinearOpWithSolveTester<"<<ST::name()<<">::check(...)\n";
00705   }
00706   
00707   return success;
00708   
00709 }
00710 
00711 
00712 // private static members
00713 
00714 
00715 // Define local macros used in the next few lines and then undefined
00716 
00717 #define LOWST_DEFINE_RAW_STATIC_MEMBER( DATA_TYPE, MEMBER_NAME, DEFAULT_VALUE ) \
00718 template<class RangeScalar, class DomainScalar> \
00719 const DATA_TYPE \
00720 LinearOpWithSolveTester<RangeScalar,DomainScalar>::MEMBER_NAME = DEFAULT_VALUE
00721 
00722 #define LOWST_DEFINE_MTD_STATIC_MEMBER( DATA_TYPE, MEMBER_NAME, DEFAULT_VALUE ) \
00723 template<class RangeScalar, class DomainScalar> \
00724 const typename LinearOpWithSolveTester<RangeScalar,DomainScalar>::DATA_TYPE \
00725 LinearOpWithSolveTester<RangeScalar,DomainScalar>::MEMBER_NAME = DEFAULT_VALUE
00726 
00727 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_forward_default_default_, true);
00728 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_forward_residual_default_, true);
00729 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_adjoint_default_default_, true);
00730 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_adjoint_residual_default_, true);
00731 
00732 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, warning_tol_default_, 1e-6);
00733 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, error_tol_default_, 1e-5);
00734 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, solve_tol_default_, 1e-5);
00735 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, slack_warning_tol_default_, 1e-6);
00736 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, slack_error_tol_default_, 1e-5);
00737 
00738 LOWST_DEFINE_RAW_STATIC_MEMBER(int, num_random_vectors_default_, 1);
00739 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, show_all_tests_default_, false);
00740 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, dump_all_default_, false);
00741 LOWST_DEFINE_RAW_STATIC_MEMBER(int, num_rhs_default_, 1);
00742 
00743 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSolveTol_name_, "All Solve Tol");
00744 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSlackWarningTol_name_, "All Slack Warning Tol");
00745 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSlackErrorTol_name_, "All Slack Error Tol");
00746 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, ShowAllTests_name_, "Show All Tests");
00747 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, DumpAll_name_, "Dump All");
00748 
00749 #undef LOWST_DEFINE_MTD_STATIC_MEMBER
00750 
00751 #undef LOWST_DEFINE_RAW_STATIC_MEMBER
00752 
00753 
00754 } // namespace Thyra
00755 
00756 
00757 #endif // THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP

Generated on Wed May 12 21:42:47 2010 for Thyra Operator Solve Support by  doxygen 1.4.7