PreconditionerWrapper.hpp
Go to the documentation of this file.
1#ifndef OPM_MIXED_PREC_HEADER_INCLUDED
2#define OPM_MIXED_PREC_HEADER_INCLUDED
3
5
6namespace Opm {
7
14template <class M, class X, class Y>
16{
17 public:
18
19 using domain_type = X;
20 static constexpr auto block_size = domain_type::block_type::dimension;
21
26 MixedPreconditioner(const M& A, bool use_dilu = false)
27 {
28 // Access double precision matrix data
29 int nrows = A.N();
30 int nnz = A.nonzeroes();
31 double_data_ = &A[0][0][0][0];
32 prec_ = prec_alloc();
33
34 // allocate and initialize mixed-precision matrix
35 mixed_matrix_ = bsr_alloc();
36 bsr_init(mixed_matrix_, nrows, nnz, block_size);
37
38 // copy sparsity pattern from double-precision matrix
39 int *rows = mixed_matrix_->rowptr;
40 int *cols = mixed_matrix_->colidx;
41
42 int irow = 0;
43 int icol = 0;
44 rows[0] = 0;
45 for(auto row=A.begin(); row!=A.end(); row++)
46 {
47 for(auto col = row->begin(); col != row->end(); ++col)
48 {
49 cols[icol++] = col.index();
50 }
51 rows[irow+1] = icol;
52 irow++;
53 }
54
55 // allocate and initialize preconditioner
56 prec_init(prec_,mixed_matrix_);
57
58 // attribute initialization
59 nnz_ = nnz;
60 use_dilu_ = use_dilu;
61
62 // perform matrix factorization
63 update();
64 };
65
68 {
69 bsr_free(mixed_matrix_);
70 prec_free(prec_);
71 }
72
77 void update() override;
78
83 void apply ([[maybe_unused]] X& x, [[maybe_unused]] const Y& y) override;
84
86 Dune::SolverCategory::Category category() const override { return Dune::SolverCategory::sequential; };
87
88 bool hasPerfectUpdate() const override {return true;}
89
90 void pre ([[maybe_unused]] X& x, [[maybe_unused]] Y& y) override {};
91 void post ([[maybe_unused]] X& x) override {};
92
93 private:
94 bool use_dilu_;
95 double const *double_data_;
96 bsr_matrix *mixed_matrix_;
97 prec_t *prec_;
98 int nnz_;
99
100
107 void matvec_mul(double *y, float const *A, double const * x);
108
115 void matvec_mulsub(double *y, float const *A, double const * x);
116
121 void mat_copy(double *C, double const * A);
122
128 void mat_inv(double *invA, const double *A);
129
135 void mat_mulsub(double *C, double const *A, double const * B);
136
141 void mat_rmul(double *C, double const *A);
142
147 void mat_lmul(double const *A, double *C);
148};
149
158template <class M, class X, class Y>
160update ()
161{
162 // transpose each dense block to make them column-major
163 constexpr int N = block_size;
164 constexpr int NN=N*N;
165
166 double B[NN];
167 for(int k=0;k<nnz_;k++)
168 {
169 for(int i=0;i<N;i++) for(int j=0;j<N;j++) B[N*j+i] = double_data_[NN*k + N*i + j];
170 for(int i=0;i<NN;i++) mixed_matrix_->dbl[NN*k + i] = B[i];
171 }
172
173 if constexpr(N==1){OPM_THROW(std::invalid_argument, "MixedMatrixPreconditioner::update does not support block size == 1!\n");}
174 else if constexpr(N==2) prec_ilu0_factorize2(prec_, mixed_matrix_, use_dilu_);
175 else if constexpr(N==3) prec_ilu0_factorize3(prec_, mixed_matrix_, use_dilu_);
176 else if constexpr(N==4) prec_ilu0_factorize4(prec_, mixed_matrix_, use_dilu_);
177 else
178 {
179 bsr_matrix const *A = mixed_matrix_;
180 bsr_matrix *L=prec_->L;
181 bsr_matrix *D=prec_->D;
182 bsr_matrix *U=prec_->U;
183
184 int const nrows = A->nrows;
185
186 // Splitting values of A into L, D, and U, respectively
187 int kU=0;
188 for(int i=0;i<nrows;i++)
189 {
190 for (int k=A->rowptr[i];k<A->rowptr[i+1];k++)
191 {
192 int j=A->colidx[k];
193 if(j<i) // struct-transpose of L
194 {
195 int kL = L->rowptr[j];
196 mat_copy(L->dbl + NN*kL, A->dbl + NN*k);
197 L->rowptr[j]++;
198 }
199 else if(j==i) // struct-copy of D
200 {
201 mat_copy(D->dbl + NN*i, A->dbl + NN*k);
202 }
203 else if(j>i) // struct-copy of U
204 {
205 mat_copy(U->dbl + NN*kU, A->dbl + NN*k);
206 kU++;
207 }
208 }
209 }
210 // reset rowptr of L
211 for(int i=nrows;i>0;i--) L->rowptr[i]=L->rowptr[i-1];
212 L->rowptr[0]=0;
213
214 // Factorizing
215 int idx=0;
216 int next = prec_->offsets[idx][0];
217 double scale[NN];
218 for(int i=0;i<A->nrows;i++)
219 {
220 mat_inv(scale,D->dbl+i*NN);
221 mat_copy(D->dbl+NN*i, scale); //store inverse instead to simplify application
222 for(int k=L->rowptr[i];k<L->rowptr[i+1];k++)
223 {
224 //scale column i of L
225 mat_rmul(L->dbl+k*NN,scale);
226
227 //update diagonal D
228 int j=L->colidx[k];
229 mat_mulsub(D->dbl+j*NN,L->dbl+k*NN,U->dbl+k*NN);
230 }
231
232 if (!use_dilu_)
233 while(next<U->rowptr[i+1])
234 {
235 int ij = prec_->offsets[idx][0];
236 int ik = prec_->offsets[idx][1];
237 int jk = prec_->offsets[idx][2];
238
239 //update off-diagonals L and U
240 mat_mulsub(U->dbl+jk*NN,L->dbl+ij*NN,U->dbl+ik*NN);
241 mat_mulsub(L->dbl+jk*NN,L->dbl+ik*NN,U->dbl+ij*NN);
242
243 //update marker
244 next=prec_->offsets[++idx][0];
245 }
246
247 for(int k=L->rowptr[i];k<L->rowptr[i+1];k++)
248 {
249 //scale row i of U
250 mat_lmul(scale,U->dbl+k*NN);
251 }
252 }
253 //prec_test(); getchar();
254 }
255
256 prec_downcast(prec_);
257}
258
267template <class M, class X, class Y>
269apply ([[maybe_unused]] X& x, [[maybe_unused]] const Y& y)
270{
271 x=y;
272
273 int const b = block_size;
274 if constexpr(b==1){OPM_THROW(std::invalid_argument, "MixedMatrixPreconditioner::apply does not support block size == 1!\n");}
275 else if constexpr(b==2) prec_mapply2c(prec_,&x[0][0]);
276 else if constexpr(b==3) prec_mapply3c(prec_,&x[0][0]);
277 else if constexpr(b==4) prec_mapply4c(prec_,&x[0][0]);
278 else //if constexpr(b==4)
279 {
280 bsr_matrix const *L = prec_->L;
281 bsr_matrix const *D = prec_->D;
282 bsr_matrix const *U = prec_->U;
283
284 int const N = block_size;
285 int const NN = N*N;
286
287 // Lower triangular solve assuming ones on diagonal
288 for(int i=0;i<L->ncols;i++)
289 {
290 double *xi = &x[0][0]+N*i;
291 for(int k=L->rowptr[i];k<L->rowptr[i+1];k++)
292 {
293 const float *A = L->flt+k*NN;
294 int j=U->colidx[k]; // should be L
295 double *xj = &x[0][0]+N*j;
296 matvec_mulsub(xj,A,xi);
297 }
298
299 // Muliply by (inverse) diagonal block
300 const float *A = D->flt+i*NN;
301 matvec_mul(xi,A,xi);
302 }
303
304 // Upper triangular solve assuming ones on diagonal`
305 for(int i=U->ncols;i>0;i--)
306 {
307 double *xi = &x[0][0]+N*(i-1);
308 for(int k=U->rowptr[i]-1;k>U->rowptr[i-1]-1;k--)
309 {
310 const float *A = U->flt+k*NN;
311 int j=U->colidx[k];
312 double const *xj =&x[0][0]+N*j;
313 matvec_mulsub(xi,A,xj);
314 }
315 }
316
317 }
318}
319
326template <class M, class X, class Y>
328matvec_mul(double *y, float const *A, double const * x)
329{
330 int const N = block_size;
331 double z[N];
332 for(int i=0;i<N;i++) z[i] = 0.0;
333 for(int j=0;j<N;j++)
334 {
335 double xj = x[j];
336 for(int i=0;i<N;i++) z[i] += A[i+N*j]*xj;
337 }
338 for(int i=0;i<N;i++) y[i] = z[i];
339}
340
347template <class M, class X, class Y>
348void MixedPreconditioner<M,X,Y>::
349matvec_mulsub(double *y, float const *A, double const * x)
350{
351 int const N = block_size;
352 double z[N];
353 for(int i=0;i<N;i++) z[i] = 0.0;
354 for(int j=0;j<N;j++)
355 {
356 double xj = x[j];
357 for(int i=0;i<N;i++) z[i] += A[i+N*j]*xj;
358 }
359 for(int i=0;i<N;i++) y[i] -= z[i];
360}
361
366template <class M, class X, class Y>
367void MixedPreconditioner<M,X,Y>::
368mat_copy(double *C, double const * A)
369{
370 int const N = block_size;
371 int const NN =N*N;
372 for(int i=0;i<NN;i++) C[i] = A[i];
373}
374
382template <class M, class X, class Y>
383void MixedPreconditioner<M,X,Y>::
384mat_inv(double *invA, const double *A)
385{
386 int const N = block_size;
387 int const NN =N*N;
388 double T[NN];
389 mat_copy(T,A);
390
391 for(int k=0;k<N;k++)
392 {
393 double scale=-1.0/T[(N+1)*k];
394 for(int i=0;i<N;i++) T[i+N*k] *= i==k?0:scale; // scale column k
395 for(int j=0;j<N;j++)
396 {
397 if (j==k) continue;
398 for(int i=0;i<N;i++) T[i+N*j] += i==k?0:T[i+N*k]*T[k+N*j]; //sweep
399 }
400 scale=-scale;
401 for(int j=0;j<N;j++) T[k+N*j] *= scale; // scale row k
402 T[(N+1)*k] = scale;
403 }
404 mat_copy(invA,T);
405}
406
412template <class M, class X, class Y>
413void MixedPreconditioner<M,X,Y>::
414mat_mulsub(double *C, double const *A, double const * B)
415{
416 int const N = block_size;
417 double z[N];
418 for(int j=0;j<N;j++)
419 {
420 for(int k=0;k<N;k++) z[k] = 0.0;
421 for(int k=0;k<N;k++)
422 {
423 double xk = B[k+N*j];
424 for(int i=0;i<N;i++) z[i] += A[i+N*k]*xk;
425 }
426 for(int i=0;i<N;i++) C[i+N*j] -= z[i];
427 }
428}
429
434template <class M, class X, class Y>
435void MixedPreconditioner<M,X,Y>::
436mat_rmul(double *C, double const *A)
437{
438 int const N = block_size;
439 int const NN =N*N;
440 double T[NN];
441 for(int j=0;j<N;j++)
442 {
443 for(int k=0;k<N;k++) T[k+N*j] = 0.0;
444 for(int k=0;k<N;k++)
445 {
446 double xk = A[k+N*j];
447 for(int i=0;i<N;i++) T[i+N*j] += C[i+N*k]*xk;
448 }
449 }
450 mat_copy(C,T);
451}
452
457template <class M, class X, class Y>
458void MixedPreconditioner<M,X,Y>::
459mat_lmul(double const *A, double *C)
460{
461 int const N = block_size;
462 double z[N];
463 for(int j=0;j<N;j++)
464 {
465 for(int k=0;k<N;k++) z[k] = 0.0;
466 for(int k=0;k<N;k++)
467 {
468 double xk = C[k+N*j];
469 for(int i=0;i<N;i++) z[i] += A[i+N*k]*xk;
470 }
471 for(int i=0;i<N;i++) C[i+N*j] = z[i];
472 }
473}
474
475
476}
477#endif // OPM_MIXED_PREC_HEADER_INCLUDED
bsr_matrix * bsr_alloc(void)
Create empty bsr matrix.
void bsr_free(bsr_matrix *A)
Delete bsr matrix.
void bsr_init(bsr_matrix *A, int nrows, int nnz, int b)
Initialize bsr matrix.
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:34
Wraps c-implementation of mixed-precision preconditioner.
Definition: PreconditionerWrapper.hpp:16
bool hasPerfectUpdate() const override
Definition: PreconditionerWrapper.hpp:88
Dune::SolverCategory::Category category() const override
Solver category.
Definition: PreconditionerWrapper.hpp:86
void pre(X &x, Y &y) override
Definition: PreconditionerWrapper.hpp:90
MixedPreconditioner(const M &A, bool use_dilu=false)
constructor
Definition: PreconditionerWrapper.hpp:26
void apply(X &x, const Y &y) override
Mixed-precision ilu0/dilu application.
Definition: PreconditionerWrapper.hpp:269
X domain_type
Definition: PreconditionerWrapper.hpp:19
void post(X &x) override
Definition: PreconditionerWrapper.hpp:91
void update() override
Update ilu0/dilu factorization.
Definition: PreconditionerWrapper.hpp:160
~MixedPreconditioner()
destructor
Definition: PreconditionerWrapper.hpp:67
static constexpr auto block_size
Definition: PreconditionerWrapper.hpp:20
Definition: blackoilbioeffectsmodules.hh:45
void prec_ilu0_factorize4(prec_t *P, bsr_matrix *A, bool use_dilu)
void prec_mapply3c(prec_t *P, double *x)
void prec_free(prec_t *P)
Delete preconditioner object.
void prec_mapply4c(prec_t *P, double *x)
void prec_downcast(prec_t *P)
Make single-precision copy of double-precision values.
void prec_ilu0_factorize3(prec_t *P, bsr_matrix *A, bool use_dilu)
prec_t * prec_alloc()
Create empty preconditioner object.
void prec_ilu0_factorize2(prec_t *P, bsr_matrix *A, bool use_dilu)
ILU0/DILU factorization.
void prec_init(prec_t *P, bsr_matrix const *A)
Initialize preconditioner object.
void prec_mapply2c(prec_t *P, double *x)
Preconditioner application in mixed-precision.
Mixed-precision bsr matrix.
Definition: bsr.h:12
float * flt
Definition: bsr.h:29
int * colidx
Definition: bsr.h:25
double * dbl
Definition: bsr.h:27
int ncols
Definition: bsr.h:16
int * rowptr
Definition: bsr.h:23
int nrows
Definition: bsr.h:14
Preconditioner struct.
Definition: prec.h:15