#include "Didasko_ConfigDefs.h"
#if defined(HAVE_DIDASKO_EPETRA) && defined(HAVE_DIDASKO_NOX)
#include "Epetra_ConfigDefs.h"
#ifdef HAVE_MPI
#include "mpi.h"
#include "Epetra_MpiComm.h"
#else
#include "Epetra_SerialComm.h"
#endif
#include "Epetra_Map.h"
#include "Epetra_Vector.h"
#include "Epetra_RowMatrix.h"
#include "Epetra_CrsMatrix.h"
#include "NOX.H"
#include "NOX_Epetra_Interface.H"
#include "NOX_Epetra_Group.H"
static void get_neighbours( const int i, const int nx, const int ny,
int & left, int & right,
int & lower, int & upper)
{
int ix, iy;
ix = i%nx;
iy = (i - ix)/nx;
if( ix == 0 )
left = -1;
else
left = i-1;
if( ix == nx-1 )
right = -1;
else
right = i+1;
if( iy == 0 )
lower = -1;
else
lower = i-nx;
if( iy == ny-1 )
upper = -1;
else
upper = i+nx;
return;
}
Epetra_CrsMatrix * CreateLaplacian( const int nx, const int ny,
const Epetra_Comm * Comm)
{
int NumGlobalElements = nx * ny;
Epetra_Map * Map = new Epetra_Map(NumGlobalElements,0,*Comm);
int NumMyElements = Map->NumMyElements();
int * MyGlobalElements = Map->MyGlobalElements();
double hx = 1.0/(nx-1);
double hy = 1.0/(ny-1);
double off_left = -1.0/(hx*hx);
double off_right = -1.0/(hx*hx);
double off_lower = -1.0/(hy*hy);
double off_upper = -1.0/(hy*hy);
double diag = 2.0/(hx*hx) + 2.0/(hy*hy);
int left, right, lower, upper;
Epetra_CrsMatrix * A = new Epetra_CrsMatrix(Copy,*Map,5);
double *Values = new double[4];
int *Indices = new int[4];
for( int i=0 ; i<NumMyElements; ++i ) {
int NumEntries=0;
get_neighbours( MyGlobalElements[i], nx, ny,
left, right, lower, upper);
if( left != -1 ) {
Indices[NumEntries] = left;
Values[NumEntries] = off_left;
++NumEntries;
}
if( right != -1 ) {
Indices[NumEntries] = right;
Values[NumEntries] = off_right;
++NumEntries;
}
if( lower != -1 ) {
Indices[NumEntries] = lower;
Values[NumEntries] = off_lower;
++NumEntries;
}
if( upper != -1 ) {
Indices[NumEntries] = upper;
Values[NumEntries] = off_upper;
++NumEntries;
}
A->InsertGlobalValues(MyGlobalElements[i], NumEntries, Values, Indices);
A->InsertGlobalValues(MyGlobalElements[i], 1, &diag, MyGlobalElements+i);
}
A->FillComplete();
return A;
}
class PDEProblem {
public:
PDEProblem(const int nx, const int ny, const double lambda,
const Epetra_Comm * Comm) :
nx_(nx), ny_(ny), lambda_(lambda)
{
hx_ = 1.0/(nx_-1);
hy_ = 1.0/(ny_-1);
Matrix_ = CreateLaplacian(nx_,ny_,Comm);
}
~PDEProblem()
{
delete Matrix_;
}
void ComputeF(const Epetra_Vector & x, Epetra_Vector & f)
{
double diag = 2.0/(hx_*hx_) + 2.0/(hy_*hy_);
int NumMyElements = Matrix_->Map().NumMyElements();
int * MyGlobalElements = Matrix_->Map().MyGlobalElements( );
for( int i=0 ; i<NumMyElements; ++i ) {
Matrix_->ReplaceGlobalValues(MyGlobalElements[i], 1, &diag, MyGlobalElements+i);
}
Matrix_->Multiply(false,x,f);
for( int i=0 ; i<NumMyElements; ++i ) {
f[i] += lambda_*exp(x[i]);
}
}
void UpdateJacobian(const Epetra_Vector & x)
{
double diag = 2.0/(hx_*hx_) + 2.0/(hy_*hy_);
int NumMyElements = Matrix_->Map().NumMyElements();
int * MyGlobalElements = Matrix_->Map().MyGlobalElements( );
for( int i=0 ; i<NumMyElements; ++i ) {
double newdiag = diag + lambda_*x[i];
Matrix_->ReplaceGlobalValues(MyGlobalElements[i], 1,
&newdiag, MyGlobalElements+i);
}
}
Epetra_CrsMatrix * GetMatrix()
{
return Matrix_;
}
private:
int nx_, ny_;
double hx_, hy_;
Epetra_CrsMatrix * Matrix_;
double lambda_;
};
class SimpleProblemInterface : public NOX::Epetra::Interface {
public:
SimpleProblemInterface( PDEProblem * Problem ) :
Problem_(Problem) {};
~SimpleProblemInterface()
{
};
bool computeF(const Epetra_Vector & x, Epetra_Vector & f,
NOX::Epetra::Interface::FillType F )
{
Problem_->ComputeF(x,f);
return true;
};
bool computeJacobian(const Epetra_Vector & x, Epetra_Operator & Jac)
{
Problem_->UpdateJacobian(x);
return true;
}
bool computePrecMatrix(const Epetra_Vector & x, Epetra_RowMatrix & M)
{
cout << "*ERR* SimpleProblem::preconditionVector()\n";
cout << "*ERR* don't use explicit preconditioning" << endl;
throw 1;
}
bool computePreconditioner(const Epetra_Vector & x, Epetra_Operator & O)
{
cout << "*ERR* SimpleProblem::preconditionVector()\n";
cout << "*ERR* don't use explicit preconditioning" << endl;
throw 1;
}
private:
PDEProblem * Problem_;
};
int main( int argc, char **argv )
{
#ifdef HAVE_MPI
MPI_Init(&argc, &argv);
Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
Epetra_SerialComm Comm;
#endif
int nx = 5;
int ny = 6;
double lambda = 1.0;
PDEProblem Problem(nx,ny,lambda,&Comm);
Epetra_Vector InitialGuess(Problem.GetMatrix()->Map());
InitialGuess.PutScalar(0.0);
SimpleProblemInterface Interface(&Problem);
NOX::Parameter::List nlParams;
nlParams.setParameter("Nonlinear Solver", "Line Search Based");
NOX::Parameter::List& printParams = nlParams.sublist("Printing");
printParams.setParameter("MyPID", Comm.MyPID());
printParams.setParameter("Output Precision", 3);
printParams.setParameter("Output Processor", 0);
printParams.setParameter("Output Information",
NOX::Utils::OuterIteration +
NOX::Utils::OuterIterationStatusTest +
NOX::Utils::InnerIteration +
NOX::Utils::Parameters +
NOX::Utils::Details +
NOX::Utils::Warning);
NOX::Parameter::List& searchParams = nlParams.sublist("Line Search");
searchParams.setParameter("Method", "Full Step");
NOX::Parameter::List& dirParams = nlParams.sublist("Direction");
dirParams.setParameter("Method", "Newton");
NOX::Parameter::List& newtonParams = dirParams.sublist("Newton");
newtonParams.setParameter("Forcing Term Method", "Constant");
NOX::Parameter::List& lsParams = newtonParams.sublist("Linear Solver");
lsParams.setParameter("Aztec Solver", "GMRES");
lsParams.setParameter("Max Iterations", 800);
lsParams.setParameter("Tolerance", 1e-4);
lsParams.setParameter("Output Frequency", 50);
lsParams.setParameter("Aztec Preconditioner", "ilu");
NOX::Epetra::Group grp(printParams, lsParams, Interface, InitialGuess,
dynamic_cast<Epetra_RowMatrix&>(*(Problem.GetMatrix())));
NOX::StatusTest::NormF statusTestA(grp, 1.0e-4);
NOX::StatusTest::MaxIters statusTestB(20);
NOX::StatusTest::Combo statusTestsCombo(NOX::StatusTest::Combo::OR, statusTestA, statusTestB);
NOX::Parameter::List solverParameters;
solverParameters.sublist("Printing").setParameter("Output Information",
NOX::Utils::OuterIteration);
solverParameters.setParameter("Nonlinear Solver", "Line Search Based");
NOX::Parameter::List& lineSearchParameters = solverParameters.sublist("Line Search");
lineSearchParameters.setParameter("Method","More'-Thuente");
NOX::Solver::Manager solver(grp, statusTestsCombo, solverParameters);
NOX::StatusTest::StatusType status = solver.solve();
cout << "\n" << "-- Parameter List From Solver --" << "\n";
solver.getParameterList().print(cout);
const NOX::Epetra::Group & finalGroup =
dynamic_cast<const NOX::Epetra::Group&>(solver.getSolutionGroup());
const Epetra_Vector & finalSolution =
(dynamic_cast<const NOX::Epetra::Vector&>(finalGroup.getX())).getEpetraVector();
if( Comm.MyPID() == 0 ) cout << "Computed solution : " << endl;
cout << finalSolution;
#ifdef HAVE_MPI
MPI_Finalize();
#endif
return(EXIT_SUCCESS);
}
#else
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_MPI
#include "mpi.h"
#endif
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
MPI_Init(&argc,&argv);
#endif
puts("Please configure Didasko with:");
puts("--enable-epetra");
puts("--enable-nox\n");
#ifdef HAVE_MPI
MPI_Finalize();
#endif
return(EXIT_SUCCESS);
}
#endif