iMSTK
Interactive Medical Simulation Toolkit
imstkConjugateGradient.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 "imstkConjugateGradient.h"
8 #include "imstkLinearProjectionConstraint.h"
9 #include "imstkLogger.h"
10 
11 namespace imstk
12 {
13 ConjugateGradient::ConjugateGradient()
14 {
15  m_type = Type::ConjugateGradient;
16  m_cgSolver.setMaxIterations(m_maxIterations);
17  m_cgSolver.setTolerance(m_tolerance);
18 }
19 
20 ConjugateGradient::ConjugateGradient(const SparseMatrixd& A, const Vectord& rhs) : ConjugateGradient()
21 {
22  this->setSystem(std::make_shared<LinearSystem<SparseMatrixd>>(A, rhs));
23 }
24 
25 void
26 ConjugateGradient::applyLinearProjectionFilter(Vectord& x, const std::vector<LinearProjectionConstraint>& linProj, const bool setVal)
27 {
28  for (auto& localProjector : linProj)
29  {
30  const auto threeI = 3 * localProjector.getNodeId();
31  Vec3d p = localProjector.getProjector() * Vec3d(x(threeI), x(threeI + 1), x(threeI + 2));
32 
33  if (setVal)
34  {
35  p += (Mat3d::Identity() - localProjector.getProjector()) * localProjector.getValue();
36  }
37 
38  x(threeI) = p.x();
39  x(threeI + 1) = p.y();
40  x(threeI + 2) = p.z();
41  }
42 }
43 
44 void
46 {
47  if (!m_linearSystem)
48  {
49  LOG(WARNING) << "Linear system is not supplied for CG solver!";
50  return;
51  }
52 
53  if (!(m_FixedLinearProjConstraints || m_DynamicLinearProjConstraints))
54  {
55  x = m_cgSolver.solve(m_linearSystem->getRHSVector());
56  }
57  else
58  {
59  this->modifiedCGSolve(x);
60  }
61 }
62 
63 void
64 ConjugateGradient::modifiedCGSolve(Vectord& x)
65 {
66  const auto& b = m_linearSystem->getRHSVector();
67  const auto& A = m_linearSystem->getMatrix();
68 
69  // Set the initial guess to zero
70  x.setZero();
71  if (m_DynamicLinearProjConstraints)
72  {
73  applyLinearProjectionFilter(x, *m_DynamicLinearProjConstraints, true);
74  }
75 
76  if (m_FixedLinearProjConstraints)
77  {
78  applyLinearProjectionFilter(x, *m_FixedLinearProjConstraints, true);
79  }
80 
81  auto res = b;
82  if (m_DynamicLinearProjConstraints)
83  {
84  applyLinearProjectionFilter(res, *m_DynamicLinearProjConstraints, false);
85  }
86  if (m_FixedLinearProjConstraints)
87  {
88  applyLinearProjectionFilter(res, *m_FixedLinearProjConstraints, false);
89  }
90  auto c = res;
91  auto delta = res.dot(res);
92  const auto eps = m_tolerance * m_tolerance * delta;
93  double alpha = 0.0;
94  Vectord q;
95  size_t iterNum = 0;
96 
97  while (delta > eps)
98  {
99  q = A * c;
100  if (m_DynamicLinearProjConstraints)
101  {
102  applyLinearProjectionFilter(q, *m_DynamicLinearProjConstraints, false);
103  }
104  if (m_FixedLinearProjConstraints)
105  {
106  applyLinearProjectionFilter(q, *m_FixedLinearProjConstraints, false);
107  }
108  double dotval = c.dot(q);
109  if (dotval != 0.0)
110  {
111  alpha = delta / dotval;
112  }
113  else
114  {
115  LOG(WARNING) << "Warning: denominator zero. Terminating MCG iteration!";
116  return;
117  }
118  x += alpha * c;
119  res -= alpha * q;
120  const double deltaPrev = delta;
121  delta = res.dot(res);
122  c *= delta / deltaPrev;
123  c += res;
124  if (m_DynamicLinearProjConstraints)
125  {
126  applyLinearProjectionFilter(c, *m_DynamicLinearProjConstraints, false);
127  }
128  if (m_FixedLinearProjConstraints)
129  {
130  applyLinearProjectionFilter(c, *m_FixedLinearProjConstraints, false);
131  }
132 
133  if (++iterNum >= m_maxIterations)
134  {
135  //LOG(WARNING) << "ConjugateGradient::modifiedCGSolve - The solver did not converge after max. iterations";
136  break;
137  }
138  }
139 }
140 
141 double
143 {
144  return m_cgSolver.error();
145 }
146 
147 void
148 ConjugateGradient::setTolerance(const double epsilon)
149 {
151  m_cgSolver.setTolerance(epsilon);
152 }
153 
154 void
156 {
158  m_cgSolver.setMaxIterations(maxIter);
159 }
160 
161 void
163 {
165  m_cgSolver.compute(m_linearSystem->getMatrix());
166 }
167 
168 void
170 {
172 
173  LOG(INFO) << "Solver: Conjugate gradient";
174  LOG(INFO) << "Tolerance: " << m_tolerance;
175  LOG(INFO) << "max. iterations: " << m_maxIterations;
176 }
177 
178 void
179 ConjugateGradient::solve(Vectord& x, const double tolerance)
180 {
181  this->setTolerance(tolerance);
182  this->solve(x);
183 }
184 } // namespace imstk
void setTolerance(const double tolerance)
Set solver tolerance.
double getResidual(const Vectord &x) override
Return the error calculated by the solver.
size_t m_maxIterations
Maximum number of iterations to be performed.
double m_tolerance
default tolerance
Compound Geometry.
void setTolerance(const double tolerance)
Set solver tolerance.
virtual void setMaxNumIterations(const size_t maxIter)
Do one iteration of the method.
virtual void setMaxNumIterations(const size_t maxIter) override
set/get the maximum number of iterations for the iterative solver.
void print() const override
Print solver information.
Represents the linear system of the form .
void print() const override
Print solver information.
void setSystem(std::shared_ptr< LinearSystemType > newSystem) override
Sets the system. System of linear equations.
void solve(Vectord &x) override
Do one iteration of the method.
Type m_type
Type of the scene object.
void applyLinearProjectionFilter(Vectord &x, const std::vector< LinearProjectionConstraint > &linProj, const bool setVal)
Apply a filter to the vector supplied.
virtual void setSystem(std::shared_ptr< LinearSystemType > newSystem)
Set/get the system. Replaces/Returns the stored linear system of equations.