KASKADE 7 development version
uzawa.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) 2002-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 UZAWA_H
14#define UZAWA_H
15
16
17#include "fem/linearspace.hh"
18#include "utilities/timing.hh"
19
20#include "dune/istl/preconditioners.hh"
21#include "dune/istl/solvers.hh"
22
23#include <boost/fusion/sequence.hpp>
24
25namespace Kaskade
26{
32 template <class X, class Y>
33 void applyPreconditioner(Dune::Preconditioner<X,Y>& p, X& x, Y& y) {
34 p.pre(x,y);
35 p.apply(x,y);
36 p.post(x);
37 }
38
54 template<class X, class Y>
55 class UzawaSolver : public Dune::InverseOperator<LinearProductSpace<typename X::field_type,
56 boost::fusion::vector<X,Y>>,
57 LinearProductSpace<typename X::field_type,
58 boost::fusion::vector<X,Y>>>
59 {
60 public:
68 typedef typename X::field_type field_type;
72
89 UzawaSolver (Dune::LinearOperator<X,X>& A_, Dune::InverseOperator<X,X>& invA_,
90 Dune::LinearOperator<X,Y>& B_, Dune::LinearOperator<Y,X>& Bt_,
91 Dune::Preconditioner<Y,Y>& precS_,
92 double reduction_, int maxit_, int verbose_)
93 : A(A_)
94 , invA(invA_)
95 , B(B_)
96 , Bt(Bt_)
97 , precS(precS_)
98 , reduction(reduction_)
99 , maxit(maxit_)
100 , verbose(verbose_)
101 {
102 }
103
104
112 virtual void apply (Domain& x, Range& b, Dune::InverseOperatorResult& res) override
113 {
114 using namespace boost::fusion;
115 using namespace Dune;
116
117 ScopedTimingSection timer("Uzawa solve");
118
119
120 Timer watch; // start a timer
121
122 InverseOperatorResult resA;
123 if (verbose>0)
124 std::cout << "=== UzawaSolver\n";
125
126 // Declare variables
127 X& u(component<0>(x)); // "velocity" component and multiplier, both as references
128 Y& p(component<1>(x)); // such that the provided solution vector is updated in place
129 X const& f(component<0>(b)); // right hand side
130 Y const& g(component<1>(b)); // and constraint
131
132 // We apply preconditioned CG to the Schur complement, with p the computed solution.
133 // Block elimination via A yields the Schur system Sp = BA^{-1}f - g with the
134 // Schur komplement S = B A^{-1} B'.
135
136 X xtmp(u), xtmp2(u);
137 Y ytmp(p);
138
139 // Compute initial energy p'Sp
140 Bt.apply(p,xtmp); // xtmp = B'p
141 {
142 ScopedTimingSection solveA("solve A");
143 auto Btp = xtmp; // need this copy since rhs arg of invA is non-const
144 invA.apply(xtmp2,Btp,resA); // xtmp2 = A^{-1}B'p
145 }
146 double energy = spX.dot(xtmp,xtmp2); // maintain squared energy norm p^T S p
147
148
149 // compute initial residual r = B A^{-1}(f-Au-B'p)-(g-Bu)
150 Y r(p);
151 xtmp = f;
152 A.applyscaleadd(-1,u,xtmp);
153 Bt.applyscaleadd(-1,p,xtmp); // xtmp = f - B'p
154 {
155 ScopedTimingSection solveA("solve A");
156 invA.apply(xtmp2,xtmp,resA); // xtmp2 = A^{-1}(f-Au-B'p)
157 }
158 B.apply(xtmp2,r); // r = B A^{-1}(f-Au-B'p)
159 r -= g; // r = B A^{-1}(f-Au-B'p) - g
160 B.applyscaleadd(1,u,r); // r = B A^{-1}(f-Au-B'p) - (g-Bu)
161
162 u += xtmp2; // maintain u = A^{-1}(f-B'p) throughout
163
164 Y rBar(r);
165 {
166 ScopedTimingSection preco("Schur preco");
167 applyPreconditioner(precS,rBar,r); // rBar = Shat^{-1} r
168 }
169 Y q = rBar;
170 X z(u); // loop invariant z = A^{-1} B' q
171 Y Sq(p); // loop invariant Sq = S q = B z
172
173 double sigma = spY.dot(r,rBar); // approximate Schur error energy r' Shat^{-1} r
174 double sigma0 = sigma; // i.e. the preconditioned residual
175
176
177 // CG iteration
178 int i = 0;
179 for ( ; i<maxit && sigma>reduction*reduction*energy; i++)
180 {
181 Bt.apply(q,xtmp); // xtmp = B'q
182 {
183 ScopedTimingSection solveA("solve A");
184 invA.apply(z,xtmp,resA); // z = A^{-1} xtmp = A^{-1} B' q
185 }
186 B.apply(z,Sq); // Sq = B z = S q
187
188 double alpha = sigma / spY.dot(q,Sq); // sigma / (q' S q)
189
190 // update solution in background, maintaining u = A^{-1}(f-B'p)
191 auto fu = std::async([&]()
192 {
193 p.axpy(alpha,q); // p = p + alpha q
194 u.axpy(-alpha,z); // u = u - alpha z = u - alpha A^{-1}B'q
195 });
196
197 energy += alpha*sigma;
198 r.axpy(-alpha,Sq); // r = r - alpha S q
199 {
200 ScopedTimingSection preco("Schur preco");
201 applyPreconditioner(precS,rBar,r); // rBar = Shat^{-1} r
202 }
203
204 fu.wait(); // join solution update
205
206 double sigmaNew = spY.dot(r,rBar);
207 double beta = sigmaNew / sigma;
208 sigma = sigmaNew;
209 q *= beta; q += rBar; // q = rBar + beta q
210
211 if (verbose>1)
212 {
213 if (i%30==0)
214 std::printf("%5s %14s %14s\n","Iter","Preco. Res.","Rate");
215 std::printf("%5d %14.4e %14.4e\n",i,std::sqrt(sigma),std::sqrt(beta));
216 }
217 }
218
219 // Fill statistics
220 res.clear();
221 res.iterations = i;
222 res.reduction = std::sqrt(sigma/sigma0);
223 res.converged = res.reduction<=reduction;
224 res.conv_rate = std::pow(res.reduction,1.0/i);
225 res.elapsed = watch.elapsed();
226
227 if (verbose>0) // final print
228 printf("=== rate=%g, time=%g, time/it=%g, iter=%d\n",res.conv_rate,res.elapsed,res.elapsed/i,i);
229 }
230
231 virtual void apply (Domain& x, Range& b, double reduction_, Dune::InverseOperatorResult& res)
232 {
233 reduction = reduction_;
234 this->apply(x,b,res);
235 }
236
237 void apply(Domain& x, Range& b)
238 {
239 Dune::InverseOperatorResult tmpResult;
240 apply(x,b,tmpResult);
241 }
242
248 virtual Dune::SolverCategory::Category category() const override
249 {
250 return Dune::SolverCategory::sequential;
251 }
252
253 private:
254 Dune::SeqScalarProduct<X> spX;
255 Dune::SeqScalarProduct<Y> spY;
256
257 Dune::LinearOperator<X,X>& A;
258 Dune::InverseOperator<X,X>& invA;
259
260 Dune::LinearOperator<X,Y>& B;
261 Dune::LinearOperator<Y,X>& Bt;
262 Dune::Preconditioner<Y,Y>& precS;
263
264 double reduction;
265 int maxit;
266 int verbose;
267 };
268
269 // ----------------------------------------------------------------------------------------------
270
279 template <class MatA, class SolA, class MatB, class MatBt, class PrecS>
280 auto uzawa(MatA& A, SolA& invA, MatB& B, MatBt& Bt, PrecS& precS,
281 double reduction=1e-3, int maxit=1000, int verbose=0)
282 {
283 using X = typename MatA::domain_type;
284 using Y = typename MatB::range_type;
285 return UzawaSolver<X,Y>(A,invA,B,Bt,precS,reduction,maxit,verbose);
286 }
287
298 template <class Scalar, class Sequence>
300 {
301 using namespace boost::fusion;
305 using Seq = vector<X,Y>;
306 return LinearProductSpace<Scalar,Seq>(Seq(X(component<0>(z)),
307 Y(component<1>(z))));
308 }
309
318 template <class Scalar, class Sequence>
320 {
321 using namespace boost::fusion;
323 using X = std::remove_const_t<typename std::remove_const_t<typename Z::Component<0>>::Component<0>>;
324 using Y = std::remove_const_t<typename std::remove_const_t<typename Z::Component<1>>::Component<0>>;
325 using Seq = boost::fusion::vector<X,Y>;
326 return LinearProductSpace<Scalar,Seq>(Seq(component<0>(component<0>(z)),
327 component<0>(component<1>(z))));
328 }
329
330}
331
332#endif
A scope guard object that automatically closes a timing section on destruction.
Definition: timing.hh:181
An inexact Uzawa type solver for solving symmetric saddle point systems.
Definition: uzawa.hh:59
UzawaSolver(Dune::LinearOperator< X, X > &A_, Dune::InverseOperator< X, X > &invA_, Dune::LinearOperator< X, Y > &B_, Dune::LinearOperator< Y, X > &Bt_, Dune::Preconditioner< Y, Y > &precS_, double reduction_, int maxit_, int verbose_)
Constructor.
Definition: uzawa.hh:89
range_type Range
Definition: uzawa.hh:71
void apply(Domain &x, Range &b)
Definition: uzawa.hh:237
virtual Dune::SolverCategory::Category category() const override
returns the category of the operator
Definition: uzawa.hh:248
LinearProductSpace< typename X::field_type, boost::fusion::vector< X, Y > > domain_type
The domain type of the Uzawa iteration.
Definition: uzawa.hh:66
virtual void apply(Domain &x, Range &b, double reduction_, Dune::InverseOperatorResult &res)
Definition: uzawa.hh:231
X::field_type field_type
Definition: uzawa.hh:68
field_type Scalar
Definition: uzawa.hh:69
virtual void apply(Domain &x, Range &b, Dune::InverseOperatorResult &res) override
Solves the saddle point system .
Definition: uzawa.hh:112
domain_type Domain
Definition: uzawa.hh:70
void applyPreconditioner(Dune::Preconditioner< X, Y > &p, X &x, Y &y)
Convenience function for simple application of preconditioners. Calls pre(), apply(),...
Definition: uzawa.hh:33
auto unnestUzawa(LinearProductSpace< Scalar, Sequence > const &z)
Convenience function for unpacking Uzawa domain/range results.
Definition: uzawa.hh:319
auto uzawa(MatA &A, SolA &invA, MatB &B, MatBt &Bt, PrecS &precS, double reduction=1e-3, int maxit=1000, int verbose=0)
Convenience function for constructing an UzawaSolver. \tparem MatA derived from Dune::LinearOperator<...
Definition: uzawa.hh:280
auto nestUzawa(LinearProductSpace< Scalar, Sequence > const &z)
Convenience function for creating Uzawa domain/range arguments.
Definition: uzawa.hh:299