OpenCAEPoro  0.2.0 Sep/22/2022
A simulator for multicomponent porous media flow
Decoupling.cpp
Go to the documentation of this file.
1 
12 #include "DenseMat.hpp"
13 #include "FaspSolver.hpp"
14 
15 // ABF decoupling method
16 static void decouple_abf(dBSRmat* A, REAL* diaginv, dBSRmat* B)
17 {
18  // members of A
19  const INT ROW = A->ROW;
20  const INT NNZ = A->NNZ;
21  const INT nb = A->nb;
22  const INT nb2 = nb * nb;
23  const INT* IA = A->IA;
24  const INT* JA = A->JA;
25  REAL* val = A->val;
26 
27  INT i, k, m, j;
28 
29  // Create a link to dBSRmat 'B'
30  INT* IAb = B->IA;
31  INT* JAb = B->JA;
32  REAL* valb = B->val;
33  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
34  memcpy(JAb, JA, NNZ * sizeof(INT));
35 
36  for (i = 0; i < ROW; ++i) {
37  // get the diagonal sub-blocks D and their inverse
38  for (k = IA[i]; k < IA[i + 1]; ++k) {
39  if (JA[k] == i) {
40  memcpy(diaginv + i * nb2, val + k * nb2, nb2 * sizeof(REAL));
41  fasp_smat_inv(diaginv + i * nb2, nb);
42  }
43  }
44  // compute D^{-1}*A
45  for (k = IA[i]; k < IA[i + 1]; ++k) {
46  m = k * nb2;
47  j = JA[k];
48  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
49  }
50  } // end of main loop
51 }
52 
53 // Analytical decoupling method
54 static void decouple_anl(dBSRmat* A, REAL* diaginv, dBSRmat* B)
55 {
56  // members of A
57  const INT ROW = A->ROW;
58  const INT NNZ = A->NNZ;
59  const INT nb = A->nb;
60  const INT nb2 = nb * nb;
61  const INT* IA = A->IA;
62  const INT* JA = A->JA;
63  REAL* val = A->val;
64 
65  INT i, k, m, j;
66 
67  // Create a dBSRmat 'B'
68  INT* IAb = B->IA;
69  INT* JAb = B->JA;
70  REAL* valb = B->val;
71  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
72  memcpy(JAb, JA, NNZ * sizeof(INT));
73 
74  for (i = 0; i < ROW; ++i) {
75  // form the diagonal sub-blocks for analytical decoupling
76  for (k = IA[i]; k < IA[i + 1]; ++k) {
77  if (JA[k] == i) {
78  m = k * nb2;
79  fasp_smat_identity(diaginv + i * nb2, nb, nb2);
80  for (int l = 0; l < nb - 1; l++)
81  diaginv[i * nb2 + 1 + l] = -val[m + 1 + l];
82  }
83  }
84 
85  // compute D^{-1}*A
86  for (k = IA[i]; k < IA[i + 1]; ++k) {
87  m = k * nb2;
88  j = JA[k];
89  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
90  }
91  } // end of main loop
92 }
93 
94 static void decouple_truetrans(dBSRmat* A, REAL* diaginv, dBSRmat* B)
95 {
96  // members of A
97  const INT ROW = A->ROW;
98  const INT NNZ = A->NNZ;
99  const INT nb = A->nb;
100  const INT nb2 = nb * nb;
101  const INT* IA = A->IA;
102  const INT* JA = A->JA;
103  REAL* val = A->val;
104 
105  INT i, j, k, l, m;
106 
107  // Create a dBSRmat 'B'
108  INT* IAb = B->IA;
109  INT* JAb = B->JA;
110  REAL* valb = B->val;
111  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
112  memcpy(JAb, JA, NNZ * sizeof(INT));
113 
114  REAL *mat1, *mat2;
115  mat1 = new REAL[nb2];
116  mat2 = new REAL[nb2];
117 
118  // Dset0(nb2*ROW, diaginv);
119  for (i = 0; i < ROW; ++i) {
120  double Tt = 0.0;
121  // get the diagonal sub-blocks
122  // mat2 is true-IMPES matrix.
123  fasp_smat_identity(mat2, nb, nb2);
124  // mat1 is the mobility ratio matrix
125  fasp_smat_identity(mat1, nb, nb2);
126 
127  for (l = 1; l < nb; ++l) {
128  mat2[l] = diaginv[i * nb2 + l];
129  Tt += diaginv[i * nb2 + l] * diaginv[i * nb2 + l * nb];
130  }
131  for (k = IA[i]; k < IA[i + 1]; ++k) {
132  if (JA[k] == i) break;
133  }
134  for (l = 0; l < nb - 1; ++l) {
135  if (val[k * nb2 + (l + 1) * nb] > 0)
136  mat1[(l + 1) * nb] = -diaginv[i * nb2 + (l + 1) * nb] / Tt; // diag(l)
137  }
138  DaABpbC(nb, nb, nb, 1, mat1, mat2, 0, diaginv + i * nb2);
139 
140  // compute D^{-1}*A
141  for (k = IA[i]; k < IA[i + 1]; ++k) {
142  m = k * nb2;
143  j = JA[k];
144  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
145  }
146  } // end of main loop
147 
148  delete mat1;
149  delete mat2;
150 }
151 
152 static void decouple_truetrans_alg(dBSRmat* A, REAL* diaginv, dBSRmat* B)
153 {
154  // members of A
155  const INT ROW = A->ROW;
156  const INT NNZ = A->NNZ;
157  const INT nb = A->nb;
158  const INT nb2 = nb * nb;
159  const INT* IA = A->IA;
160  const INT* JA = A->JA;
161  REAL* val = A->val;
162 
163  INT i, j, k, l, m;
164 
165  // Create a link to dBSRmat 'B'
166  INT* IAb = B->IA;
167  INT* JAb = B->JA;
168  REAL* valb = B->val;
169  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
170  memcpy(JAb, JA, NNZ * sizeof(INT));
171 
172  REAL *mat1, *mat2;
173  mat1 = new REAL[nb2];
174  mat2 = new REAL[nb2];
175 
176  // Dset0(nb2*ROW, diaginv);
177  for (i = 0; i < ROW; ++i) {
178  for (k = IA[i]; k < IA[i + 1]; ++k) {
179  double Tt = 0.0;
180  if (JA[k] == i) {
181  m = k * nb2;
182  fasp_smat_identity(mat2, nb, nb2);
183  for (l = 1; l < nb; ++l) {
184  mat2[l] = -val[m + l];
185  if (val[m + l * nb] > 0) {
186  Tt += -val[m + l] * val[m + l * nb];
187  }
188  }
189 
190  fasp_smat_identity(mat1, nb, nb2);
191  for (l = 1; l < nb; ++l) {
192  if (val[m + l * nb] > 0) {
193  mat1[l * nb] = -val[m + l * nb] / Tt; // diag(l)
194  }
195  }
196 
197  DaABpbC(nb, nb, nb, 1, mat1, mat2, 0, diaginv + i * nb2);
198  }
199  }
200 
201  // compute D^{-1}*A
202  for (k = IA[i]; k < IA[i + 1]; ++k) {
203  m = k * nb2;
204  j = JA[k];
205  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
206  }
207  } // end of main loop
208 
209  delete mat1;
210  delete mat2;
211 }
212 
213 // Semi-analytical decoupling method
214 static void decouple_abftrue(dBSRmat* A, REAL* diaginv, dBSRmat* B)
215 {
216  // members of A
217  const INT ROW = A->ROW;
218  const INT NNZ = A->NNZ;
219  const INT nb = A->nb;
220  const INT nb2 = nb * nb;
221  const INT* IA = A->IA;
222  const INT* JA = A->JA;
223  REAL* val = A->val;
224 
225  INT i, k, m, j;
226 
227  // Create a dBSRmat 'B'
228  INT* IAb = B->IA;
229  INT* JAb = B->JA;
230  REAL* valb = B->val;
231  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
232  memcpy(JAb, JA, NNZ * sizeof(INT));
233 
234  for (i = 0; i < ROW; ++i) {
235  // get the diagonal sub-blocks
236  for (k = IA[i]; k < IA[i + 1]; ++k) {
237  if (JA[k] == i) {
238  // Form the ABF part first
239  memcpy(diaginv + i * nb2, val + k * nb2, nb2 * sizeof(REAL));
240  fasp_smat_inv(diaginv + i * nb2, nb);
241  // Replace the first line with analytical decoupling
242  m = k * nb2;
243  diaginv[i * nb2] = 1;
244  for (int l = 0; l < nb - 1; l++)
245  diaginv[i * nb2 + 1 + l] = -val[m + 1 + l];
246  }
247  }
248 
249  // compute D^{-1}*A
250  for (k = IA[i]; k < IA[i + 1]; ++k) {
251  m = k * nb2;
252  j = JA[k];
253  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
254  }
255  } // end of main loop
256 }
257 
258 static void decouple_true_scale(dBSRmat* A, REAL* diaginv, dBSRmat* B)
259 {
260  // members of A
261  const INT ROW = A->ROW;
262  const INT NNZ = A->NNZ;
263  const INT nb = A->nb;
264  const INT nb2 = nb * nb;
265  const INT* IA = A->IA;
266  const INT* JA = A->JA;
267  REAL* val = A->val;
268 
269  INT i, k, m, j;
270 
271  // Create a dBSRmat 'B'
272  INT* IAb = B->IA;
273  INT* JAb = B->JA;
274  REAL* valb = B->val;
275  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
276  memcpy(JAb, JA, NNZ * sizeof(INT));
277 
278  for (i = 0; i < ROW; ++i) {
279  // get the diagonal sub-blocks
280  for (k = IA[i]; k < IA[i + 1]; ++k) {
281  if (JA[k] == i) {
282  m = k * nb2;
283  fasp_smat_identity(diaginv + i * nb2, nb, nb2);
284  diaginv[i * nb2] = 1 / val[m];
285  for (int l = 0; l < nb - 1; l++)
286  diaginv[i * nb2 + 1 + l] = -val[m + 1 + l] / val[m];
287  }
288  }
289 
290  // compute D^{-1}*A
291  for (k = IA[i]; k < IA[i + 1]; ++k) {
292  m = k * nb2;
293  j = JA[k];
294  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
295  }
296  } // end of main loop
297 }
298 
299 static void decouple_rotate(dBSRmat* A, REAL* diaginv, dBSRmat* B)
300 {
301  // members of A
302  const INT ROW = A->ROW;
303  const INT NNZ = A->NNZ;
304  const INT nb = A->nb;
305  const INT nb2 = nb * nb;
306  const INT* IA = A->IA;
307  const INT* JA = A->JA;
308  REAL* val = A->val;
309 
310  INT i, k, m, j;
311 
312  // Create a dBSRmat 'B'
313  INT* IAb = B->IA;
314  INT* JAb = B->JA;
315  REAL* valb = B->val;
316  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
317  memcpy(JAb, JA, NNZ * sizeof(INT));
318 
319  for (i = 0; i < ROW; ++i) {
320  // get the diagonal sub-blocks
321  for (k = IA[i]; k < IA[i + 1]; ++k) {
322  if (JA[k] == i) {
323  m = k * nb2;
324  for (int li = 0; li < nb; li++) {
325  for (int lj = 0; lj < nb; lj++) {
326  diaginv[i * nb2 + li * nb + lj] = 0;
327  if (lj - li == 1) {
328  diaginv[i * nb2 + li * nb + lj] = 1;
329  }
330  if (lj == 0 && li == nb - 1) {
331  diaginv[i * nb2 + li * nb + lj] = 1;
332  }
333  }
334  }
335  }
336  }
337 
338  // compute D^{-1}*A
339  for (k = IA[i]; k < IA[i + 1]; ++k) {
340  m = k * nb2;
341  j = JA[k];
342  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
343  }
344  } // end of main loop
345 }
346 
347 // Quasi-IMPES decoupling method
348 static void decouple_quasi(dBSRmat* A, REAL* diaginv, dBSRmat* B)
349 {
350  // members of A
351  const INT ROW = A->ROW;
352  const INT NNZ = A->NNZ;
353  const INT nb = A->nb;
354  const INT nb2 = nb * nb;
355  const INT* IA = A->IA;
356  const INT* JA = A->JA;
357  REAL* val = A->val;
358 
359  INT i, k, m, j;
360 
361  INT* IAb = B->IA;
362  INT* JAb = B->JA;
363  REAL* valb = B->val;
364  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
365  memcpy(JAb, JA, NNZ * sizeof(INT));
366 
367  for (i = 0; i < ROW; ++i) {
368  // get the diagonal sub-blocks
369  for (k = IA[i]; k < IA[i + 1]; ++k) {
370  if (JA[k] == i) {
371  m = k * nb2;
372  fasp_smat_identity(diaginv + i * nb2, nb, nb2);
373  for (int l = 0; l < nb - 1; l++)
374  diaginv[i * nb2 + 1 + l] =
375  -val[m + 1 + l] / val[m + (l + 1) * nb + l + 1];
376  }
377  }
378 
379  // compute D^{-1}*A
380  for (k = IA[i]; k < IA[i + 1]; ++k) {
381  m = k * nb2;
382  j = JA[k];
383  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
384  }
385  } // end of main loop
386 }
387 
388 // What's the difference with decouple_anl?
389 static void decouple_trueabf(dBSRmat* A, REAL* diaginv, dBSRmat* B)
390 {
391  // members of A
392  const INT ROW = A->ROW;
393  const INT NNZ = A->NNZ;
394  const INT nb = A->nb;
395  const INT nb2 = nb * nb;
396  const INT* IA = A->IA;
397  const INT* JA = A->JA;
398  REAL* val = A->val;
399 
400  INT i, k, m, j;
401 
402  INT* IAb = B->IA;
403  INT* JAb = B->JA;
404  REAL* valb = B->val;
405  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
406  memcpy(JAb, JA, NNZ * sizeof(INT));
407 
408  for (i = 0; i < ROW; ++i) {
409  // get the diagonal sub-blocks
410  for (k = IA[i]; k < IA[i + 1]; ++k) {
411  if (JA[k] == i) {
412  m = k * nb2;
413  fasp_smat_identity(diaginv + i * nb2, nb, nb2);
414  for (int l = 0; l < nb; l++) diaginv[i * nb2 + l] = val[m + l];
415  fasp_smat_inv(diaginv + i * nb2, nb);
416  }
417  }
418 
419  // compute D^{-1}*A
420  for (k = IA[i]; k < IA[i + 1]; ++k) {
421  m = k * nb2;
422  j = JA[k];
423  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
424  }
425  } // end of main loop
426 }
427 
428 static void decouple_rowsum(dBSRmat* A, REAL* diaginv, dBSRmat* B)
429 {
430  // members of A
431  const INT ROW = A->ROW;
432  const INT NNZ = A->NNZ;
433  const INT nb = A->nb;
434  const INT nb2 = nb * nb;
435  const INT* IA = A->IA;
436  const INT* JA = A->JA;
437  REAL* val = A->val;
438 
439  INT i, k, m, j;
440 
441  // Variables for OpenMP
442  INT* IAb = B->IA;
443  INT* JAb = B->JA;
444  REAL* valb = B->val;
445  memcpy(IAb, IA, (ROW + 1) * sizeof(INT));
446  memcpy(JAb, JA, NNZ * sizeof(INT));
447 
448  for (i = 0; i < ROW; ++i) {
449  // get the diagonal sub-blocks
450  for (k = IA[i]; k < IA[i + 1]; ++k) {
451  if (JA[k] == i) {
452  m = k * nb2;
453  fasp_smat_identity(diaginv + i * nb2, nb, nb2);
454  for (int l = 0; l < nb - 1; l++) diaginv[i * nb2 + 1 + l] = 1;
455  }
456  }
457 
458  // compute D^{-1}*A
459  for (k = IA[i]; k < IA[i + 1]; ++k) {
460  m = k * nb2;
461  j = JA[k];
462  fasp_blas_smat_mul(diaginv + i * nb2, val + m, valb + m, nb);
463  }
464  } // end of main loop
465 }
466 
468 void VectorFaspSolver::Decoupling(dBSRmat* Absr, dvector* b, dBSRmat* Asc, dvector* fsc,
469  ivector* order, double* Dmatvec, int decoupleType)
470 {
471  int nrow = Absr->ROW;
472  int nb = Absr->nb;
473  double* Dmat = Dmatvec;
474  precond_diag_bsr diagA;
475 
476  // Natural ordering
477  for (int i = 0; i < nrow; ++i) order->val[i] = i;
478 
479  // Without decoupling
480  if (decoupleType == 0) {
481  fasp_dbsr_cp(Absr, Asc); // Asc = Absr;
482  fasp_dvec_cp(b, fsc); // fsc = b;
483  return;
484  }
485 
486  // With decoupling
487  switch (decoupleType) {
488  case 2:
489  decouple_anl(Absr, Dmat, Asc);
490  break;
491  case 3:
492  decouple_quasi(Absr, Dmat, Asc);
493  break;
494  case 4:
495  decouple_trueabf(Absr, Dmat, Asc);
496  break;
497  case 5:
498  decouple_abftrue(Absr, Dmat, Asc);
499  break;
500  case 6:
501  decouple_abftrue(Absr, Dmat, Asc);
502  break;
503  case 7:
504  decouple_truetrans_alg(Absr, Dmat, Asc);
505  break;
506  case 8:
507  decouple_truetrans(Absr, Dmat, Asc);
508  break;
509  case 9:
510  decouple_true_scale(Absr, Dmat, Asc);
511  break;
512  case 10:
513  decouple_rotate(Absr, Dmat, Asc);
514  break;
515  default: // case 1:
516  decouple_abf(Absr, Dmat, Asc);
517  }
518 
519  diagA.diag.row = nrow * nb * nb;
520  diagA.diag.val = Dmat;
521  diagA.nb = nb;
522  fasp_precond_dbsr_diag(b->val, fsc->val, &diagA);
523 }
524 
525 /*----------------------------------------------------------------------------*/
526 /* Brief Change History of This File */
527 /*----------------------------------------------------------------------------*/
528 /* Author Date Actions */
529 /*----------------------------------------------------------------------------*/
530 /* Shizhe Li Oct/15/2021 Create file */
531 /* Chensong Zhang Nov/09/2021 Restruct decoupling methods */
532 /* Chensong Zhang Nov/30/2021 Add null decoupling */
533 /*----------------------------------------------------------------------------*/
Operations about small dense mat.
void DaABpbC(const int &m, const int &n, const int &k, const double &alpha, const double *A, const double *B, const double &beta, double *C)
Computes C' = alpha B'A' + beta C', all matrices are column-major.
Definition: DenseMat.cpp:76
Declaration of classes interfacing to the FASP solvers.