00001
00002
00003 #include <BelosConfigDefs.hpp>
00004 #include <BelosLinearProblem.hpp>
00005 #include <BelosOutputManager.hpp>
00006 #include <BelosStatusTestMaxIters.hpp>
00007 #include <BelosStatusTestMaxRestarts.hpp>
00008 #include <BelosStatusTestResNorm.hpp>
00009 #include <BelosStatusTestCombo.hpp>
00010 #include <BelosEpetraAdapter.hpp>
00011 #include <BelosEpetraOperator.h>
00012 #include <BelosBlockGmres.hpp>
00013
00014 #include <Epetra_Map.h>
00015 #include <Epetra_Vector.h>
00016 #include <Epetra_CrsMatrix.h>
00017
00018 #include <Teuchos_Time.hpp>
00019
00020 #ifdef EPETRA_MPI
00021 #include <Epetra_MpiComm.h>
00022 #include <mpi.h>
00023 #else
00024 #include <Epetra_SerialComm.h>
00025 #endif
00026
00027 using std::vector;
00028 using namespace Belos;
00029
00030
00031
00032 class Vector_Operator
00033 {
00034 public:
00035
00036 Vector_Operator(unsigned m, unsigned n) : m(m), n(n) { y.resize(m, 0.0); };
00037
00038 virtual ~Vector_Operator() {};
00039
00040 virtual vector<double> & operator () (const vector<double> &x) = 0;
00041
00042 int size (int dim) const { return (dim == 1) ? m : n; };
00043
00044 protected:
00045
00046 unsigned m, n;
00047 vector<double> y;
00048
00049 private:
00050
00051
00052 Vector_Operator( const Vector_Operator& ) {};
00053 Vector_Operator* operator=( const Vector_Operator& ) { return NULL; };
00054
00055 };
00056
00057
00058
00059 class Diagonal_Operator : public Vector_Operator
00060 {
00061 public:
00062
00063 Diagonal_Operator(unsigned n, double v) : Vector_Operator(n, n), v(v) { };
00064
00065 ~Diagonal_Operator() { };
00066
00067 vector<double> & operator () (const vector<double> &x)
00068 {
00069 for (unsigned i=0; i < m; ++i) y[i] = v*x[i];
00070
00071 return y;
00072 };
00073
00074 private:
00075
00076 double v;
00077 };
00078
00079
00080
00081 class Diagonal_Operator_2 : public Vector_Operator
00082 {
00083 public:
00084
00085 Diagonal_Operator_2(unsigned n, double v) : Vector_Operator(n, n), v(v) { };
00086
00087 ~Diagonal_Operator_2() { };
00088
00089 vector<double> & operator () (const vector<double> &x)
00090 {
00091 for (unsigned i=0; i < m; ++i) y[i] = (i+1)*v*x[i];
00092
00093 return y;
00094 };
00095
00096 private:
00097
00098 double v;
00099 };
00100
00101
00102
00103 class Composed_Operator : public Vector_Operator
00104 {
00105 public:
00106
00107 Composed_Operator(unsigned n,
00108 const Teuchos::RefCountPtr<Vector_Operator>& pA,
00109 const Teuchos::RefCountPtr<Vector_Operator>& pB);
00110
00111 virtual ~Composed_Operator() {};
00112
00113 virtual vector<double> & operator () (const vector<double> &x);
00114
00115 private:
00116
00117 Teuchos::RefCountPtr<Vector_Operator> pA;
00118 Teuchos::RefCountPtr<Vector_Operator> pB;
00119 };
00120
00121 Composed_Operator::Composed_Operator(unsigned n,
00122 const Teuchos::RefCountPtr<Vector_Operator>& pA,
00123 const Teuchos::RefCountPtr<Vector_Operator>& pB)
00124 : Vector_Operator(n, n), pA(pA), pB(pB)
00125 {
00126 }
00127
00128 vector<double> & Composed_Operator::operator () (const vector<double> &x)
00129 {
00130 y = (*pA)((*pB)(x));
00131 return y;
00132 }
00133
00134
00135
00136 class Trilinos_Interface : public Epetra_Operator
00137 {
00138 public:
00139
00140 Trilinos_Interface(const Teuchos::RefCountPtr<Vector_Operator> pA,
00141 const Teuchos::RefCountPtr<const Epetra_Comm> pComm,
00142 const Teuchos::RefCountPtr<const Epetra_Map> pMap)
00143 : pA(pA), pComm(pComm), pMap(pMap)
00144 {
00145 };
00146
00147 int Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const;
00148
00149 int ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00150 {
00151 return(Apply(X,Y));
00152 };
00153
00154 virtual ~Trilinos_Interface() {};
00155
00156 const char * Label() const {return("Trilinos_Interface, an Epetra_Operator implementation");};
00157
00158 bool UseTranspose() const {return(use_transpose);};
00159
00160 int SetUseTranspose(bool UseTranspose_) { use_transpose = false; return(-1); };
00161
00162 bool HasNormInf() const {return(false);};
00163
00164 double NormInf() const {return(0.0);};
00165
00166 virtual const Epetra_Comm & Comm() const {return *pComm; }
00167
00168 virtual const Epetra_Map & OperatorDomainMap() const {return *pMap; };
00169
00170 virtual const Epetra_Map & OperatorRangeMap() const {return *pMap; };
00171
00172 private:
00173
00174 Teuchos::RefCountPtr<Vector_Operator> pA;
00175 Teuchos::RefCountPtr<const Epetra_Comm> pComm;
00176 Teuchos::RefCountPtr<const Epetra_Map> pMap;
00177
00178 bool use_transpose;
00179 };
00180
00181 int Trilinos_Interface::Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00182 {
00183 vector<double> x(X.MyLength());
00184 X.ExtractCopy(&x[0], X.MyLength());
00185 x = (*pA)(x);
00186
00187 for (int i = 0; i < Y.MyLength(); ++i)
00188 Y.ReplaceMyValue(i, 0, x[i]);
00189 return(0);
00190 }
00191
00192
00193
00194 class Iterative_Inverse_Operator : public Vector_Operator
00195 {
00196
00197 typedef Epetra_MultiVector MV;
00198 typedef Epetra_Operator OP;
00199
00200 public:
00201
00202 Iterative_Inverse_Operator(unsigned n,
00203 const Teuchos::RefCountPtr<Vector_Operator>& pA,
00204 string opString="Iterative Solver", bool print=false);
00205
00206 virtual ~Iterative_Inverse_Operator() {}
00207
00208 virtual vector<double> & operator () (const vector<double> &b);
00209
00210 private:
00211
00212 Teuchos::RefCountPtr<Vector_Operator> pA;
00213
00214 const bool print;
00215
00216 Teuchos::Time timer;
00217 Teuchos::RefCountPtr<Epetra_Comm> pComm;
00218 Teuchos::RefCountPtr<Epetra_Map> pMap;
00219
00220 Teuchos::RefCountPtr<OP> pPE;
00221 Teuchos::RefCountPtr<MV> pPX;
00222 Teuchos::RefCountPtr<MV> pPB;
00223 Teuchos::RefCountPtr<StatusTestMaxIters<double,MV,OP> > test1;
00224 Teuchos::RefCountPtr<StatusTestMaxRestarts<double,MV,OP> > test2;
00225 Teuchos::RefCountPtr<StatusTestCombo<double,MV,OP> > test3;
00226 Teuchos::RefCountPtr<StatusTestResNorm<double,MV,OP> > test4;
00227 Teuchos::RefCountPtr<Teuchos::ParameterList> pList;
00228 Teuchos::RefCountPtr<StatusTestCombo<double,MV,OP> > pTest;
00229 Teuchos::RefCountPtr<LinearProblem<double,MV,OP> > pProb;
00230 Teuchos::RefCountPtr<OutputManager<double> > pOM;
00231 Teuchos::RefCountPtr<BlockGmres<double,MV,OP> > pBelos;
00232 };
00233
00234 Iterative_Inverse_Operator::Iterative_Inverse_Operator(unsigned n,
00235 const Teuchos::RefCountPtr<Vector_Operator>& pA,
00236 string opString, bool print)
00237 : Vector_Operator(n, n),
00238 pA(pA),
00239 print(print),
00240 timer(opString)
00241 {
00242
00243 unsigned n_global;
00244
00245 #ifdef EPETRA_MPI
00246 MPI_Allreduce(&n, &n_global, 1, MPI_UNSIGNED, MPI_SUM, MPI_COMM_WORLD);
00247 pComm = Teuchos::rcp( new Epetra_MpiComm(MPI_COMM_WORLD) );
00248 #else
00249 pComm = Teuchos::rcp( new Epetra_SerialComm() );
00250 n_global = n;
00251 #endif
00252 pMap = Teuchos::rcp( new Epetra_Map(n_global, n, 0, *pComm) );
00253
00254 pPE = Teuchos::rcp( new Trilinos_Interface(pA, pComm, pMap ) );
00255 pPX = Teuchos::rcp( new Epetra_MultiVector(*pMap, 1) );
00256 pPB = Teuchos::rcp( new Epetra_MultiVector(*pMap, 1) );
00257
00258 pProb = Teuchos::rcp( new LinearProblem<double,MV,OP>(pPE, pPX, pPB) );
00259 pProb->SetBlockSize(1);
00260
00261 int restart = 10;
00262 int max_iter = 100;
00263 double tol = 1.0e-10;
00264
00265 test1 = Teuchos::rcp( new StatusTestMaxIters<double,MV,OP>( max_iter ) );
00266 test2 = Teuchos::rcp( new StatusTestMaxRestarts<double,MV,OP>( static_cast<int>(ceil((double)max_iter/restart)) ) );
00267 test3 = Teuchos::rcp( new StatusTestCombo<double,MV,OP>(Belos::StatusTestCombo<double,MV,OP>::OR, *test1, *test2) );
00268 test4 = Teuchos::rcp( new StatusTestResNorm<double,MV,OP>( tol ) );
00269 test4->DefineResForm( Belos::StatusTestResNorm<double,MV,OP>::Explicit, Belos::TwoNorm );
00270 pTest = Teuchos::rcp( new StatusTestCombo<double,MV,OP>(Belos::StatusTestCombo<double,MV,OP>::OR, *test3, *test4) );
00271
00272 int pid = pComm->MyPID();
00273
00274 if (print)
00275 pOM = Teuchos::rcp( new OutputManager<double>(pid, 2, 0) );
00276 else
00277 pOM = Teuchos::rcp( new OutputManager<double>(pid) );
00278
00279 pList = Teuchos::rcp( new Teuchos::ParameterList );
00280 pList->set( "Length", restart );
00281
00282 pBelos = Teuchos::rcp( new BlockGmres<double,MV,OP>(pProb, pTest, pOM, pList) );
00283 }
00284
00285 vector<double> & Iterative_Inverse_Operator::operator () (const vector<double> &b)
00286 {
00287 for (unsigned int i=0; i < b.size(); ++i) {
00288 pPB->ReplaceMyValue(i, 0, b[i]);
00289 }
00290 pPX->PutScalar( 0.0 );
00291
00292
00293 pBelos->Reset();
00294 pProb->Reset(pPX,pPB);
00295 pTest->Reset();
00296
00297 timer.start();
00298 pBelos->Solve();
00299 timer.stop();
00300
00301 int pid = pComm->MyPID();
00302
00303 if (pid == 0 && print)
00304 if (pTest->GetStatus() == Belos::Converged)
00305 {
00306 cout << endl << "pid[" << pid << "] Block GMRES converged in "
00307 << pBelos->GetNumIters() << " iteration(s)" << endl;
00308 cout << "Solution time: " << timer.totalElapsedTime() << endl;
00309
00310 }
00311 else
00312 cout << endl << "pid[" << pid << "] Block GMRES did not converge" << endl;
00313
00314 pPX->ExtractCopy(&y[0], pPX->Stride());
00315
00316 return y;
00317 }
00318
00319
00320
00321
00322 int main(int argc, char *argv[])
00323 {
00324
00325 int pid = -1;
00326
00327 #ifdef EPETRA_MPI
00328 MPI_Init(&argc, &argv);
00329 MPI_Comm_rank(MPI_COMM_WORLD, &pid);
00330 #else
00331 pid = 0;
00332 #endif
00333
00334 unsigned int n(10);
00335
00336 vector<double> x(n, 1.0);
00337
00338
00339 Teuchos::RefCountPtr<Diagonal_Operator_2> D2 = Teuchos::rcp(new Diagonal_Operator_2(n, 1.0));
00340 Iterative_Inverse_Operator A2(n, D2, "Belos (inv(D2))", true);
00341
00342
00343 x = A2(x);
00344
00345 if (pid==0) {
00346 std::cout << "Vector x should have all entries [1, 1/2, 1/3, ..., 1/10]" << std::endl;
00347 for (unsigned int i = 0; i < n; ++i)
00348 std::cout << "x[" << i << "]=" << x[i] << std::endl;
00349 std::cout << std::endl;
00350 }
00351
00352
00353 Teuchos::RefCountPtr<Diagonal_Operator> D = Teuchos::rcp(new Diagonal_Operator(n, 4.0));
00354 Teuchos::RefCountPtr<Iterative_Inverse_Operator> Inner =
00355 Teuchos::rcp(new Iterative_Inverse_Operator(n, D, "Belos (inv(D))", false));
00356
00357
00358 Teuchos::RefCountPtr<Diagonal_Operator> B = Teuchos::rcp(new Diagonal_Operator(n, 4.0));
00359 Teuchos::RefCountPtr<Composed_Operator> C = Teuchos::rcp(new Composed_Operator(n, Inner, B));
00360
00361
00362 Teuchos::RefCountPtr<Iterative_Inverse_Operator> Outer =
00363 Teuchos::rcp(new Iterative_Inverse_Operator(n, C, "Belos (inv(C)=inv(inv(D)*B)", true));
00364
00365
00366 vector<double> y(n, 1.0);
00367 y = (*Inner)(y);
00368
00369 if (pid==0) {
00370 std::cout << "Vector y should have all entries [1/4, 1/4, 1/4, ..., 1/4]" << std::endl;
00371 for (unsigned int i = 0; i < n; ++i)
00372 std::cout << "y[" << i << "]=" << y[i] << std::endl;
00373 std::cout << std::endl;
00374 }
00375
00376
00377 vector<double> z(n, 1.0);
00378 z = (*Outer)(z);
00379
00380 if (pid==0) {
00381 std::cout << "Vector z should have all entries [1, 1, 1, ..., 1]" << std::endl;
00382 for (unsigned int i = 0; i < n; ++i)
00383 std::cout << "z[" << i << "]=" << z[i] << std::endl;
00384 }
00385
00386 double norm_z, sum_z = 0.0;
00387 for (unsigned int i = 0; i < n; ++i)
00388 sum_z += Teuchos::ScalarTraits<double>::magnitude(z[i] - 1.0)*Teuchos::ScalarTraits<double>::magnitude(z[i] - 1.0);
00389 norm_z = Teuchos::ScalarTraits<double>::squareroot( sum_z );
00390 if (pid==0)
00391 std::cout << "Two-norm of vector (z-1.0) : "<< norm_z << std::endl;
00392
00393 #ifdef EPETRA_MPI
00394 MPI_Finalize();
00395 #endif
00396
00397 if (norm_z > 1e-10 || Teuchos::ScalarTraits<double>::isnaninf( norm_z ) ) {
00398 if (pid==0)
00399 cout << "End Result: TEST FAILED" << endl;
00400 return -1;
00401 }
00402
00403
00404
00405
00406 if (pid==0)
00407 cout << "End Result: TEST PASSED" << endl;
00408 return 0;
00409 }