Skip to content
Snippets Groups Projects
Commit fb3af037 authored by Marian Piatkowski's avatar Marian Piatkowski Committed by Steffen Müthing
Browse files

fixed MinRes with the following changes:

replaced the usual arrays for the Givens-rotation coefficients and the search directions etc. with the arrays from Dune

implemented the BLAS-routine drotg for greater robustness which was a TODO note to compute the Givens rotation
parent 1f4cd6b4
No related branches found
No related tags found
No related merge requests found
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <dune/common/ftraits.hh> #include <dune/common/ftraits.hh>
#include <dune/common/shared_ptr.hh> #include <dune/common/shared_ptr.hh>
#include <dune/common/static_assert.hh> #include <dune/common/static_assert.hh>
#include <dune/common/array.hh>
namespace Dune { namespace Dune {
/** @defgroup ISTL_Solvers Iterative Solvers /** @defgroup ISTL_Solvers Iterative Solvers
...@@ -840,127 +841,126 @@ namespace Dune { ...@@ -840,127 +841,126 @@ namespace Dune {
*/ */
virtual void apply (X& x, X& b, InverseOperatorResult& res) virtual void apply (X& x, X& b, InverseOperatorResult& res)
{ {
res.clear(); // clear solver statistics // clear solver statistics
Timer watch; // start a timer res.clear();
_prec.pre(x,b); // prepare preconditioner // start a timer
_op.applyscaleadd(-1,x,b); // overwrite b with defect/residual Dune::Timer watch;
watch.reset();
real_type def0 = _sp.norm(b); // compute residual norm // prepare preconditioner
_prec.pre(x,b);
// overwrite rhs with defect
_op.applyscaleadd(-1,x,b);
if (def0<1E-30) // convergence check // compute residual norm
{ field_type def0 = _sp.norm(b);
res.converged = true;
res.iterations = 0; // fill statistics
res.reduction = 0;
res.conv_rate = 0;
res.elapsed=0;
if (_verbose>0) // final print
std::cout << "=== rate=" << res.conv_rate << ", T=" << res.elapsed << ", TIT=" << res.elapsed << ", IT=0" << std::endl;
return;
}
if (_verbose>0) // printing // printing
{ if(_verbose > 0) {
std::cout << "=== MINRESSolver" << std::endl; std::cout << "=== MINRESSolver" << std::endl;
if (_verbose>1) { if(_verbose > 1) {
this->printHeader(std::cout); this->printHeader(std::cout);
this->printOutput(std::cout,0,def0); this->printOutput(std::cout,0,def0);
} }
} }
// some local variables // check for convergence
real_type def=def0; // the defect/residual norm if(def0 < 1e-30 ) {
field_type alpha, // recurrence coefficients as computed in the Lanczos alg making up the matrix T res.converged = true;
c[2]={0.0, 0.0}, // diagonal entry of Givens rotation res.iterations = 0;
s[2]={0.0, 0.0}; // off-diagonal entries of Givens rotation res.reduction = 0;
real_type beta; res.conv_rate = 0;
res.elapsed = 0.0;
// final print
if(_verbose > 0)
std::cout << "=== rate=" << res.conv_rate
<< ", T=" << res.elapsed
<< ", TIT=" << res.elapsed
<< ", IT=" << res.iterations
<< std::endl;
return;
}
field_type T[3]={0.0, 0.0, 0.0}; // recurrence coefficients (column k of Matrix T) // the defect norm
field_type def = def0;
// recurrence coefficients as computed in Lanczos algorithm
field_type alpha, beta;
// diagonal entries of givens rotation
Dune::array<field_type,2> c = {0.0,0.0};
// off-diagonal entries of givens rotation
Dune::array<field_type,2> s = {0.0,0.0};
X z(b.size()), // some temporary vectors // recurrence coefficients (column k of tridiag matrix T_k)
dummy(b.size()); Dune::array<field_type,3> T = {0.0,0.0,0.0};
field_type xi[2]={1.0, 0.0}; // the rhs vector of the min problem
Dune::array<field_type,2> xi = {1.0,0.0};
// initialize // some temporary vectors
z = 0.0; // clear correction X z(b), dummy(b);
_prec.apply(z,b); // apply preconditioner z=M^-1*b // initialize and clear correction
z = 0.0;
_prec.apply(z,b);
beta = std::sqrt(std::abs(_sp.dot(z,b))); beta = std::sqrt(std::abs(_sp.dot(z,b)));
real_type beta0 = beta; field_type beta0 = beta;
X p[3]; // the search directions
X q[3]; // Orthonormal basis vectors (in unpreconditioned case)
q[0].resize(b.size());
q[1].resize(b.size());
q[2].resize(b.size());
q[0] = 0.0;
q[1] = b;
q[1] /= beta;
q[2] = 0.0;
p[0].resize(b.size()); // the search directions
p[1].resize(b.size()); Dune::array<X,3> p = {b,b,b};
p[2].resize(b.size());
p[0] = 0.0; p[0] = 0.0;
p[1] = 0.0; p[1] = 0.0;
p[2] = 0.0; p[2] = 0.0;
// orthonormal basis vectors (in unpreconditioned case)
Dune::array<X,3> q = {b,b,b};
q[0] = 0.0;
q[1] *= 1.0/beta;
q[2] = 0.0;
z /= beta; // this is w_current z *= 1.0/beta;
// the loop // the loop
int i=1; int i = 1;
for ( ; i<=_maxit; i++) for( ; i<=_maxit; i++) {
{
dummy = z; // remember z_old for the computation of the search direction p in the next iteration
dummy = z;
int i1 = i%3, int i1 = i%3,
i0 = (i1+2)%3, i0 = (i1+2)%3,
i2 = (i1+1)%3; i2 = (i1+1)%3;
// Symmetrically Preconditioned Lanczos (Greenbaum p.121) // symmetrically preconditioned Lanczos algorithm (see Greenbaum p.121)
_op.apply(z,q[i2]); // q[i2] = Az _op.apply(z,q[i2]); // q[i2] = Az
q[i2].axpy(-beta, q[i0]); q[i2].axpy(-beta,q[i0]);
alpha = _sp.dot(q[i2],z); alpha = _sp.dot(q[i2],z);
q[i2].axpy(-alpha, q[i1]); q[i2].axpy(-alpha,q[i1]);
z=0.0; z = 0.0;
_prec.apply(z,q[i2]); _prec.apply(z,q[i2]);
beta = std::sqrt(std::abs(_sp.dot(q[i2],z))); beta = std::sqrt(std::abs(_sp.dot(q[i2],z)));
q[i2] /= beta; q[i2] *= 1.0/beta;
z /= beta; z *= 1.0/beta;
// QR Factorization of recurrence coefficient matrix // QR Factorization of recurrence coefficient matrix
// apply previous Givens rotations to last column of T // apply previous givens rotations to last column of T
T[1] = T[2]; T[1] = T[2];
if (i>2) if(i>2) {
{
T[0] = s[i%2]*T[1]; T[0] = s[i%2]*T[1];
T[1] = c[i%2]*T[1]; T[1] = c[i%2]*T[1];
} }
if (i>1) if(i>1) {
{
T[2] = c[(i+1)%2]*alpha - s[(i+1)%2]*T[1]; T[2] = c[(i+1)%2]*alpha - s[(i+1)%2]*T[1];
T[1] = c[(i+1)%2]*T[1] + s[(i+1)%2]*alpha; T[1] = c[(i+1)%2]*T[1] + s[(i+1)%2]*alpha;
} }
else else
T[2] = alpha; T[2] = alpha;
// recompute c, s -> current Givens rotation \TODO use BLAS-routine drotg instead for greater robustness // update QR factorization
// cblas_drotg (a, b, c, s); generateGivensRotation(T[2],beta,c[i%2],s[i%2]);
c[i%2] = 1.0/std::sqrt(T[2]*T[2] + beta*beta); // to last column of T_k
s[i%2] = beta*c[i%2];
c[i%2] *= T[2];
// apply current Givens rotation to T eliminating the last entry...
T[2] = c[i%2]*T[2] + s[i%2]*beta; T[2] = c[i%2]*T[2] + s[i%2]*beta;
// and to the rhs xi of the min problem
// ...and to xi, the right hand side of the least squares problem min_y||beta*xi-T*y||
xi[i%2] = -s[i%2]*xi[(i+1)%2]; xi[i%2] = -s[i%2]*xi[(i+1)%2];
xi[(i+1)%2] *= c[i%2]; xi[(i+1)%2] *= c[i%2];
...@@ -968,53 +968,46 @@ namespace Dune { ...@@ -968,53 +968,46 @@ namespace Dune {
p[i2] = dummy; p[i2] = dummy;
p[i2].axpy(-T[1],p[i1]); p[i2].axpy(-T[1],p[i1]);
p[i2].axpy(-T[0],p[i0]); p[i2].axpy(-T[0],p[i0]);
p[i2] /= T[2]; p[i2] *= 1.0/T[2];
// apply correction/update solution // apply correction/update solution
x.axpy(beta0*xi[(i+1)%2], p[i2]); x.axpy(beta0*xi[(i+1)%2],p[i2]);
// remember beta_old // remember beta_old
T[2] = beta; T[2] = beta;
// update residual - not necessary if in the preconditioned case we are content with the residual norm of the // check for convergence
// preconditioned system as convergence test // the last entry in the rhs of the min-problem is the residual
// _op.apply(p[i2],dummy); field_type defnew = std::abs(beta0*xi[i%2]);
// b.axpy(-beta0*xi[(i+1)%2],dummy);
// convergence test
real_type defnew = std::abs(beta0*xi[i%2]); // the last entry the QR-transformed least squares RHS is the new residual norm
if (_verbose>1) // print
this->printOutput(std::cout,i,defnew,def);
def = defnew; // update norm
if (def<def0*_reduction || def<1E-30 || i==_maxit) // convergence check
{
res.converged = true;
break;
}
}
//correct i which is wrong if convergence was not achieved. if(_verbose > 1)
i=std::min(_maxit,i); this->printOutput(std::cout,i,defnew,def);
if (_verbose==1) // printing for non verbose def = defnew;
this->printOutput(std::cout,i,def); if(def < def0*_reduction || def < 1e-30 || i == _maxit ) {
res.converged = true;
break;
}
} // end for
_prec.post(x); // postprocess preconditioner if(_verbose == 1)
res.iterations = i; // fill statistics this->printOutput(std::cout,i,def);
res.reduction = def/def0;
res.conv_rate = pow(res.reduction,1.0/i);
res.elapsed = watch.elapsed();
if (_verbose>0) // final print // postprocess preconditioner
{ _prec.post(x);
std::cout << "=== rate=" << res.conv_rate // fill statistics
<< ", T=" << res.elapsed res.iterations = i;
<< ", TIT=" << res.elapsed/i res.reduction = def/def0;
<< ", IT=" << i << std::endl; res.conv_rate = pow(res.reduction,1.0/i);
} res.elapsed = watch.elapsed();
// final print
if(_verbose > 0) {
std::cout << "=== rate=" << res.conv_rate
<< ", T=" << res.elapsed
<< ", TIT=" << res.elapsed/i
<< ", IT=" << i << std::endl;
}
} }
/*! /*!
...@@ -1030,6 +1023,25 @@ namespace Dune { ...@@ -1030,6 +1023,25 @@ namespace Dune {
} }
private: private:
void generateGivensRotation(field_type& dx, field_type& dy, field_type& cs, field_type& sn)
{
field_type temp = std::abs(dy);
if(temp < 1e-16) {
cs = 1.0;
sn = 0.0;
}
else if(temp > std::abs(dx)) {
temp = dx/dy;
sn = 1.0/std::sqrt(1.0 + temp*temp);
cs = temp * sn;
} else {
temp = dy/dx;
cs = 1.0/std::sqrt(1.0 + temp*temp);
sn = temp * cs;
}
}
SeqScalarProduct<X> ssp; SeqScalarProduct<X> ssp;
LinearOperator<X,X>& _op; LinearOperator<X,X>& _op;
Preconditioner<X,X>& _prec; Preconditioner<X,X>& _prec;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment