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_TestingTools.hpp"
00040 #include "Teuchos_Time.hpp"
00041
00042
00043 namespace Thyra {
00044
00045
00046
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
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
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
00167 validPL = pl;
00168 }
00169 return validPL;
00170 }
00171
00172
00173
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
00713
00714
00715
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 }
00755
00756
00757 #endif // THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP