Dune Core Modules (2.7.0)

ilu.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_ISTL_ILU_HH
4#define DUNE_ISTL_ILU_HH
5
6#include <cmath>
7#include <complex>
8#include <map>
9#include <vector>
10
14#include "istlexception.hh"
15
20namespace Dune {
21
26 class MatrixBlockError : public virtual Dune::FMatrixError {
27 public:
28 int r, c;
29 };
30
31
33 template<class M>
35 {
36 // iterator types
37 typedef typename M::RowIterator rowiterator;
38 typedef typename M::ColIterator coliterator;
39 typedef typename M::block_type block;
40
41 // implement left looking variant with stored inverse
42 rowiterator endi=A.end();
43 for (rowiterator i=A.begin(); i!=endi; ++i)
44 {
45 // coliterator is diagonal after the following loop
46 coliterator endij=(*i).end(); // end of row i
47 coliterator ij;
48
49 // eliminate entries left of diagonal; store L factor
50 for (ij=(*i).begin(); ij.index()<i.index(); ++ij)
51 {
52 // find A_jj which eliminates A_ij
53 coliterator jj = A[ij.index()].find(ij.index());
54
55 // compute L_ij = A_jj^-1 * A_ij
56 Impl::asMatrix(*ij).rightmultiply(Impl::asMatrix(*jj));
57
58 // modify row
59 coliterator endjk=A[ij.index()].end(); // end of row j
60 coliterator jk=jj; ++jk;
61 coliterator ik=ij; ++ik;
62 while (ik!=endij && jk!=endjk)
63 if (ik.index()==jk.index())
64 {
65 block B(*jk);
66 Impl::asMatrix(B).leftmultiply(Impl::asMatrix(*ij));
67 *ik -= B;
68 ++ik; ++jk;
69 }
70 else
71 {
72 if (ik.index()<jk.index())
73 ++ik;
74 else
75 ++jk;
76 }
77 }
78
79 // invert pivot and store it in A
80 if (ij.index()!=i.index())
81 DUNE_THROW(ISTLError,"diagonal entry missing");
82 try {
83 Impl::asMatrix(*ij).invert(); // compute inverse of diagonal block
84 }
85 catch (Dune::FMatrixError & e) {
86 DUNE_THROW(MatrixBlockError, "ILU failed to invert matrix block A["
87 << i.index() << "][" << ij.index() << "]" << e.what();
88 th__ex.r=i.index(); th__ex.c=ij.index(););
89 }
90 }
91 }
92
94 template<class M, class X, class Y>
95 void bilu_backsolve (const M& A, X& v, const Y& d)
96 {
97 // iterator types
98 typedef typename M::ConstRowIterator rowiterator;
99 typedef typename M::ConstColIterator coliterator;
100 typedef typename Y::block_type dblock;
101 typedef typename X::block_type vblock;
102
103 // lower triangular solve
104 rowiterator endi=A.end();
105 for (rowiterator i=A.begin(); i!=endi; ++i)
106 {
107 // We need to be careful here: Directly using
108 // auto rhs = Impl::asVector(d[ i.index() ]);
109 // is not OK in case this is a proxy. Hence
110 // we first have to copy the value. Notice that
111 // this is still not OK, if the vector type itself returns
112 // proxy references.
113 dblock rhsValue(d[i.index()]);
114 auto&& rhs = Impl::asVector(rhsValue);
115 for (coliterator j=(*i).begin(); j.index()<i.index(); ++j)
116 Impl::asMatrix(*j).mmv(Impl::asVector(v[j.index()]),rhs);
117 Impl::asVector(v[i.index()]) = rhs; // Lii = I
118 }
119
120 // upper triangular solve
121 rowiterator rendi=A.beforeBegin();
122 for (rowiterator i=A.beforeEnd(); i!=rendi; --i)
123 {
124 // We need to be careful here: Directly using
125 // auto rhs = Impl::asVector(v[ i.index() ]);
126 // is not OK in case this is a proxy. Hence
127 // we first have to copy the value. Notice that
128 // this is still not OK, if the vector type itself returns
129 // proxy references.
130 vblock rhsValue(v[i.index()]);
131 auto&& rhs = Impl::asVector(rhsValue);
132 coliterator j;
133 for (j=(*i).beforeEnd(); j.index()>i.index(); --j)
134 Impl::asMatrix(*j).mmv(Impl::asVector(v[j.index()]),rhs);
135 auto&& vi = Impl::asVector(v[i.index()]);
136 Impl::asMatrix(*j).mv(rhs,vi); // diagonal stores inverse!
137 }
138 }
139
140
141
142 // recursive function template to access first entry of a matrix
143 template<class M>
144 typename M::field_type& firstmatrixelement (M& A, typename std::enable_if_t<!Dune::IsNumber<M>::value>* sfinae = nullptr)
145 {
146 return firstmatrixelement(*(A.begin()->begin()));
147 }
148
149 template<class K>
150 K& firstmatrixelement (K& A, typename std::enable_if_t<Dune::IsNumber<K>::value>* sfinae = nullptr)
151 {
152 return A;
153 }
154
155 template<class K, int n, int m>
156 K& firstmatrixelement (FieldMatrix<K,n,m>& A)
157 {
158 return A[0][0];
159 }
160
161
168 template<class M>
169 void bilu_decomposition (const M& A, int n, M& ILU)
170 {
171 // iterator types
172 typedef typename M::ColIterator coliterator;
173 typedef typename M::ConstRowIterator crowiterator;
174 typedef typename M::ConstColIterator ccoliterator;
175 typedef typename M::CreateIterator createiterator;
176 typedef typename M::field_type K;
177 typedef std::map<size_t, int> map;
178 typedef typename map::iterator mapiterator;
179
180 // symbolic factorization phase, store generation number in first matrix element
181 crowiterator endi=A.end();
182 createiterator ci=ILU.createbegin();
183 for (crowiterator i=A.begin(); i!=endi; ++i)
184 {
185 map rowpattern; // maps column index to generation
186
187 // initialize pattern with row of A
188 for (ccoliterator j=(*i).begin(); j!=(*i).end(); ++j)
189 rowpattern[j.index()] = 0;
190
191 // eliminate entries in row which are to the left of the diagonal
192 for (mapiterator ik=rowpattern.begin(); (*ik).first<i.index(); ++ik)
193 {
194 if ((*ik).second<n)
195 {
196 coliterator endk = ILU[(*ik).first].end(); // end of row k
197 coliterator kj = ILU[(*ik).first].find((*ik).first); // diagonal in k
198 for (++kj; kj!=endk; ++kj) // row k eliminates in row i
199 {
200 // we misuse the storage to store an int. If the field_type is std::complex, we have to access the real/abs part
201 // starting from C++11, we can use std::abs to always return a real value, even if it is double/float
202 using std::abs;
203 int generation = (int) Simd::lane(0,abs( firstmatrixelement(*kj) ));
204 if (generation<n)
205 {
206 mapiterator ij = rowpattern.find(kj.index());
207 if (ij==rowpattern.end())
208 {
209 rowpattern[kj.index()] = generation+1;
210 }
211 }
212 }
213 }
214 }
215
216 // create row
217 for (mapiterator ik=rowpattern.begin(); ik!=rowpattern.end(); ++ik)
218 ci.insert((*ik).first);
219 ++ci; // now row i exist
220
221 // write generation index into entries
222 coliterator endILUij = ILU[i.index()].end();;
223 for (coliterator ILUij=ILU[i.index()].begin(); ILUij!=endILUij; ++ILUij)
224 Simd::lane(0,firstmatrixelement(*ILUij)) = (Simd::Scalar<K>) rowpattern[ILUij.index()];
225 }
226
227 // copy entries of A
228 for (crowiterator i=A.begin(); i!=endi; ++i)
229 {
230 coliterator ILUij;
231 coliterator endILUij = ILU[i.index()].end();;
232 for (ILUij=ILU[i.index()].begin(); ILUij!=endILUij; ++ILUij)
233 (*ILUij) = 0; // clear row
234 ccoliterator Aij = (*i).begin();
235 ccoliterator endAij = (*i).end();
236 ILUij = ILU[i.index()].begin();
237 while (Aij!=endAij && ILUij!=endILUij)
238 {
239 if (Aij.index()==ILUij.index())
240 {
241 *ILUij = *Aij;
242 ++Aij; ++ILUij;
243 }
244 else
245 {
246 if (Aij.index()<ILUij.index())
247 ++Aij;
248 else
249 ++ILUij;
250 }
251 }
252 }
253
254 // call decomposition on pattern
256 }
257
258 namespace ILU {
259
260 template <class B, class Alloc = std::allocator<B>>
261 struct CRS
262 {
263 typedef B block_type;
264 typedef size_t size_type;
265
266 CRS() : nRows_( 0 ) {}
267
268 size_type rows() const { return nRows_; }
269
270 size_type nonZeros() const
271 {
272 assert( rows_[ rows() ] != size_type(-1) );
273 return rows_[ rows() ];
274 }
275
276 void resize( const size_type nRows )
277 {
278 if( nRows_ != nRows )
279 {
280 nRows_ = nRows ;
281 rows_.resize( nRows_+1, size_type(-1) );
282 }
283 }
284
285 void reserveAdditional( const size_type nonZeros )
286 {
287 const size_type needed = values_.size() + nonZeros ;
288 if( values_.capacity() < needed )
289 {
290 const size_type estimate = needed * 1.1;
291 values_.reserve( estimate );
292 cols_.reserve( estimate );
293 }
294 }
295
296 void push_back( const block_type& value, const size_type index )
297 {
298 values_.push_back( value );
299 cols_.push_back( index );
300 }
301
302 std::vector< size_type > rows_;
303 std::vector< block_type, Alloc> values_;
304 std::vector< size_type > cols_;
305 size_type nRows_;
306 };
307
309 template<class M, class CRS, class InvVector>
310 void convertToCRS(const M& A, CRS& lower, CRS& upper, InvVector& inv )
311 {
312 typedef typename M :: size_type size_type;
313
314 lower.resize( A.N() );
315 upper.resize( A.N() );
316 inv.resize( A.N() );
317
318 // lower and upper triangular should store half of non zeros minus diagonal
319 const size_t memEstimate = (A.nonzeroes() - A.N())/2;
320
321 assert( A.nonzeroes() != 0 );
322 lower.reserveAdditional( memEstimate );
323 upper.reserveAdditional( memEstimate );
324
325 const auto endi = A.end();
326 size_type row = 0;
327 size_type colcount = 0;
328 lower.rows_[ 0 ] = colcount;
329 for (auto i=A.begin(); i!=endi; ++i, ++row)
330 {
331 const size_type iIndex = i.index();
332
333 // store entries left of diagonal
334 for (auto j=(*i).begin(); j.index() < iIndex; ++j )
335 {
336 lower.push_back( (*j), j.index() );
337 ++colcount;
338 }
339 lower.rows_[ iIndex+1 ] = colcount;
340 }
341
342 const auto rendi = A.beforeBegin();
343 row = 0;
344 colcount = 0;
345 upper.rows_[ 0 ] = colcount ;
346
347 // NOTE: upper and inv store entries in reverse row and col order,
348 // reverse here relative to ILU
349 for (auto i=A.beforeEnd(); i!=rendi; --i, ++ row )
350 {
351 const auto endij=(*i).beforeBegin(); // end of row i
352
353 const size_type iIndex = i.index();
354
355 // store in reverse row order for faster access during backsolve
356 for (auto j=(*i).beforeEnd(); j != endij; --j )
357 {
358 const size_type jIndex = j.index();
359 if( j.index() == iIndex )
360 {
361 inv[ row ] = (*j);
362 break; // assuming consecutive ordering of A
363 }
364 else if ( j.index() >= i.index() )
365 {
366 upper.push_back( (*j), jIndex );
367 ++colcount ;
368 }
369 }
370 upper.rows_[ row+1 ] = colcount;
371 }
372 } // end convertToCRS
373
374
376 template<class CRS, class InvVector, class X, class Y>
377 void bilu_backsolve (const CRS& lower,
378 const CRS& upper,
379 const InvVector& inv,
380 X& v, const Y& d)
381 {
382 // iterator types
383 typedef typename Y :: block_type dblock;
384 typedef typename X :: block_type vblock;
385 typedef typename X :: size_type size_type ;
386
387 const size_type iEnd = lower.rows();
388 const size_type lastRow = iEnd - 1;
389 if( iEnd != upper.rows() )
390 {
391 DUNE_THROW(ISTLError,"ILU::bilu_backsolve: lower and upper rows must be the same");
392 }
393
394 // lower triangular solve
395 for( size_type i=0; i<iEnd; ++ i )
396 {
397 dblock rhsValue( d[ i ] );
398 auto&& rhs = Impl::asVector(rhsValue);
399 const size_type rowI = lower.rows_[ i ];
400 const size_type rowINext = lower.rows_[ i+1 ];
401
402 for( size_type col = rowI; col < rowINext; ++ col )
403 Impl::asMatrix(lower.values_[ col ]).mmv( Impl::asVector(v[ lower.cols_[ col ] ] ), rhs );
404
405 Impl::asVector(v[ i ]) = rhs; // Lii = I
406 }
407
408 // upper triangular solve
409 for( size_type i=0; i<iEnd; ++ i )
410 {
411 auto&& vBlock = Impl::asVector(v[ lastRow - i ]);
412 vblock rhsValue ( v[ lastRow - i ] );
413 auto&& rhs = Impl::asVector(rhsValue);
414 const size_type rowI = upper.rows_[ i ];
415 const size_type rowINext = upper.rows_[ i+1 ];
416
417 for( size_type col = rowI; col < rowINext; ++ col )
418 Impl::asMatrix(upper.values_[ col ]).mmv( Impl::asVector(v[ upper.cols_[ col ] ]), rhs );
419
420 // apply inverse and store result
421 Impl::asMatrix(inv[ i ]).mv(rhs, vBlock);
422 }
423 }
424
425 } // end namespace ILU
426
427
430} // end namespace
431
432#endif
Error thrown if operations of a FieldMatrix fail.
Definition: densematrix.hh:150
derive error class from the base class in common
Definition: istlexception.hh:16
RowIterator beforeBegin()
Definition: matrix.hh:630
RowIterator beforeEnd()
Definition: matrix.hh:623
RowIterator end()
Get iterator to one beyond last row.
Definition: matrix.hh:616
RowIterator begin()
Get iterator to first row.
Definition: matrix.hh:610
Implements a matrix constructed from a given type representing a field and compile-time given number ...
const char * what() const noexcept override
output internal message buffer
Definition: exceptions.cc:35
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
void bilu_backsolve(const M &A, X &v, const Y &d)
LU backsolve with stored inverse.
Definition: ilu.hh:95
void bilu_decomposition(const M &A, int n, M &ILU)
Definition: ilu.hh:169
void bilu0_decomposition(M &A)
compute ILU decomposition of A. A is overwritten by its decomposition
Definition: ilu.hh:34
decltype(auto) lane(std::size_t l, V &&v)
Extract an element of a SIMD type.
Definition: interface.hh:322
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:233
void convertToCRS(const M &A, CRS &lower, CRS &upper, InvVector &inv)
convert ILU decomposition into CRS format for lower and upper triangular and inverse.
Definition: ilu.hh:310
Dune namespace.
Definition: alignedallocator.hh:14
Implements a scalar matrix view wrapper around an existing scalar.
Implements a scalar vector view wrapper around an existing scalar.
Whether this type acts as a scalar in the context of (hierarchically blocked) containers.
Definition: typetraits.hh:163
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)