KASKADE 7 development version
taylorHoodPreconditioner.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2023-2024 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef TAYLORHOODPRECONDITIONER_HH
14#define TAYLORHOODPRECONDITIONER_HH
15
16#include "dune/common/config.h"
17
18
19#include "fem/linearspace.hh"
20#include "fem/supports.hh"
23
24#include "dune/grid/common/rangegenerators.hh"
25#include "dune/istl/preconditioner.hh"
26
27#include <fstream>
28
29
30namespace Kaskade
31{
32 namespace TaylorHoodPreconditionerDetail
33 {
82 template <int dim, class Real=double>
84 {
87
88 template <class R, int n>
90
92
93
94 public:
97
99
103 std::vector<int> const& constraintIndices() const;
104
105 template <class R, int nu>
107 Vector<R,dim> const& f, Vector<R,1> const& g) const;
108
109 Matrix const& getInvK() const { return invK; }
110
111 private:
112 Matrix invK; // inverse of local Stokes system
113 std::vector<EntryA> D; // square root of inverse diagonal of A
114 std::vector<int> idx; // row indices of given B that are retained.
115 };
116 }
117
118
124 {
125 SYMMETRIC,
126 PRESMOOTH,
128 };
129
199 template <class X>
201 : public Dune::Preconditioner<X,X>
202 {
204
205 public:
209 using domain_type = X;
210
219
220 using field_type = typename X::field_type;
222
228 template <class AGOP, class VelocitySpace>
230 VelocitySpace const& velocitySpace)
231 {
232 abort();
233 }
234
242 template <class MatrixA, class MatrixB, class MatrixBt, class VelocitySpace>
243 TaylorHoodPreconditioner(MatrixA const& A, MatrixB const& B, MatrixBt const& Bt,
244 VelocitySpace const& velocitySpace)
245 : dim(VelocitySpace::dim)
246 {
247 auto const& gridView = velocitySpace.gridView();
248 static_assert(MatrixA::block_type::rows==1,"matrix blocks should have one row");
249 static_assert(MatrixA::block_type::cols==1,"matrix blocks should have one col");
250 assert(A.N() % dim == 0);
251 assert(A.M() % dim == 0);
252 assert(A.M() == B.M());
253
254 // for each patch around a vertex, store the global velocity dof indices
255 patchDofs.resize(gridView.size(dim));
256 localInverse.resize(patchDofs.size());
257
258 auto patches = computePatches(gridView);
259 assert(patches.size()==patchDofs.size());
260
261 // for each dof, count the number of incident patches
262 velocityPatchCount.resize(A.N()/dim,0);
263 pressurePatchCount.resize(B.N(),0);
264
265// std::ofstream out("out.m");
266// out << "A = [" << A << "];\n";
267// out << "B = [" << B << "];\n";
268// out.close();
269
270 for (size_t i=0; i<patches.size(); ++i) // TODO: parallelize as in domainDecompositionPreconditioner.hh
271 {
272// Check if this is a boundary patch:
273bool boundaryPatch = false;
274for (auto const& cell: patches[i])
275 for (auto const& face: Dune::intersections(gridView,cell))
276 if (face.boundary())
277 boundaryPatch = true;
278
279 // Find all velocity degrees of freedom with support inside the patch
280 auto const& velocityDofs = algebraicPatch(velocitySpace,patches[i]);
281
282 // The algebraic patch computation and hence the velocityDofs vector contain indices
283 // with respect to the vectorial, i.e. multi-component, velocity space, but A is
284 // flattened out with scalar entries. Thus, we need to compute entries into A.
285 std::vector<size_t> vDofs;
286 vDofs.reserve(dim*velocityDofs.size());
287 for (auto j: velocityDofs)
288 for (int k=0; k<dim; ++k)
289 vDofs.push_back(dim*j+k);
290
291 int const nA = vDofs.size();
292 assert(nA==dim*velocityDofs.size());
293
294 // Find all pressure constraints which affect any of the velocity dofs on
295 // the patch. This is done by collecting all column indices of B' in rows
296 // given by the velocity dofs.
297 std::vector<size_t> pressureDofs;
298 for (size_t const i: vDofs)
299 for (auto ci=Bt[i].begin(); ci!=Bt[i].end(); ++ci)
300 pressureDofs.push_back(ci.index());
301
302 std::sort(pressureDofs.begin(),pressureDofs.end());
303 pressureDofs.erase(std::unique(pressureDofs.begin(),pressureDofs.end()),
304 pressureDofs.end());
305 int nB = pressureDofs.size();
306
307 // update the patch count for incident dofs (patch count is w.r.t. vectorial space/indices
308 for (size_t uIdx: velocityDofs)
309 ++velocityPatchCount[uIdx];
310 for (size_t pIdx: pressureDofs)
311 ++pressurePatchCount[pIdx];
312
313
314 // TODO: implement the method above
315
316 // using DenseMatrix = DynamicMatrix<Dune::FieldMatrix<double,1,1>>;
317 // TaylorHoodPreconditionerDetail::LocalStokesSolver<1>
318 // invK(submatrix<DenseMatrix>(A,vDofs,vDofs),
319 // submatrix<DenseMatrix>(B,pressureDofs,vDofs),
320 // submatrix<DenseMatrix>(Bt,vDofs,pressureDofs));
321 //
322 // // Move over to global data structure
323 // patchDofs[i][0] = std::move(velocityDofs);
324 // patchDofs[i][1] = std::move(pressureDofs);
325 // localInverse[i] = std::move(invK);
326 }
327 }
328
334 virtual void apply(domain_type& x, range_type const& y) override
335 {
337 }
338
347 {
348 // Initialize to zero, as we need to accumulate the solution contributions of
349 // all the patch systems.
350 x = 0;
351
352 // TODO: parallelize
353 // for (int k=0; k<patchDofs.size(); ++k)
354 for (int k=1; k<2; ++k)
355 {
356std::cout << "patch " << k << " indices: idxu=[";
357for(int i=0; i<patchDofs[k][0].size(); ++i) std::cout << 2*patchDofs[k][0][i]+1 << ' ' << 2*patchDofs[k][0][i]+2 << ' ';
358std::cout << "]; idxp=[";
359for (int i=0; i<patchDofs[k][1].size(); ++i) std::cout << patchDofs[k][1][i]+1 << ' ';
360std::cout << "];\n";
361
362 // gather velocity and pressure rhs entries with appropriate weight
363 int prolongation = 0;
364 std::vector<double> r(dim*patchDofs[k][0].size()+patchDofs[k][1].size());
365
366std::cout << "weighted urhs=[";
367 // velocity rhs
368 for (int i=0; i<patchDofs[k][0].size(); ++i)
369 {
370 auto uIdx = patchDofs[k][0][i];
371 double w = weight(velocityPatchCount[uIdx],prolongation,flavour);
372 for (int j=0; j<dim; ++j)
373 {
374 r[i*dim+j] = component<0>(y)[uIdx][j] * w;
375std::cout << r[i*dim+j] << ' ';
376 }
377 }
378std::cout << "];\nweighted prhs=[";
379
380
381 // pressure rhs
382 for (int i=0; i<patchDofs[k][1].size(); ++i)
383 {
384 auto pIdx = patchDofs[k][1][i];
385 double w = weight(pressurePatchCount[pIdx],prolongation,flavour);
386 r[dim*patchDofs[k][0].size()+i] = component<1>(y)[pIdx][0] * w;
387std::cout << r[dim*patchDofs[k][0].size()+i] << ' ';
388 }
389std::cout << "];\n";
390
391
392 // solve system
393 std::vector<double> z(r.size(),0.0);
394 // localInverse[k].mv(r,z);
395
396 // write velocity and pressure to solution, with appropriate scaling
397 prolongation = 1;
398
399 // velocity
400std::cout << "u = [";
401 for (int i=0; i<patchDofs[k][0].size(); ++i)
402 {
403 auto uIdx = patchDofs[k][0][i];
404 double w = weight(velocityPatchCount[uIdx],prolongation,flavour);
405 for (int j=0; j<dim; ++j)
406 {
407 component<0>(x)[uIdx][j] += z[i*dim+j] * w;
408std::cout << z[i*dim+j] * w << ' ';
409 }
410 }
411std::cout << "]; \np = [";
412
413 // pressure
414 for (int i=0; i<patchDofs[k][1].size(); ++i)
415 {
416 auto pIdx = patchDofs[k][1][i];
417 double w = weight(pressurePatchCount[pIdx],prolongation,flavour);
418 component<1>(x)[pIdx][0] += z[dim*patchDofs[k][0].size()+i] * w;
419std::cout << z[dim*patchDofs[k][0].size()+i] * w << ' ';
420 }
421std::cout << "];\n";
422
423 // no need to output the constant pressure multiplicator
424 }
425 }
426
427 virtual bool requiresInitializedInput() const
428 {
429 return true;
430 }
431
432 virtual void pre (domain_type& x, range_type&) override {}
433 virtual void post (domain_type& x) override {}
434 virtual Dune::SolverCategory::Category category() const override
435 {
436 return Dune::SolverCategory::sequential;
437 }
438
439 private:
440 // determines restriction (prolongation==0) or prolongation (prolongation==1). See class
441 // documentation for a detailed explanation.
442 double weight(int count, int prolongation, TaylorHoodPreconditionerFlavour flavour) const
443 {
444 assert(count > 0);
445 double w = 1.0/count;
446
448 w = std::sqrt(w);
450 w = 1;
452 w = 1;
453
454 return w;
455 }
456
457 int dim;
458
459 // for each patch around a vertex, store the global velocity and pressure dof indices
460 std::vector<std::array<std::vector<size_t>,2>> patchDofs;
461
462 // for each patch store the local inverse
463 std::vector<LocalSolver> localInverse;
464
465 // for each global velocity and pressure dof, store the number of incident patches
466 std::vector<int> velocityPatchCount;
467 std::vector<int> pressurePatchCount;
468 };
469
470 // ----------------------------------------------------------------------------------------------
471
480 template <class AGOP>
482 : public SymmetricPreconditioner<typename AGOP::Scalar,
483 typename AGOP::Domain>
484 {
485 public:
486 using domain_type = typename AGOP::Domain;
487 using range_type = typename AGOP::Range;
488 static_assert(std::is_same_v<domain_type,range_type>,"need a symmetric saddle point operator");
489 using field_type = typename AGOP::Scalar;
490
498 : K(&K_)
499 , hatKinv(*K)
500 {
501 }
502
510 void init(domain_type& x, range_type const& y) const
511 {
513 }
514
515 virtual void apply(domain_type& x, range_type const& y) override
516 {
517 // apply presmoother
518 auto z = x;
519 z = 0;
521
522 // compute residual r = y - Kz
523 auto r = y;
524 K->applyscaleadd(-1.0,z,r);
525
526 // apply postsmoother
528 x += z;
529 }
530
531 private:
532 AGOP const* K;
533
535 };
536
537}
538
539#endif
Interface for symmetric preconditioners.
Symmetric Taylor-Hood constraint preconditioner.
SymmetricTaylorHoodPreconditioner(AGOP const &K_)
Constructor.
void init(domain_type &x, range_type const &y) const
Computes an approximate solution satisfying the constraints.
virtual void apply(domain_type &x, range_type const &y) override
Solves small Stokes systems even if incompressibility constraints are linearly dependent.
void apply(Vector< R, dim > &u, Vector< R, 1 > &p, Vector< R, dim > const &f, Vector< R, 1 > const &g) const
std::vector< int > const & constraintIndices() const
the indices of B rows that are actually retained in the reduced system
Constraint preconditioner for Taylor-Hood discretizations of incompressibility problems.
virtual Dune::SolverCategory::Category category() const override
virtual void post(domain_type &x) override
TaylorHoodPreconditioner(AGOP const &K, VelocitySpace const &velocitySpace)
Constructor.
void apply(domain_type &x, range_type const &y, TaylorHoodPreconditionerFlavour flavour) const
Applies the preconditioner either as presmoother, postsmoother, or in its symmetric flavour.
virtual void pre(domain_type &x, range_type &) override
X domain_type
The domain type of the saddle point system.
TaylorHoodPreconditioner(MatrixA const &A, MatrixB const &B, MatrixBt const &Bt, VelocitySpace const &velocitySpace)
Constructor.
virtual void apply(domain_type &x, range_type const &y) override
Appliess the symmetric preconditioner as .
domain_type range_type
The range type of the saddle point system.
int count(Cell const &cell, int codim)
Computes the number of subentities of codimension c of a given entity.
Definition: fixdune.hh:716
std::vector< size_t > algebraicPatch(Space const &space, Range const &cells)
Computes the global indices of all ansatz functions whose support is a subset of the union of given c...
Definition: supports.hh:42
auto computePatches(GridView const &gridview)
Computes the patches around vertices of the grid view.
Definition: supports.hh:165
NumaBCRSMatrix< Dune::FieldMatrix< typename FineSpace::Scalar, 1, 1 >, SparseIndex > prolongation(CoarseSpace const &coarseSpace, FineSpace const &fineSpace)
Computes an interpolation-based prolongation matrix from a (supposedly) coarser space to a finer spac...
Definition: prolongation.hh:43
TaylorHoodPreconditionerFlavour
tag for controlling the TaylorHoodPreconditioner flavour