G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsMultiGrid.hpp
Go to the documentation of this file.
1 
14 #include <gsSolver/gsMatrixOp.h>
15 
16 namespace gismo
17 {
18 
19 template<class T>
21  SpMatrix fineMatrix,
22  std::vector<SpMatrixRowMajor> transferMatrices,
23  OpPtr coarseSolver
24 )
25  : m_nLevels(transferMatrices.size()+1), m_ops(m_nLevels), m_smoother(m_nLevels),
26  m_prolong(m_nLevels-1), m_restrict(m_nLevels-1), m_coarseSolver(coarseSolver),
27  m_numPreSmooth(1), m_numPostSmooth(1), m_symmSmooth(true), m_damping(1)
28 {
29  m_numCycles.setConstant(m_nLevels-1,1);
30  std::vector<SpMatrixRowMajorPtr> transferMatrixPtrs(m_nLevels-1);
31  for (index_t i=0; i<m_nLevels-1; ++i)
32  transferMatrixPtrs[i] = transferMatrices[i].moveToPtr();
33 
34  init(fineMatrix.moveToPtr(),give(transferMatrixPtrs));
35 }
36 
37 template<class T>
39  SpMatrixPtr fineMatrix,
40  std::vector<SpMatrixRowMajorPtr> transferMatrices,
41  OpPtr coarseSolver
42 )
43  : m_nLevels(transferMatrices.size()+1), m_ops(m_nLevels), m_smoother(m_nLevels),
44  m_prolong(m_nLevels-1), m_restrict(m_nLevels-1), m_coarseSolver(coarseSolver),
45  m_numPreSmooth(1), m_numPostSmooth(1), m_symmSmooth(true), m_damping(1)
46 {
47  m_numCycles.setConstant(m_nLevels-1,1);
48  init(give(fineMatrix),give(transferMatrices));
49 }
50 
51 template<class T>
53  const std::vector<OpPtr>& ops,
54  const std::vector<OpPtr>& prolongation,
55  const std::vector<OpPtr>& restriction,
56  OpPtr coarseSolver
57 )
58  : m_nLevels(ops.size()), m_ops(ops), m_smoother(m_nLevels),
59  m_prolong(prolongation), m_restrict(restriction), m_coarseSolver(coarseSolver),
60  m_numPreSmooth(1), m_numPostSmooth(1), m_symmSmooth(true), m_damping(1)
61 {
62  m_numCycles.setConstant(m_nLevels-1,1);
63  GISMO_ASSERT (prolongation.size() == restriction.size(),
64  "gsMultiGridOp: The number of prolongation and restriction operators differ.");
65  GISMO_ASSERT (ops.size() == prolongation.size()+1,
66  "gsMultiGridOp: The number of prolongation and restriction operators do not fit to the number of operators.");
67 }
68 
69 template<class T>
70 void gsMultiGridOp<T>::init(SpMatrixPtr fineMatrix, std::vector<SpMatrixRowMajorPtr> transferMatrices)
71 {
72  GISMO_ASSERT (fineMatrix->rows() == fineMatrix->cols(), "gsMultiGridOp needs quadratic matrices.");
73 
74  SpMatrixPtr mat = fineMatrix;
75  m_ops[m_nLevels-1] = makeMatrixOp(mat);
76 
77  for ( index_t i = m_nLevels - 2; i >= 0; --i )
78  {
79  SpMatrixPtr newMat = SpMatrixPtr(new SpMatrix(
80  transferMatrices[i]->transpose() * *mat * *(transferMatrices[i])
81  ));
82  m_ops[i] = makeMatrixOp(newMat);
83  mat = newMat; // copies just the smart pointers
84  }
85 
86  for ( index_t i=0; i<m_nLevels-1; ++i )
87  {
88  m_prolong[i] = makeMatrixOp(transferMatrices[i]);
89  // Note that the following works since we know that m_prolong does not
90  // get destroyed beforem_restrict, so the shared pointer stored in
91  // m_prolong will make sure that the underlying matrix will not get
92  // destroyed. Thus, there will be no dangling pointer.
93  m_restrict[i] = makeMatrixOp(transferMatrices[i]->transpose());
94  }
95 }
96 
97 // This function is const since it is called from "apply", which itself is const.
98 // Since this function realizes a late initialization for the coarse solver, it is
99 // semantically const. We want late initialization since this gives the caller a
100 // better chance to use an alternate solver.
101 template<class T>
103 {
104  const gsMatrixOp<SpMatrix>* matrOp = dynamic_cast< const gsMatrixOp<SpMatrix>* >( m_ops[0].get() );
105  if (matrOp)
106  {
107  const SpMatrix & matr = matrOp->matrix();
108  m_coarseSolver = makeSparseLUSolver(matr);
109  }
110  else
111  {
112  // Fallback for other types of operators (matrix free implementations, etc.)
113  // Warn if we do this for big matrices...
114  if (m_ops[0]->rows() > 50)
115  gsWarn << "gsMultiGridOp::initCoarseSolverIfUninitialized(): The coarse grid solver is constructed "
116  "based on gsLinearOperator::toMatrix(). This might be inefficient. Consider providing matrices of "
117  "type gsSparseMatrix<T> or an exact solver for the coarset grid level to gsMultiGridOp constructor.\n";
118  Matrix coarse_dense;
119  m_ops[0]->toMatrix( coarse_dense );
120  m_coarseSolver = makePartialPivLUSolver( coarse_dense );
121  }
122 }
123 
124 template<class T>
125 void gsMultiGridOp<T>::smoothingStep(index_t level, const Matrix& rhs, Matrix& x) const
126 {
127  GISMO_ASSERT (m_smoother[level], "gsMultiGridOp::smoothingStep: "
128  "Smoother is not defined for level "<<level<<". Define it using setSmoother.");
129 
130  // pre-smooth
131  for (index_t i = 0; i < m_numPreSmooth; ++i)
132  {
133  m_smoother[level]->step( rhs, x );
134  }
135 
136  // post-smooth
137  for (index_t i = 0; i < m_numPostSmooth; ++i)
138  {
139  if (m_symmSmooth)
140  m_smoother[level]->stepT( rhs, x );
141  else
142  m_smoother[level]->step( rhs, x );
143  }
144 
145 }
146 
147 template<class T>
148 void gsMultiGridOp<T>::multiGridStep(index_t level, const Matrix& rhs, Matrix& x) const
149 {
150  GISMO_ASSERT ( 0 <= level && level < m_nLevels, "TgsMultiGridOp: the given level is not feasible." );
151 
152  if (level == 0)
153  {
154  solveCoarse(rhs, x);
155  }
156  else
157  {
158  const index_t lf = level;
159  const index_t lc = lf - 1;
160 
161  GISMO_ASSERT (m_smoother[lf], "gsMultiGridOp::multiGridStep: "
162  "Smoother is not defined for level "<<lf<<". Define it using setSmoother.");
163 
164  Matrix fineRes, fineCorr, coarseRes, coarseCorr;
165 
166  // pre-smooth
167  for (index_t i = 0; i < m_numPreSmooth; ++i)
168  {
169  m_smoother[lf]->step( rhs, x );
170  }
171 
172  // compute fine residual
173  m_ops[lf]->apply( x, fineRes );
174  fineRes -= rhs;
175 
176  // restrict residual to coarse grid
177  restrictVector( lf, fineRes, coarseRes );
178 
179  // obtain coarse-grid correction by recursing
180  coarseCorr.setZero( nDofs(lc), coarseRes.cols() );
181  for (index_t i = 0; i < m_numCycles[lc]; ++i)
182  {
183  multiGridStep( lc, coarseRes, coarseCorr );
184  }
185 
186  // prolong correction
187  prolongVector( lc, coarseCorr, fineCorr );
188 
189  // apply correction
190  x -= m_damping * fineCorr;
191 
192  // post-smooth
193  for (index_t i = 0; i < m_numPostSmooth; ++i)
194  {
195  if (m_symmSmooth)
196  m_smoother[lf]->stepT( rhs, x );
197  else
198  m_smoother[lf]->step( rhs, x );
199  }
200  }
201 }
202 
203 template<class T>
205  const std::vector<Matrix>& rhs,
206  const std::vector<Matrix>& fixedValues,
207  gsMatrix<T>& result
208 ) const
209 {
210 
211  GISMO_ASSERT (fixedValues.size() == static_cast<size_t>(m_nLevels),
212  "gsMultiGridOp::fullMultiGrid: The size of fixedValues does not correspond to the number of levels.");
213  GISMO_ASSERT (rhs.size() == static_cast<size_t>(m_nLevels),
214  "gsMultiGridOp::fullMultiGrid: The size of rhs does not correspond to the number of levels.");
215 
216  std::vector<Matrix> u(m_nLevels);
217 
218  // solve coarse problem
219  solveCoarse( rhs[0], u[0] );
220 
221  for (index_t i = 1; i <= finestLevel(); ++i)
222  {
223  // transfer result from previous level
224  prolongVector(i-1, u[i-1], u[i]);
225  u[i] += fixedValues[i];
226 
227  // run one multigrid step
228  multiGridStep(i, rhs[i], u[i]);
229  }
230 
231  result = u[ finestLevel() ];
232 }
233 
234 template<class T>
236  const std::vector<Matrix>& rhs,
237  const std::vector<Matrix>& fixedValues,
238  Matrix& result
239 ) const
240 {
241 
242  GISMO_ASSERT (fixedValues.size() == static_cast<size_t>(m_nLevels),
243  "gsMultiGridOp::cascadicMultiGrid: The size of fixedValue does not correspond to the number of levels.");
244  GISMO_ASSERT (rhs.size() == static_cast<size_t>(m_nLevels),
245  "gsMultiGridOp::cascadicMultiGrid: The size of rhs does not correspond to the number of levels.");
246 
247  std::vector<Matrix> u(m_nLevels);
248 
249  // solve coarse problem
250  solveCoarse( rhs[0], u[0] );
251 
252  for (index_t i = 1; i <= finestLevel(); ++i)
253  {
254  // transfer result from previous level
255  prolongVector(i-1, u[i-1], u[i]);
256  u[i] += fixedValues[i];
257 
258  // smooth
259  smoothingStep(i, rhs[i], u[i]);
260  }
261 
262  result = u[ finestLevel() ];
263 }
264 
265 template<class T>
266 void gsMultiGridOp<T>::restrictVector(index_t lf, const Matrix& fine, Matrix& coarse) const
267 {
268  GISMO_ASSERT ( 0 < lf && lf < m_nLevels, "gsMultiGrid: The given level is not feasible." );
269  GISMO_ASSERT ( fine.rows() == nDofs(lf), "gsMultiGrid: The dimensions do not fit." );
270 
271  m_restrict[lf-1]->apply( fine, coarse );
272 }
273 
274 template<class T>
275 void gsMultiGridOp<T>::prolongVector(index_t lc, const Matrix& coarse, Matrix& fine) const
276 {
277  GISMO_ASSERT ( 0 <= lc && lc < m_nLevels - 1, "gsMultiGrid: The given level is not feasible." );
278  GISMO_ASSERT ( coarse.rows() == nDofs(lc), "gsMultiGrid: The dimensions do not fit." );
279 
280  m_prolong[lc]->apply( coarse, fine );
281 }
282 
283 template<class T>
285 {
286  GISMO_ASSERT ( 0 <= lvl && lvl < m_nLevels, "gsMultiGrid: The given level is not feasible." );
287  m_smoother[lvl] = sm;
288 }
289 
290 template<class T>
292 {
293  const gsMatrixOp<SpMatrix>* matrOp = dynamic_cast< const gsMatrixOp<SpMatrix>* >( m_ops[lvl].get() );
294  GISMO_ASSERT ( matrOp, "Matrices are not available for matrix-free multigrid solvers." );
295  //return matrOp->matrix(); does not work because we must not return a temporary
296  return *(matrOp->matrixPtr());
297 }
298 
299 template<class T>
301 {
302  gsOptionList opt = Base::defaultOptions();
303  opt.addInt ("NumPreSmooth" , "Number of pre-smoothing steps", 1 );
304  opt.addInt ("NumPostSmooth" , "Number of post-smoothing steps", 1 );
305  opt.addInt ("NumCycles" , "Number of cycles (usually 1 for V-cycle or 2 for W-cycle)", 1 );
306  opt.addReal ("CoarseGridCorrectionDamping" , "Damping of the coarse-grid correction (usually 1)", (gsOptionList::Real)1 );
307  opt.addSwitch("SymmSmooth" , "Iff true, stepT is called for post-smoothing", true );
308 
309  return opt;
310 }
311 
312 template<class T>
314 {
315  Base::setOptions(opt);
316  m_numPreSmooth = opt.askInt ("NumPreSmooth" , m_numPreSmooth );
317  m_numPostSmooth = opt.askInt ("NumPostSmooth" , m_numPostSmooth );
318  m_damping = opt.askReal ("CoarseGridCorrectionDamping" , m_damping );
319  m_symmSmooth = opt.askSwitch("SymmSmooth" , m_symmSmooth );
320 
321  const index_t nc = opt.askInt ("NumCycles" , -1 );
322  if (nc > -1)
323  {
324  m_numCycles.setConstant(m_nLevels-1, nc);
325  // The direct solver on coarsest level is only invoked once
326  m_numCycles[0] = 1;
327  }
328 }
329 
330 }
MatrixPtr matrixPtr() const
Returns a shared pinter to the matrix.
Definition: gsMatrixOp.h:88
static gsOptionList defaultOptions()
Returns a list of default options.
Definition: gsMultiGrid.hpp:300
gsMultiGridOp(SpMatrix fineMatrix, std::vector< SpMatrixRowMajor > transferMatrices, OpPtr coarseSolver=OpPtr())
Constructor.
Definition: gsMultiGrid.hpp:20
gsPreconditionerOp< T >::Ptr PrecondPtr
Shared pointer to gsPreconditionerOp.
Definition: gsMultiGrid.h:72
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition: gsSparseMatrix.h:249
Simple adapter class to use a matrix (or matrix-like object) as a linear operator. Needed for the iterative method classes.
Definition: gsMatrixOp.h:33
void prolongVector(index_t lc, const Matrix &coarse, Matrix &fine) const
Prolong a vector of coefficients from the level lc, given by coarse, to the next finer level...
Definition: gsMultiGrid.hpp:275
NestedMatrix matrix() const
Returns the matrix.
Definition: gsMatrixOp.h:84
S give(S &x)
Definition: gsMemory.h:266
#define index_t
Definition: gsConfig.h:32
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
void multiGridStep(index_t level, const Matrix &rhs, Matrix &x) const
Perform one multigrid cycle, starting from the given level.
Definition: gsMultiGrid.hpp:148
void addInt(const std::string &label, const std::string &desc, const index_t &value)
Adds a option named label, with description desc and value value.
Definition: gsOptionList.cpp:201
#define gsWarn
Definition: gsDebug.h:50
memory::shared_ptr< SpMatrix > SpMatrixPtr
Smart pointer to sparse matrix type.
Definition: gsMultiGrid.h:87
void cascadicMultiGrid(const std::vector< Matrix > &rhs, const std::vector< Matrix > &fixedValues, Matrix &result) const
Perform one cascadic multigrid cycle and store the resulting solution vector in result.
Definition: gsMultiGrid.hpp:235
void initCoarseSolver() const
Init solver on coarsest grid level.
Definition: gsMultiGrid.hpp:102
const SpMatrix & matrix() const
Stiffness matrix for finest level.
Definition: gsMultiGrid.h:278
void setOptions(const gsOptionList &opt) override
Set the options based on a gsOptionList.
Definition: gsMultiGrid.hpp:313
void restrictVector(index_t lf, const Matrix &fine, Matrix &coarse) const
Restrict a vector of coefficients from the level lf, given by fine, to the next coarser level...
Definition: gsMultiGrid.hpp:266
void fullMultiGrid(const std::vector< Matrix > &rhs, const std::vector< Matrix > &dirichletIntp, Matrix &result) const
Perform one full multigrid cycle and store the resulting solution vector in result.
Definition: gsMultiGrid.hpp:204
Real askReal(const std::string &label, const Real &value=0) const
Reads value for option label from options.
Definition: gsOptionList.cpp:139
index_t m_nLevels
Number of levels.
Definition: gsMultiGrid.h:363
void init(SpMatrixPtr fineMatrix, std::vector< SpMatrixRowMajorPtr > transferMatrices)
Init function that is used by matrix based constructors.
Definition: gsMultiGrid.hpp:70
index_t askInt(const std::string &label, const index_t &value=0) const
Reads value for option label from options.
Definition: gsOptionList.cpp:117
void addReal(const std::string &label, const std::string &desc, const Real &value)
Adds a option named label, with description desc and value value.
Definition: gsOptionList.cpp:211
gsVector< index_t > m_numCycles
Number of coarse-grid steps (1=V-cycle, 2=W-cycle)
Definition: gsMultiGrid.h:390
gsLinearOperator< T >::Ptr OpPtr
Shared pointer to gsLinearOperator.
Definition: gsMultiGrid.h:69
bool askSwitch(const std::string &label, const bool &value=false) const
Reads value for option label from options.
Definition: gsOptionList.cpp:128
Class which holds a list of parameters/options, and provides easy access to them. ...
Definition: gsOptionList.h:32
void smoothingStep(index_t level, const Matrix &rhs, Matrix &x) const
Apply smoothing steps on the corresponding level.
Definition: gsMultiGrid.hpp:125
void addSwitch(const std::string &label, const std::string &desc, const bool &value)
Adds a option named label, with description desc and value value.
Definition: gsOptionList.cpp:235
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.
void setSmoother(index_t lvl, const PrecondPtr &sm)
Definition: gsMultiGrid.hpp:284