KASKADE 7 development version
schur_solver.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-2009 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 SCHUR_SOLVER_HH
14#define SCHUR_SOLVER_HH
15
22#include <iostream>
23#include <memory> // std::unique_ptr
24
25#include <boost/timer/timer.hpp>
26
27
28#include "dune/common/fmatrix.hh"
29#include "dune/istl/matrix.hh"
30
36
37namespace Kaskade
38{
39
46void printVec(std::vector<double> const&v, int vend=1000000);
47
48
49template<class Factorization=UMFFactorization<double> >
51{
52public:
54 static const bool needMatrix = true;
55template<class Sys>
56BlockLUFactorization(Sys const& lin, int start2, int end2, int start3, int end3)
57 {
59 lin.getMatrixBlocks(matL,start3,end3,start2,end2);
60 matA.resize(0);
61 lin.getMatrixBlocks(matA,start2,end2,start2,end2);
62 boost::timer::cpu_timer timer;
63 factoredL.reset(new Factorization(matL.nrows(),
64 2,
65 matL.ridx,
66 matL.cidx,
67 matL.data,
69 }
70
71 void resetBlock22(MatrixAsTriplet<double>const & matA_) { matA = matA_; };
72
73 void solve(std::vector<double>const& rhs, std::vector<double>& sol, int nr=1);
75 std::unique_ptr<Factorization> factoredL;
76};
77
78void printVec(std::vector<double> const&v, int vend)
79{
80 int endv=v.size();
81 if(vend < v.size()) endv=vend;
82 for(int i=0; i< endv; ++i)
83 {
84 if(i%5 == 0) std::cout << ". " << v[i] << std::endl;
85 else std::cout << " " << v[i] << std::endl;
86
87 }
88}
89
90template<class Factorization>
91void BlockLUFactorization<Factorization>::solve(std::vector<double>const& rhs, std::vector<double>& sol, int nr)
92{
93 int r=rhs.size()/2/nr;
94 std::vector<double> rhs1(r*nr);
95 std::vector<double> rhs2(r*nr);
96 std::vector<double> sol1(r*nr);
97 std::vector<double> sol2(r*nr);
98 for(int i=0; i<nr; ++i)
99 for(int j=0; j<r; ++j)
100 {
101 rhs1[i*r+j]=rhs[i*2*r+j];
102 rhs2[i*r+j]=-rhs[i*2*r+r+j];
103 }
104 factoredL->solve(rhs2,sol2,false); // solve system
105 // factoredL->solve(rhs2,sol2,nr,false); // solve system
106 matA.axpy(rhs1,sol2,1.0,nr);
107 factoredL->solve(rhs1,sol1,true); //solve transposed system
108 // factoredL->solve(rhs1,sol1,nr,true); //solve transposed system
109 sol.resize(2*r*nr);
110 for(int i=0; i<nr; ++i)
111 for(int j=0; j<r; ++j)
112 {
113 sol[i*2*r+j]=-sol2[i*r+j];
114 sol[i*2*r+r+j]=sol1[i*r+j];
115 }
116};
117
118
120{
123 {
125 }
126
127 BlockSchurParameters(bool reg_, bool innerf_, bool outerf_)
128 : refactorizeInner(innerf_), refactorizeOuter(outerf_)
129 {
131 }
132
134 typedef enum { None=0, AddId=1, CG = 2} RegularizationMethod;
135
137};
138
139
140
141template<class Factorization, class VariableSet>
142class DirectBlockSchurSolver : public AbstractNormalDirection, public Dune::Preconditioner<typename VariableSet::Descriptions::template CoefficientVectorRepresentation<>::type,
143 typename VariableSet::Descriptions::template CoefficientVectorRepresentation<>::type>
144{
145public:
146 typedef typename VariableSet::Descriptions::template CoefficientVectorRepresentation<>::type Domain;
147 typedef Domain Range;
148
150
152 static const bool needMatrix = true;
153
154 DirectBlockSchurSolver(bool doregularize = false) :
155 start1(0), end1(1),
156 start2(1), end2(2),
157 start3(2), end3(3),
158 report(false), paras(doregularize)
159 {}
160
161 virtual void pre(Domain &x, Range &b) {}
162
163 virtual void apply (Domain &v, const Range &d) {
164
165 std::vector<double> r(rows1),s(rows2),t(rows3), sol1(rows1+rows2+rows3);
166
167 d.write(sol1.begin());
168
169 for(int i=0; i<rows1; ++i) r[i]=sol1[i];
170 for(int i=0; i<rows2; ++i) s[i]=sol1[i+rows1];
171 for(int i=0; i<rows3; ++i) t[i]=sol1[i+rows1+rows2];
172
173 resolveN(sol1,r,s,t);
174
175 v.read(sol1.begin());
176 }
177 virtual void post (Domain &x) {}
178
180
182 {
183 if(factorization.get() && paras.refactorizeInner) factorization.reset();
184 mC.setSize(0,0);
185 B.resize(0);
186 AinvB.resize(0);
187 matANormal.flush();
188 }
189
190 bool report;
191
192 void resetParameters(BlockSchurParameters const& p_) { paras=p_; }
193
194 virtual void computeCorrectionAndAdjointCorrection(AbstractVector& correction, AbstractVector& adjointCorrection, AbstractLinearization& linearization)
195 {
196 SparseLinearSystem& lins=dynamic_cast<SparseLinearSystem &>(linearization);
198 buildNewSchurComplement(lins);
199
200 std::vector<double> r,s,t, sol1, sol2;
201
202 lins.getRHSBlocks(r,start1,end1);
203 lins.getRHSBlocks(s,start2,end2);
204 lins.getRHSBlocks(t,start3,end3);
205
206 std::vector<double> r0(r.size(),0.0),s0(s.size(),0.0),t0(t.size(),0.0);
207 resolveN(sol1,r0,s0,t);
208 resolveN(sol2,r,s,t0);
209
210 dynamic_cast<Bridge::Vector<VariableSet>& >(correction).read(sol1);
211 dynamic_cast<Bridge::Vector<VariableSet>& >(adjointCorrection).read(sol2);
212 correction *= -1.0;
213 adjointCorrection *= -1.0;
214 }
215
216 virtual void computeSimplifiedCorrection(AbstractVector& correction, AbstractLinearization const& lin) const
217 {
218 SparseLinearSystem const& lins=dynamic_cast<SparseLinearSystem const&>(lin);
219
220 std::vector<double> t, sol1;
221 lins.getRHSBlocks(t,start3,end3);
222 std::vector<double> r0(rows1,0.0),s0(rows2,0.0);
223 resolveN(sol1,r0,s0,t);
224 dynamic_cast<Bridge::Vector<VariableSet>& >(correction).read(sol1);
225 correction *= -1.0;
226 }
227
228private:
229
230 void resolveN(std::vector<double>& sol, std::vector<double>const &rhs0,std::vector<double>const &rhs1, std::vector<double>const &rhs2) const;
231
232 void fwd(std::vector<double>& sol, std::vector<double>const &r,std::vector<double>const &s,std::vector<double>const &t) const;
233 void bwd(std::vector<double>& sol, std::vector<double>const &x2,std::vector<double>const &s,std::vector<double>const &t) const;
234
235
236 void buildNewSchurComplement(SparseLinearSystem const& lin,int task);
237
238 std::unique_ptr<BlockLUFactorization<Factorization> > factorization; //
239 MatrixAsTriplet<double> matANormal;
241 std::vector<double> B,AinvB;
242
243 int rowsB, colsBC, rowsC;
244 int rows1, rows2, rows3;
245
247
248};
249
250// UU UY BU* ... C B* B*
251// YU YY AY* ... B A A
252// BU AY 00 ... B A A
253// .. .. .. ...
254template<class Factorization, class VariableSet>
255void DirectBlockSchurSolver<Factorization, VariableSet>::buildNewSchurComplement(SparseLinearSystem const& lin,int task=0)
256{
257 boost::timer::cpu_timer timer;
258 if(report) std::cout << "Schur Complement: " << std::flush;
259
260 MatrixAsTriplet<double> matB, matC;
261 rowsB=lin.rows(start2,end3);
262 colsBC=lin.cols(start1,end1);
263 rowsC=lin.rows(start1,end1);
264 if(task==0)
265 {
266 rows1=lin.rows(start1,end1);
267 rows2=lin.rows(start2,end2);
268 rows3=lin.rows(start3,end3);
269 }
270
271 if(paras.refactorizeOuter || !factorization.get() || B.size()==0)
272 {
273 if(report) std::cout << "Outer, " << std::flush;
274 if(task==0)
275 {
276 flushFactorization();
277 }
278
279 if((task==0 && paras.refactorizeInner) || !factorization.get())
280 {
281 factorization.reset(new BlockLUFactorization<Factorization>(lin,start2,end2,start3,end3));
282 lin.getMatrixBlocks(matANormal,start2,end2, start2, end2);
283 }
284 else
285 {
286 MatrixAsTriplet<double> matA;
287 lin.getMatrixBlocks(matA,start2,end2, start2, end2);
288 factorization->resetBlock22(matA);
289 }
290
291
292// Matrix = [C B^T; B A]; rhs=[r2, r1]; sol=[x_2,x_1]
293// Compute sol via the Schur complement
294// B is stored in column-first formal in a vector B(i,j)=B[i+j*rowsB]
295 if(task==0 || B.size()==0)
296 {
297 matB.resize(0);
298 lin.getMatrixBlocks(matB,start2,end3, start1, end1);
299 B.resize(0);
300 matB.toVector(B);
301 }
302
303// Compute A^{-1}B
304 AinvB.resize(0);
305 factorization->solve(B,AinvB,colsBC);
306
307 }
308
309
310// Compute C as a full matrix
311 matC.resize(0);
312 lin.getMatrixBlocks(matC,start1,end1, start1, end1);
313 mC.setSize(rowsC, colsBC);
314 mC=0.0;
315 matC.addToMatrix(mC);
316
317// Compute S := B^T A^{-1}B-C
318 for(int i=0; i<rowsC; ++i)
319 for(int j=0; j<colsBC; ++j)
320 {
321 mC[i][j] *= -1.0;
322 for(int k=0; k<rowsB; ++k) mC[i][j] += B[i*rowsB+k]*AinvB[j*rowsB+k];
323 }
324 if(task==0)
325 {
326 mCNormal.setSize(rowsC, colsBC);
327 mCNormal = mC;
328 }
329 if(report) std::cout << "Finished: " << (double)(timer.elapsed().user)/1e9 << " sec." << std::endl;
330}
331
332template<class Factorization, class VariableSet>
333void DirectBlockSchurSolver<Factorization,VariableSet>::resolveN(std::vector<double>& sol, std::vector<double>const &r,std::vector<double>const &s,std::vector<double>const &t) const
334{
335 std::vector<double> xx2;
336
337 fwd(xx2,r,s,t);
338
339 std::vector<double> x2(xx2.size(),0.0);
340
341 // Compute x2 := S^{-1}xx_2
342
343 LeastSquares(SLAPMatrix<double>(mCNormal), xx2, x2);
344
345 bwd(sol,x2,s,t);
346}
347
348template<class Factorization, class VariableSet>
349void DirectBlockSchurSolver<Factorization,VariableSet>::fwd(std::vector<double>& sol, std::vector<double>const &r,std::vector<double>const &s,std::vector<double>const &t) const
350{
351 std::vector<double> xx1, r1;
352
353 r1.reserve(s.size()+t.size());
354
355 for(int i=0; i<s.size();++i) r1.push_back(s[i]);
356 for(int i=0; i<t.size();++i) r1.push_back(t[i]);
357// Compute xx1=A^{-1}r1
358
359 xx1.resize(r1.size());
360 factorization->solve(r1,xx1);
361
362// Compute sol := -r2+B^T xx1
363
364 sol.resize(r.size());
365 for(int i=0; i<r.size(); ++i)
366 {
367 sol[i]=-r[i];
368 for(int k=0; k<xx1.size(); ++k)
369 sol[i]+=B[i*rowsB+k]*xx1[k];
370 }
371}
372
373template<class Factorization, class VariableSet>
374void DirectBlockSchurSolver<Factorization,VariableSet>::bwd
375(std::vector<double>& sol, std::vector<double>const &x2,std::vector<double>const &s,std::vector<double>const &t) const
376{
377 std::vector<double> xx1,x1;
378
379 xx1.reserve(s.size()+t.size());
380
381 for(int i=0; i<s.size();++i) xx1.push_back(s[i]);
382 for(int i=0; i<t.size();++i) xx1.push_back(t[i]);
383
384// Compute xx1 := r1-B x2
385 for(int i=0; i<xx1.size(); ++i)
386 for(int k=0; k<x2.size(); ++k)
387 xx1[i]-=B[k*rowsB+i]*x2[k];
388
389// Compute x1 = A^{-1}xx1
390 factorization->solve(xx1,x1);
391
392// sol=[x2;x1]
393 sol.reserve(x2.size()+x1.size());//x2.size()+x1.size());
394 sol.resize(x2.size()+x1.size(),0.0);
395 int k=0;
396 for(int i=0; i< x2.size(); ++i)
397 {
398 sol[k]=x2[i];
399 ++k;
400 }
401 for(int i=0; i< x1.size(); ++i)
402 {
403 sol[k]=x1[i];
404 ++k;
405 }
406}
407
408
409} // namespace Kaskade
410#endif
std::unique_ptr< Factorization > factoredL
Definition: schur_solver.hh:75
void solve(std::vector< double >const &rhs, std::vector< double > &sol, int nr=1)
Definition: schur_solver.hh:91
MatrixAsTriplet< double > matA
Definition: schur_solver.hh:74
static const bool needMatrix
needs a matrix
Definition: schur_solver.hh:54
BlockLUFactorization(Sys const &lin, int start2, int end2, int start3, int end3)
Definition: schur_solver.hh:56
void resetBlock22(MatrixAsTriplet< double >const &matA_)
Definition: schur_solver.hh:71
Mathematical Vector that supports copy-on-write, implements AbstractFunctionSpaceElement.
regularized preconditioned conjugate gradient method
virtual void computeCorrectionAndAdjointCorrection(AbstractVector &correction, AbstractVector &adjointCorrection, AbstractLinearization &linearization)
virtual void pre(Domain &x, Range &b)
DirectBlockSchurSolver(bool doregularize=false)
virtual void post(Domain &x)
virtual void computeSimplifiedCorrection(AbstractVector &correction, AbstractLinearization const &lin) const
virtual void apply(Domain &v, const Range &d)
void resetParameters(BlockSchurParameters const &p_)
static const bool needMatrix
needs a matrix
VariableSet::Descriptions::template CoefficientVectorRepresentation ::type Domain
Abstract base class for matrix factorizations.
SparseIndexInt nrows() const
Returns number of rows (computes them, if not known)
Definition: triplet.hh:202
std::vector< SparseIndexInt > ridx
row indices
Definition: triplet.hh:669
std::vector< SparseIndexInt > cidx
column indices
Definition: triplet.hh:671
std::vector< Scalar > data
data
Definition: triplet.hh:673
void resize(size_t s)
Resizes the memory.
Definition: triplet.hh:234
Abstract base class for a sparse linear system.
Definition: linearsystem.hh:30
virtual void getRHSBlocks(std::vector< double > &rhs, int rbegin, int rend) const =0
Return components of the right hand side of the linear system.
void printVec(std::vector< double > const &v, int vend=1000000)
Adapter class for DUNE::IterativeSolver.
Definition: schur_solver.hh:78
void LeastSquares(SLAPMatrix< double > a, std::vector< double > const &b, std::vector< double > &x)
Solve linear least squares problem, given by a*x=b.
Bridge classes that connect low level FE algorithms to higher level algorithms.
Simple interface to acml (AMD Core Math Library), to be augmented.
RegularizationMethod regularizationMethod
BlockSchurParameters(bool reg_, bool innerf_, bool outerf_)