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