#include "ExampleTridiagSpmdLinearOp.hpp"
#include "sillyCgSolve.hpp"
#include "Thyra_VectorStdOps.hpp"
#include "Thyra_TestingTools.hpp"
#include "Thyra_LinearOpTester.hpp"
#include "Teuchos_GlobalMPISession.hpp"
#include "Teuchos_CommandLineProcessor.hpp"
#include "Teuchos_DefaultComm.hpp"
#include "Teuchos_VerboseObject.hpp"
#include "Teuchos_Time.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
template<class Scalar>
bool runCgSolveExample(
const Teuchos::RefCountPtr<const Teuchos::Comm<Thyra::Index> > &comm
,const int procRank
,const int numProc
,const int localDim
,const Scalar diagScale
,const bool showAllTests
,const bool verbose
,const bool dumpAll
,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance
,const int maxNumIters
)
{
using Teuchos::RefCountPtr;
using Teuchos::rcp;
using Teuchos::OSTab;
typedef Teuchos::ScalarTraits<Scalar> ST;
typedef typename ST::magnitudeType ScalarMag;
bool success = true;
bool result;
Teuchos::RefCountPtr<Teuchos::FancyOStream>
out = (verbose ? Teuchos::VerboseObjectBase::getDefaultOStream() : Teuchos::null);
if(verbose)
*out << "\n***\n*** Running silly CG solver using scalar type = \'" << ST::name() << "\' ...\n***\n";
Teuchos::Time timer("");
timer.start(true);
if(verbose)
*out << "\nConstructing tridiagonal matrix A of local dimension = " << localDim
<< " and diagonal multiplier = " << diagScale << " ...\n";
const Thyra::Index
lowerDim = ( procRank == 0 ? localDim - 1 : localDim ),
upperDim = ( procRank == numProc-1 ? localDim - 1 : localDim );
std::vector<Scalar> lower(lowerDim), diag(localDim), upper(upperDim);
const Scalar one = ST::one(), diagTerm = Scalar(2)*diagScale*ST::one();
int k = 0, kl = 0;
if(procRank > 0) { lower[kl] = -one; ++kl; }; diag[k] = diagTerm; upper[k] = -one;
for( k = 1; k < localDim - 1; ++k, ++kl ) {
lower[kl] = -one; diag[k] = diagTerm; upper[k] = -one;
}
lower[kl] = -one; diag[k] = diagTerm; if(procRank < numProc-1) upper[k] = -one;
RefCountPtr<const Thyra::LinearOpBase<Scalar> >
A = rcp(new ExampleTridiagSpmdLinearOp<Scalar>(comm,localDim,&lower[0],&diag[0],&upper[0]));
if(verbose) *out << "\nGlobal dimension of A = " << A->domain()->dim() << std::endl;
if(verbose) *out << "\nTesting the constructed linear operator A ...\n";
Thyra::LinearOpTester<Scalar> linearOpTester;
linearOpTester.dump_all(dumpAll);
linearOpTester.set_all_error_tol(tolerance);
linearOpTester.set_all_warning_tol(ScalarMag(ScalarMag(1e-2)*tolerance));
linearOpTester.show_all_tests(true);
linearOpTester.check_adjoint(false);
linearOpTester.check_for_symmetry(true);
linearOpTester.show_all_tests(showAllTests);
result = linearOpTester.check(*A,out.get());
if(!result) success = false;
RefCountPtr<Thyra::VectorBase<Scalar> > b = createMember(A->range());
Thyra::seed_randomize<Scalar>(0);
Thyra::randomize( Scalar(-ST::one()), Scalar(+ST::one()), &*b );
RefCountPtr<Thyra::VectorBase<Scalar> > x = createMember(A->domain());
Thyra::assign( &*x, ST::zero() );
if(verbose) *out << "\nSolving the linear system with sillyCgSolve(...) ...\n";
result = sillyCgSolve(*A,*b,maxNumIters,tolerance,&*x,OSTab(out).getOStream().get());
if(!result) success = false;
RefCountPtr<Thyra::VectorBase<Scalar> > r = createMember(A->range());
Thyra::assign(&*r,*b);
Thyra::apply(*A,Thyra::NOTRANS,*x,&*r,Scalar(-ST::one()),ST::one());
const ScalarMag r_nrm = Thyra::norm(*r), b_nrm = Thyra::norm(*b);
const ScalarMag rel_err = r_nrm/b_nrm, relaxTol = ScalarMag(10.0)*tolerance;
result = rel_err <= relaxTol;
if(!result) success = false;
if(verbose) {
*out << "\nChecking the residual ourselves ...\n";
if(1){
OSTab tab(out);
*out
<< "\n||b-A*x||/||b|| = "<<r_nrm<<"/"<<b_nrm<<" = "<<rel_err<<(result?" <= ":" > ")
<<"10.0*tolerance = "<<relaxTol<<": "<<(result?"passed":"failed")<<std::endl;
}
}
timer.stop();
if(verbose) *out << "\nTotal time = " << timer.totalElapsedTime() << " sec\n";
return success;
}
int main(int argc, char *argv[])
{
using Teuchos::CommandLineProcessor;
bool success = true;
bool verbose = true;
bool result;
Teuchos::GlobalMPISession mpiSession(&argc,&argv);
const int procRank = Teuchos::GlobalMPISession::getRank();
const int numProc = Teuchos::GlobalMPISession::getNProc();
const Teuchos::RefCountPtr<const Teuchos::Comm<Thyra::Index> >
comm = Teuchos::DefaultComm<Thyra::Index>::getComm();
Teuchos::RefCountPtr<Teuchos::FancyOStream>
out = Teuchos::VerboseObjectBase::getDefaultOStream();
try {
int localDim = 500;
double diagScale = 1.001;
double tolerance = 1e-4;
bool showAllTests = false;
int maxNumIters = 300;
bool dumpAll = false;
CommandLineProcessor clp;
clp.throwExceptions(false);
clp.addOutputSetupOptions(true);
clp.setOption( "verbose", "quiet", &verbose, "Determines if any output is printed or not." );
clp.setOption( "local-dim", &localDim, "Local dimension of the linear system." );
clp.setOption( "diag-scale", &diagScale, "Scaling of the diagonal to improve conditioning." );
clp.setOption( "show-all-tests", "show-summary-only", &showAllTests, "Show all LinearOpTester tests or not" );
clp.setOption( "tol", &tolerance, "Relative tolerance for linear system solve." );
clp.setOption( "max-num-iters", &maxNumIters, "Maximum of CG iterations." );
clp.setOption( "dump-all", "no-dump-all", &dumpAll, "Determines if vectors are printed or not." );
CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
TEST_FOR_EXCEPTION( localDim < 2, std::logic_error, "Error, localDim=" << localDim << " < 2 is not allowed!" );
result = runCgSolveExample<float>(comm,procRank,numProc,localDim,diagScale,showAllTests,verbose,dumpAll,tolerance,maxNumIters);
if(!result) success = false;
result = runCgSolveExample<double>(comm,procRank,numProc,localDim,diagScale,showAllTests,verbose,dumpAll,tolerance,maxNumIters);
if(!result) success = false;
#if defined(HAVE_COMPLEX) && defined(HAVE_TEUCHOS_COMPLEX)
result = runCgSolveExample<std::complex<float> >(comm,procRank,numProc,localDim,diagScale,showAllTests,verbose,dumpAll,tolerance,maxNumIters);
if(!result) success = false;
result = runCgSolveExample<std::complex<double> >(comm,procRank,numProc,localDim,diagScale,showAllTests,verbose,dumpAll,tolerance,maxNumIters);
if(!result) success = false;
#endif
}
TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success)
if( verbose && procRank==0 ) {
if(success) *out << "\nAll of the tests seem to have run successfully!\n";
else *out << "\nOh no! at least one of the tests failed!\n";
}
return success ? 0 : 1;
}