iMSTK
Interactive Medical Simulation Toolkit
imstkNonLinearSolver.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkNonLinearSolver.h"
8 
9 namespace imstk
10 {
11 template<typename SystemMatrix>
12 NonLinearSolver<SystemMatrix>::NonLinearSolver() : m_sigma(std::array<double, 2>
13  {
14  { 0.1, 0.5 }
15  }),
16  m_alpha(1e-4),
17  m_armijoMax(30)
18 {
19  m_updateIterate = [](const Vectord& dx, Vectord& x)
20  {
21  x += dx;
22  };
23 }
24 
25 template<typename SystemMatrix>
26 double
27 NonLinearSolver<SystemMatrix>::armijo(const Vectord& dx, Vectord& x, const double previousFnorm)
28 {
30  std::array<double, 3> fnormSqr = { previousFnorm* previousFnorm, 0.0, 0.0 };
31  std::array<double, 3> lambda = { m_sigma[0] * m_sigma[1], 1.0, 1.0 };
32 
34  if (!m_nonLinearSystem)
35  {
37  return previousFnorm;
38  }
39 
40  double currentFnorm = m_nonLinearSystem->m_F(x, !m_isSemiImplicit).norm();
41 
42  // Exit if the function norm satisfies the Armijo-Goldstein condition
43  if (currentFnorm < (1.0 - m_alpha * lambda[0]) * previousFnorm)
44  {
46  return currentFnorm;
47  }
48 
49  // Save iterate in case this fails
50  //auto x_old = x;
51 
52  // Starts Armijo line search loop
53  size_t i;
54  for (i = 0; i < m_armijoMax; ++i)
55  {
57  m_updateIterate(-lambda[0] * dx, x);
58  lambda[2] = lambda[1];
59  lambda[1] = lambda[0];
60 
61  currentFnorm = m_nonLinearSystem->m_F(x, !m_isSemiImplicit).norm();
62 
63  // Exit if the function norm satisfies the Armijo-Goldstein condition
64  if (currentFnorm < (1.0 - m_alpha * lambda[0]) * previousFnorm)
65  {
67  return currentFnorm;
68  }
69 
71  fnormSqr[2] = fnormSqr[1];
72  fnormSqr[1] = currentFnorm * currentFnorm;
73 
75  this->parabolicModel(fnormSqr, lambda);
76  }
77 
78  if (i == m_armijoMax)
79  {
81 // std::cout << "Maximum number of Armijo iterations reached." << std::endl;
82  }
83  return currentFnorm;
84 }
85 
86 template<typename SystemMatrix>
87 void
88 NonLinearSolver<SystemMatrix>::parabolicModel(const std::array<double, 3>& fnorm, std::array<double, 3>& lambda)
89 {
95  double a1 = lambda[2] * (fnorm[1] - fnorm[0]);
96  double a2 = lambda[1] * (fnorm[2] - fnorm[0]);
97  double a = a1 - a2;
98 
99  if (a >= 0)
100  {
101  lambda[0] = m_sigma[0] * lambda[1];
102  return;
103  }
104 
105  double b = lambda[1] * a2 - lambda[2] * a1;
106  double newLambda = -.5 * b / a;
107 
108  if (newLambda < m_sigma[0] * lambda[1])
109  {
110  newLambda = m_sigma[0] * lambda[1];
111  }
112 
113  if (newLambda > m_sigma[1] * lambda[1])
114  {
115  newLambda = m_sigma[1] * lambda[1];
116  }
117 
118  lambda[0] = newLambda;
119 }
120 
121 template<typename SystemMatrix>
122 void
123 NonLinearSolver<SystemMatrix>::setSigma(const std::array<double, 2>& newSigma)
124 {
125  m_sigma = newSigma;
126 }
127 
128 template<typename SystemMatrix>
129 const std::array<double, 2>&
131 {
132  return m_sigma;
133 }
134 
135 template<typename SystemMatrix>
136 void
138 {
139  m_alpha = newAlpha;
140 }
141 
142 template<typename SystemMatrix>
143 double
145 {
146  return m_alpha;
147 }
148 
149 template<typename SystemMatrix>
150 void
152 {
153  m_armijoMax = newArmijoMax;
154 }
155 
156 template<typename SystemMatrix>
157 size_t
159 {
160  return m_armijoMax;
161 }
162 
163 template<typename SystemMatrix>
164 void
166 {
167  m_nonLinearSystem = newSystem;
168 }
169 
170 template<typename SystemMatrix>
171 std::shared_ptr<NonLinearSystem<SystemMatrix>>
173 {
174  return m_nonLinearSystem;
175 }
176 
177 template class NonLinearSolver<SparseMatrixd>;
178 template class NonLinearSolver<Matrixd>;
179 } // namespace imstk
UpdateIterateType m_updateIterate
Update iteration function.
bool m_isSemiImplicit
Semi-Implicit solver.
size_t m_armijoMax
Maximum number of step length reductions.
void setAlpha(const double newAlpha)
Set/Get Alpha. Parameter to measure sufficient decrease in the line search.
Compound Geometry.
void parabolicModel(const std::array< double, 3 > &fnorm, std::array< double, 3 > &lambda)
Three-point safeguarded parabolic model for a line search. Upon return lambda[0] will contain the new...
double m_alpha
Parameter to measure decrease.
Base class for a multi-variable nonlinear system.
void setSigma(const std::array< double, 2 > &newSigma)
Set/Get Sigma. Safeguard parameter for the the line search method.
double armijo(const Vectord &dx, Vectord &x, const double previousFnorm)
Backtracking line search method based on the Armijo-Goldstein condition.
void setSystem(std::shared_ptr< NonLinearSystem< SystemMatrix >> newSystem)
Sets the system. System of nonlinear equations.
std::array< double, 2 > m_sigma
Safeguarding bounds for the line search.
Base class for non-linear solvers.
void setArmijoMax(const size_t newArmijoMax)
Set/Get ArmijoMax. Maximum number of step length reductions.
std::shared_ptr< NonLinearSystem< SystemMatrix > > m_nonLinearSystem
System of non-linear equations.