// ATC headers #include "NonLinearSolver.h" #include "LinearSolver.h" #include "ATC_Error.h" #include "LammpsInterface.h" using std::stringstream; namespace ATC { //=================================================================== // TangentOperator //=================================================================== //=================================================================== // NonLinearSolver //=================================================================== NonLinearSolver::NonLinearSolver(TangentOperator * f, const BC_SET * bcs, const int dof, bool parallel): f_(f), bcs_(bcs), dof_(dof), rNorm0P_(1.0), tol_(1.e-10), tolx_(1.e-8), tol0_(1.e-6), maxIterations_(20), parallel_(parallel) { } //-------------------------------------------------------------------- double NonLinearSolver::residual_norm(VECTOR & r) { if (bcs_) { DENS_VEC R = r; BC_SET::const_iterator itr; for (itr = bcs_->begin(); itr != bcs_->end(); itr++) { int i = itr->first; R(i) = 0; } return R.norm(); } else { return r.norm(); } } //-------------------------------------------------------------------- bool NonLinearSolver::solve(VECTOR & x) { f_->function(x, r_); rNorm0_ = residual_norm(r_); if (rNorm0_ < tol_*rNorm0P_) { // if a "solution" does pass here rNorm0_ will be too small to allow for convergence return true; // note abs vs rel tol } if (rNorm0_ == 0.0) rNorm0_ = 1.0; if (rNorm0_ < tol0_ ) rNorm0_ = rNorm0P_; if (rNorm0P_ == 1.0) rNorm0P_ = rNorm0_; rNormP_ = rNorm0_; dx_.reset(r_.nRows()); // needs to be sized for linear solver // newton's method for (int iter = 0; iter < maxIterations_ ; iter++ ) { // compute tangent f_->tangent(x, r_, A_); rNorm_ = residual_norm(r_); rNorm_ /= rNorm0_; if (rNorm_ < tol_) { return true; } SPAR_MAT Asparse(A_); LinearSolver linearSolver(Asparse, LinearSolver::AUTO_SOLVE, parallel_); if (bcs_) { linearSolver.allow_reinitialization(); linearSolver.initialize(bcs_); if (iter > 0) linearSolver.set_homogeneous_bcs(); else { x.zero(); } // linear solve w/ bcs will replace guess } r_ *= -1; linearSolver.solve(dx_,r_); if (iter > 0 && rNorm_ > rNormP_) { bool descent = line_search(x); if (! descent ) { // return false; } } rNormP_ = rNorm_; x += dx_; } stringstream ss; ss << "WARNING NonLinearSolver: did not converge, iterations="<< maxIterations_ <<" error= " << rNorm_; ATC::LammpsInterface::instance()->print_msg_once(ss.str()); return false; } //-------------------------------------------------------------------- bool NonLinearSolver::line_search(VECTOR & x) { double rNormP = rNormP_; double dxnorm = dx_.norm(); while ( dxnorm > tolx_) { dx_ *= 0.5; // bisection dxnorm = dx_.norm(); f_->function(x+dx_,r_); rNorm_ = residual_norm(r_)/rNorm0_; if (rNorm_ < rNormP) return true; } return false; // no descent } } // end namespace ATC