7 #include "imstkNewtonSolver.h" 8 #include "imstkConjugateGradient.h" 9 #include "imstkDirectLinearSolver.h" 10 #include "imstkLogger.h" 17 NewtonSolver<SparseMatrixd>::NewtonSolver() :
18 m_linearSolver(
std::make_shared<ConjugateGradient>()),
20 m_absoluteTolerance(1e-3),
21 m_relativeTolerance(1e-6),
30 NewtonSolver<Matrixd>::NewtonSolver() :
31 m_linearSolver(
std::make_shared<DirectLinearSolver<
Matrixd>>()),
33 m_absoluteTolerance(1e-3),
34 m_relativeTolerance(1e-6),
42 template<
typename SystemMatrix>
46 if (!this->m_nonLinearSystem)
48 LOG(WARNING) <<
"NewtonMethod::solve - nonlinear system is not set to the nonlinear solver";
53 double fnorm = this->m_nonLinearSystem->evaluateF(x, this->m_isSemiImplicit).norm();
54 double stopTolerance = m_absoluteTolerance + m_relativeTolerance * fnorm;
56 m_linearSolver->setTolerance(stopTolerance);
60 const int maxIters = this->m_isSemiImplicit ? 1 :
static_cast<int>(m_maxIterations);
62 for (
int i = 0; i < maxIters; ++i)
64 if (fnorm < stopTolerance)
68 this->updateJacobian(x);
70 m_linearSolver->solve(dx);
71 this->m_updateIterate(-dx, x);
73 double newNorm = this->armijo(dx, x, fnorm);
75 if (m_forcingTerm > 0.0 && newNorm > stopTolerance)
77 double ratio = newNorm / fnorm;
78 this->updateForcingTerm(ratio, stopTolerance, fnorm);
82 m_linearSolver->setTolerance(m_forcingTerm);
89 template<
typename SystemMatrix>
93 if (!this->m_nonLinearSystem)
95 LOG(WARNING) <<
"NewtonMethod::solve - nonlinear system is not set to the nonlinear solver";
100 const auto& u = this->m_nonLinearSystem->getUnknownVector();
102 double error0 = MAX_D;
104 double epsilon = m_relativeTolerance * m_relativeTolerance;
105 for (iterNum = 0; iterNum < m_maxIterations; ++iterNum)
107 double error = updateJacobian(u);
115 if (error / error0 < epsilon && iterNum > 0)
121 m_linearSolver->solve(du);
122 this->m_nonLinearSystem->m_FUpdate(du, this->m_isSemiImplicit);
125 this->m_nonLinearSystem->m_FUpdatePrevState();
127 if (iterNum == m_maxIterations && !this->m_isSemiImplicit)
129 LOG(WARNING) <<
"NewtonMethod::solve - The solver did not converge after max. iterations";
133 template<
typename SystemMatrix>
138 if (!this->m_nonLinearSystem)
140 LOG(WARNING) <<
"NewtonMethod::updateJacobian - nonlinear system is not set to the nonlinear solver";
153 const auto& vecAndMat = this->m_nonLinearSystem->m_F_dF(x, this->m_isSemiImplicit);
154 auto& b = *vecAndMat.first;
155 auto& A = *vecAndMat.second;
156 if (A.innerSize() == 0)
158 LOG(WARNING) <<
"NewtonMethod::updateJacobian - Size of matrix is 0!";
162 auto linearSystem = std::make_shared<typename LinearSolverType::LinearSystemType>(A, b);
164 m_linearSolver->setSystem(linearSystem);
166 return std::sqrt(b.dot(b));
169 template<
typename SystemMatrix>
173 double eta = m_gamma * ratio * ratio;
174 double forcingTermSqr = m_forcingTerm * m_forcingTerm;
177 if (m_gamma * forcingTermSqr > 0.1)
180 eta = std::max(eta, m_gamma * forcingTermSqr);
183 m_forcingTerm = std::max(std::min(eta, m_etaMax), 0.5 * stopTolerance / fnorm);
186 template<
typename SystemMatrix>
191 return m_linearSolver;
194 template<
typename SystemMatrix>
198 m_absoluteTolerance = aTolerance;
201 template<
typename SystemMatrix>
205 return m_absoluteTolerance;
auto getLinearSolver() const -> std::shared_ptr< LinearSolverType >
Get LinearSolver.
void solveGivenState(Vectord &x) override
Solve the non linear system of equations G(x)=0 using Newton's method.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > Matrixd
A dynamic size matrix of doubles.
void setAbsoluteTolerance(const double aTolerance)
Get JacobianMatrix. Returns jacobian matrix.
void updateForcingTerm(const double ratio, const double stopTolerance, const double fnorm)
Update forcing term according to Eisenstat-Walker criteria.
double updateJacobian(const Vectord &x)
Update jacobians.
Base class for linear solvers.
double getAbsoluteTolerance() const
Get AbsoluteTolerance. Returns current tolerance value.
Newton method. This version of the newton method is based on the work by Tim Kelly and others at NC S...