Dune Core Modules (2.7.1)

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 
11 #include <dune/common/fmatrix.hh>
14 #include "istlexception.hh"
15 
20 namespace Dune {
21 
26  class MatrixBlockError : public virtual Dune::FMatrixError {
27  public:
28  int r, c;
29  };
30 
31 
33  template<class M>
34  void bilu0_decomposition (M& A)
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
255  bilu0_decomposition(ILU);
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.80.0 (May 9, 22:29, 2024)