G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsMultiGrid.hpp
Go to the documentation of this file.
1
14#include <gsSolver/gsMatrixOp.h>
15
16namespace gismo
17{
18
19template<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
37template<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
51template<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
69template<class T>
70void 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.
101template<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
124template<class T>
125void 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
147template<class T>
148void 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
203template<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
234template<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
265template<class T>
266void 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
274template<class T>
275void 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
283template<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
290template<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
299template<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
312template<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}
Simple adapter class to use a matrix (or matrix-like object) as a linear operator....
Definition gsMatrixOp.h:34
MatrixPtr matrixPtr() const
Returns a shared pinter to the matrix.
Definition gsMatrixOp.h:88
NestedMatrix matrix() const
Returns the matrix.
Definition gsMatrixOp.h:84
gsMultiGridOp(SpMatrix fineMatrix, std::vector< SpMatrixRowMajor > transferMatrices, OpPtr coarseSolver=OpPtr())
Constructor.
Definition gsMultiGrid.hpp:20
index_t m_nLevels
Number of levels.
Definition gsMultiGrid.h:363
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
gsLinearOperator< T >::Ptr OpPtr
Shared pointer to gsLinearOperator.
Definition gsMultiGrid.h:69
void setOptions(const gsOptionList &opt) override
Set the options based on a gsOptionList.
Definition gsMultiGrid.hpp:313
void init(SpMatrixPtr fineMatrix, std::vector< SpMatrixRowMajorPtr > transferMatrices)
Init function that is used by matrix based constructors.
Definition gsMultiGrid.hpp:70
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
void setSmoother(index_t lvl, const PrecondPtr &sm)
Definition gsMultiGrid.hpp:284
void smoothingStep(index_t level, const Matrix &rhs, Matrix &x) const
Apply smoothing steps on the corresponding level.
Definition gsMultiGrid.hpp:125
gsPreconditionerOp< T >::Ptr PrecondPtr
Shared pointer to gsPreconditionerOp.
Definition gsMultiGrid.h:72
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
const SpMatrix & matrix() const
Stiffness matrix for finest level.
Definition gsMultiGrid.h:278
void initCoarseSolver() const
Init solver on coarsest grid level.
Definition gsMultiGrid.hpp:102
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
gsVector< index_t > m_numCycles
Number of coarse-grid steps (1=V-cycle, 2=W-cycle)
Definition gsMultiGrid.h:390
void multiGridStep(index_t level, const Matrix &rhs, Matrix &x) const
Perform one multigrid cycle, starting from the given level.
Definition gsMultiGrid.hpp:148
static gsOptionList defaultOptions()
Returns a list of default options.
Definition gsMultiGrid.hpp:300
Class which holds a list of parameters/options, and provides easy access to them.
Definition gsOptionList.h:33
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
Real askReal(const std::string &label, const Real &value=0) const
Reads value for option label from options.
Definition gsOptionList.cpp:139
bool askSwitch(const std::string &label, const bool &value=false) const
Reads value for option label from options.
Definition gsOptionList.cpp:128
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
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 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
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition gsSparseMatrix.h:247
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.
The G+Smo namespace, containing all definitions for the library.
S give(S &x)
Definition gsMemory.h:266