xref: /petsc/src/mat/impls/blockmat/seq/blockmat.c (revision 1cc06b555e92f8ec64db10330b8bbd830e5bc876)
1421e10b8SBarry Smith 
2421e10b8SBarry Smith /*
3421e10b8SBarry Smith    This provides a matrix that consists of Mats
4421e10b8SBarry Smith */
5421e10b8SBarry Smith 
6af0996ceSBarry Smith #include <petsc/private/matimpl.h>          /*I "petscmat.h" I*/
7c6db04a5SJed Brown #include <../src/mat/impls/baij/seq/baij.h> /* use the common AIJ data-structure */
8421e10b8SBarry Smith 
9421e10b8SBarry Smith typedef struct {
10421e10b8SBarry Smith   SEQAIJHEADER(Mat);
11421e10b8SBarry Smith   SEQBAIJHEADER;
12ccb205f8SBarry Smith   Mat *diags;
13421e10b8SBarry Smith 
146e63c7a1SBarry Smith   Vec left, right, middle, workb; /* dummy vectors to perform local parts of product */
15421e10b8SBarry Smith } Mat_BlockMat;
16421e10b8SBarry Smith 
17d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSOR_BlockMat_Symmetric(Mat A, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
18d71ae5a4SJacob Faibussowitsch {
19290bbb0aSBarry Smith   Mat_BlockMat      *a = (Mat_BlockMat *)A->data;
20290bbb0aSBarry Smith   PetscScalar       *x;
21a2ea699eSBarry Smith   const Mat         *v;
22290bbb0aSBarry Smith   const PetscScalar *b;
23d0f46423SBarry Smith   PetscInt           n = A->cmap->n, i, mbs = n / A->rmap->bs, j, bs = A->rmap->bs;
24290bbb0aSBarry Smith   const PetscInt    *idx;
25290bbb0aSBarry Smith   IS                 row, col;
26290bbb0aSBarry Smith   MatFactorInfo      info;
276e63c7a1SBarry Smith   Vec                left = a->left, right = a->right, middle = a->middle;
28290bbb0aSBarry Smith   Mat               *diag;
29290bbb0aSBarry Smith 
30290bbb0aSBarry Smith   PetscFunctionBegin;
31290bbb0aSBarry Smith   its = its * lits;
3208401ef6SPierre Jolivet   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " and local its %" PetscInt_FMT " both positive", its, lits);
33aed4548fSBarry Smith   PetscCheck(!(flag & SOR_EISENSTAT), PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for Eisenstat");
3408401ef6SPierre Jolivet   PetscCheck(omega == 1.0, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for omega not equal to 1.0");
3528b400f6SJacob Faibussowitsch   PetscCheck(!fshift, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for fshift");
367a46b595SBarry Smith   PetscCheck(!((flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) && !(flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot do backward sweep without forward sweep");
37290bbb0aSBarry Smith 
38290bbb0aSBarry Smith   if (!a->diags) {
399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mbs, &a->diags));
409566063dSJacob Faibussowitsch     PetscCall(MatFactorInfoInitialize(&info));
41290bbb0aSBarry Smith     for (i = 0; i < mbs; i++) {
429566063dSJacob Faibussowitsch       PetscCall(MatGetOrdering(a->a[a->diag[i]], MATORDERINGND, &row, &col));
439566063dSJacob Faibussowitsch       PetscCall(MatCholeskyFactorSymbolic(a->diags[i], a->a[a->diag[i]], row, &info));
449566063dSJacob Faibussowitsch       PetscCall(MatCholeskyFactorNumeric(a->diags[i], a->a[a->diag[i]], &info));
459566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&row));
469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&col));
47290bbb0aSBarry Smith     }
489566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(bb, &a->workb));
49290bbb0aSBarry Smith   }
50290bbb0aSBarry Smith   diag = a->diags;
51290bbb0aSBarry Smith 
529566063dSJacob Faibussowitsch   PetscCall(VecSet(xx, 0.0));
539566063dSJacob Faibussowitsch   PetscCall(VecGetArray(xx, &x));
54290bbb0aSBarry Smith   /* copy right hand side because it must be modified during iteration */
559566063dSJacob Faibussowitsch   PetscCall(VecCopy(bb, a->workb));
569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(a->workb, &b));
57290bbb0aSBarry Smith 
5841f059aeSBarry Smith   /* need to add code for when initial guess is zero, see MatSOR_SeqAIJ */
59290bbb0aSBarry Smith   while (its--) {
60290bbb0aSBarry Smith     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
61290bbb0aSBarry Smith       for (i = 0; i < mbs; i++) {
626e63c7a1SBarry Smith         n   = a->i[i + 1] - a->i[i] - 1;
636e63c7a1SBarry Smith         idx = a->j + a->i[i] + 1;
646e63c7a1SBarry Smith         v   = a->a + a->i[i] + 1;
65290bbb0aSBarry Smith 
669566063dSJacob Faibussowitsch         PetscCall(VecSet(left, 0.0));
67290bbb0aSBarry Smith         for (j = 0; j < n; j++) {
689566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(right, x + idx[j] * bs));
699566063dSJacob Faibussowitsch           PetscCall(MatMultAdd(v[j], right, left, left));
709566063dSJacob Faibussowitsch           PetscCall(VecResetArray(right));
71290bbb0aSBarry Smith         }
729566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, b + i * bs));
739566063dSJacob Faibussowitsch         PetscCall(VecAYPX(left, -1.0, right));
749566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
75290bbb0aSBarry Smith 
769566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, x + i * bs));
779566063dSJacob Faibussowitsch         PetscCall(MatSolve(diag[i], left, right));
786e63c7a1SBarry Smith 
7941f059aeSBarry Smith         /* now adjust right hand side, see MatSOR_SeqSBAIJ */
806e63c7a1SBarry Smith         for (j = 0; j < n; j++) {
819566063dSJacob Faibussowitsch           PetscCall(MatMultTranspose(v[j], right, left));
829566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(middle, b + idx[j] * bs));
839566063dSJacob Faibussowitsch           PetscCall(VecAXPY(middle, -1.0, left));
849566063dSJacob Faibussowitsch           PetscCall(VecResetArray(middle));
856e63c7a1SBarry Smith         }
869566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
87290bbb0aSBarry Smith       }
88290bbb0aSBarry Smith     }
89290bbb0aSBarry Smith     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
90290bbb0aSBarry Smith       for (i = mbs - 1; i >= 0; i--) {
916e63c7a1SBarry Smith         n   = a->i[i + 1] - a->i[i] - 1;
926e63c7a1SBarry Smith         idx = a->j + a->i[i] + 1;
936e63c7a1SBarry Smith         v   = a->a + a->i[i] + 1;
94290bbb0aSBarry Smith 
959566063dSJacob Faibussowitsch         PetscCall(VecSet(left, 0.0));
96290bbb0aSBarry Smith         for (j = 0; j < n; j++) {
979566063dSJacob Faibussowitsch           PetscCall(VecPlaceArray(right, x + idx[j] * bs));
989566063dSJacob Faibussowitsch           PetscCall(MatMultAdd(v[j], right, left, left));
999566063dSJacob Faibussowitsch           PetscCall(VecResetArray(right));
100290bbb0aSBarry Smith         }
1019566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, b + i * bs));
1029566063dSJacob Faibussowitsch         PetscCall(VecAYPX(left, -1.0, right));
1039566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
104290bbb0aSBarry Smith 
1059566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, x + i * bs));
1069566063dSJacob Faibussowitsch         PetscCall(MatSolve(diag[i], left, right));
1079566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
108290bbb0aSBarry Smith       }
109290bbb0aSBarry Smith     }
110290bbb0aSBarry Smith   }
1119566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(xx, &x));
1129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(a->workb, &b));
1133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114290bbb0aSBarry Smith }
115290bbb0aSBarry Smith 
116d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSOR_BlockMat(Mat A, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
117d71ae5a4SJacob Faibussowitsch {
118ccb205f8SBarry Smith   Mat_BlockMat      *a = (Mat_BlockMat *)A->data;
119ccb205f8SBarry Smith   PetscScalar       *x;
120a2ea699eSBarry Smith   const Mat         *v;
121ccb205f8SBarry Smith   const PetscScalar *b;
122d0f46423SBarry Smith   PetscInt           n = A->cmap->n, i, mbs = n / A->rmap->bs, j, bs = A->rmap->bs;
123ccb205f8SBarry Smith   const PetscInt    *idx;
124ccb205f8SBarry Smith   IS                 row, col;
125ccb205f8SBarry Smith   MatFactorInfo      info;
126ccb205f8SBarry Smith   Vec                left = a->left, right = a->right;
127ccb205f8SBarry Smith   Mat               *diag;
128ccb205f8SBarry Smith 
129ccb205f8SBarry Smith   PetscFunctionBegin;
130ccb205f8SBarry Smith   its = its * lits;
13108401ef6SPierre Jolivet   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " and local its %" PetscInt_FMT " both positive", its, lits);
132aed4548fSBarry Smith   PetscCheck(!(flag & SOR_EISENSTAT), PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for Eisenstat");
13308401ef6SPierre Jolivet   PetscCheck(omega == 1.0, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for omega not equal to 1.0");
13428b400f6SJacob Faibussowitsch   PetscCheck(!fshift, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for fshift");
135ccb205f8SBarry Smith 
136ccb205f8SBarry Smith   if (!a->diags) {
1379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mbs, &a->diags));
1389566063dSJacob Faibussowitsch     PetscCall(MatFactorInfoInitialize(&info));
139ccb205f8SBarry Smith     for (i = 0; i < mbs; i++) {
1409566063dSJacob Faibussowitsch       PetscCall(MatGetOrdering(a->a[a->diag[i]], MATORDERINGND, &row, &col));
1419566063dSJacob Faibussowitsch       PetscCall(MatLUFactorSymbolic(a->diags[i], a->a[a->diag[i]], row, col, &info));
1429566063dSJacob Faibussowitsch       PetscCall(MatLUFactorNumeric(a->diags[i], a->a[a->diag[i]], &info));
1439566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&row));
1449566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&col));
145ccb205f8SBarry Smith     }
146ccb205f8SBarry Smith   }
147ccb205f8SBarry Smith   diag = a->diags;
148ccb205f8SBarry Smith 
1499566063dSJacob Faibussowitsch   PetscCall(VecSet(xx, 0.0));
1509566063dSJacob Faibussowitsch   PetscCall(VecGetArray(xx, &x));
1519566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(bb, &b));
152ccb205f8SBarry Smith 
15341f059aeSBarry Smith   /* need to add code for when initial guess is zero, see MatSOR_SeqAIJ */
154ccb205f8SBarry Smith   while (its--) {
155ccb205f8SBarry Smith     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
156ccb205f8SBarry Smith       for (i = 0; i < mbs; i++) {
157ccb205f8SBarry Smith         n   = a->i[i + 1] - a->i[i];
158ccb205f8SBarry Smith         idx = a->j + a->i[i];
159ccb205f8SBarry Smith         v   = a->a + a->i[i];
160ccb205f8SBarry Smith 
1619566063dSJacob Faibussowitsch         PetscCall(VecSet(left, 0.0));
162ccb205f8SBarry Smith         for (j = 0; j < n; j++) {
163ccb205f8SBarry Smith           if (idx[j] != i) {
1649566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(right, x + idx[j] * bs));
1659566063dSJacob Faibussowitsch             PetscCall(MatMultAdd(v[j], right, left, left));
1669566063dSJacob Faibussowitsch             PetscCall(VecResetArray(right));
167ccb205f8SBarry Smith           }
168ccb205f8SBarry Smith         }
1699566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, b + i * bs));
1709566063dSJacob Faibussowitsch         PetscCall(VecAYPX(left, -1.0, right));
1719566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
172ccb205f8SBarry Smith 
1739566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, x + i * bs));
1749566063dSJacob Faibussowitsch         PetscCall(MatSolve(diag[i], left, right));
1759566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
176ccb205f8SBarry Smith       }
177ccb205f8SBarry Smith     }
178ccb205f8SBarry Smith     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
179ccb205f8SBarry Smith       for (i = mbs - 1; i >= 0; i--) {
180ccb205f8SBarry Smith         n   = a->i[i + 1] - a->i[i];
181ccb205f8SBarry Smith         idx = a->j + a->i[i];
182ccb205f8SBarry Smith         v   = a->a + a->i[i];
183ccb205f8SBarry Smith 
1849566063dSJacob Faibussowitsch         PetscCall(VecSet(left, 0.0));
185ccb205f8SBarry Smith         for (j = 0; j < n; j++) {
186ccb205f8SBarry Smith           if (idx[j] != i) {
1879566063dSJacob Faibussowitsch             PetscCall(VecPlaceArray(right, x + idx[j] * bs));
1889566063dSJacob Faibussowitsch             PetscCall(MatMultAdd(v[j], right, left, left));
1899566063dSJacob Faibussowitsch             PetscCall(VecResetArray(right));
190ccb205f8SBarry Smith           }
191ccb205f8SBarry Smith         }
1929566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, b + i * bs));
1939566063dSJacob Faibussowitsch         PetscCall(VecAYPX(left, -1.0, right));
1949566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
195ccb205f8SBarry Smith 
1969566063dSJacob Faibussowitsch         PetscCall(VecPlaceArray(right, x + i * bs));
1979566063dSJacob Faibussowitsch         PetscCall(MatSolve(diag[i], left, right));
1989566063dSJacob Faibussowitsch         PetscCall(VecResetArray(right));
199ccb205f8SBarry Smith       }
200ccb205f8SBarry Smith     }
201ccb205f8SBarry Smith   }
2029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(xx, &x));
2039566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(bb, &b));
2043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
205ccb205f8SBarry Smith }
206ccb205f8SBarry Smith 
207d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_BlockMat(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
208d71ae5a4SJacob Faibussowitsch {
209421e10b8SBarry Smith   Mat_BlockMat *a = (Mat_BlockMat *)A->data;
210421e10b8SBarry Smith   PetscInt     *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N, lastcol = -1;
211421e10b8SBarry Smith   PetscInt     *imax = a->imax, *ai = a->i, *ailen = a->ilen;
212d0f46423SBarry Smith   PetscInt     *aj = a->j, nonew = a->nonew, bs = A->rmap->bs, brow, bcol;
213421e10b8SBarry Smith   PetscInt      ridx, cidx;
214ace3abfcSBarry Smith   PetscBool     roworiented = a->roworiented;
215421e10b8SBarry Smith   MatScalar     value;
216421e10b8SBarry Smith   Mat          *ap, *aa = a->a;
217421e10b8SBarry Smith 
218421e10b8SBarry Smith   PetscFunctionBegin;
219421e10b8SBarry Smith   for (k = 0; k < m; k++) { /* loop over added rows */
220421e10b8SBarry Smith     row  = im[k];
221421e10b8SBarry Smith     brow = row / bs;
222421e10b8SBarry Smith     if (row < 0) continue;
2236bdcaf15SBarry Smith     PetscCheck(row < A->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->N - 1);
224421e10b8SBarry Smith     rp   = aj + ai[brow];
225421e10b8SBarry Smith     ap   = aa + ai[brow];
226421e10b8SBarry Smith     rmax = imax[brow];
227421e10b8SBarry Smith     nrow = ailen[brow];
228421e10b8SBarry Smith     low  = 0;
229421e10b8SBarry Smith     high = nrow;
230421e10b8SBarry Smith     for (l = 0; l < n; l++) { /* loop over added columns */
231421e10b8SBarry Smith       if (in[l] < 0) continue;
2326bdcaf15SBarry Smith       PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1);
2339371c9d4SSatish Balay       col  = in[l];
2349371c9d4SSatish Balay       bcol = col / bs;
235b94d7dedSBarry Smith       if (A->symmetric == PETSC_BOOL3_TRUE && brow > bcol) continue;
2369371c9d4SSatish Balay       ridx = row % bs;
2379371c9d4SSatish Balay       cidx = col % bs;
2382205254eSKarl Rupp       if (roworiented) value = v[l + k * n];
2392205254eSKarl Rupp       else value = v[k + l * m];
2402205254eSKarl Rupp 
2412205254eSKarl Rupp       if (col <= lastcol) low = 0;
2422205254eSKarl Rupp       else high = nrow;
243421e10b8SBarry Smith       lastcol = col;
244421e10b8SBarry Smith       while (high - low > 7) {
245421e10b8SBarry Smith         t = (low + high) / 2;
246421e10b8SBarry Smith         if (rp[t] > bcol) high = t;
247421e10b8SBarry Smith         else low = t;
248421e10b8SBarry Smith       }
249421e10b8SBarry Smith       for (i = low; i < high; i++) {
250421e10b8SBarry Smith         if (rp[i] > bcol) break;
2512205254eSKarl Rupp         if (rp[i] == bcol) goto noinsert1;
252421e10b8SBarry Smith       }
253421e10b8SBarry Smith       if (nonew == 1) goto noinsert1;
25408401ef6SPierre Jolivet       PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero (%" PetscInt_FMT ", %" PetscInt_FMT ") in the matrix", row, col);
255fef13f97SBarry Smith       MatSeqXAIJReallocateAIJ(A, a->mbs, 1, nrow, brow, bcol, rmax, aa, ai, aj, rp, ap, imax, nonew, Mat);
2569371c9d4SSatish Balay       N = nrow++ - 1;
2579371c9d4SSatish Balay       high++;
258421e10b8SBarry Smith       /* shift up all the later entries in this row */
259421e10b8SBarry Smith       for (ii = N; ii >= i; ii--) {
260421e10b8SBarry Smith         rp[ii + 1] = rp[ii];
261421e10b8SBarry Smith         ap[ii + 1] = ap[ii];
262421e10b8SBarry Smith       }
263f4259b30SLisandro Dalcin       if (N >= i) ap[i] = NULL;
264421e10b8SBarry Smith       rp[i] = bcol;
265421e10b8SBarry Smith       a->nz++;
266e56f5c9eSBarry Smith       A->nonzerostate++;
267421e10b8SBarry Smith     noinsert1:;
26848a46eb9SPierre Jolivet       if (!*(ap + i)) PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, bs, bs, 0, NULL, ap + i));
2699566063dSJacob Faibussowitsch       PetscCall(MatSetValues(ap[i], 1, &ridx, 1, &cidx, &value, is));
270421e10b8SBarry Smith       low = i;
271421e10b8SBarry Smith     }
272421e10b8SBarry Smith     ailen[brow] = nrow;
273421e10b8SBarry Smith   }
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
275421e10b8SBarry Smith }
276421e10b8SBarry Smith 
277d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatLoad_BlockMat(Mat newmat, PetscViewer viewer)
278d71ae5a4SJacob Faibussowitsch {
279a5973382SShri Abhyankar   Mat                tmpA;
280a5973382SShri Abhyankar   PetscInt           i, j, m, n, bs = 1, ncols, *lens, currentcol, mbs, **ii, *ilens, nextcol, *llens, cnt = 0;
281a5973382SShri Abhyankar   const PetscInt    *cols;
282a5973382SShri Abhyankar   const PetscScalar *values;
283ace3abfcSBarry Smith   PetscBool          flg = PETSC_FALSE, notdone;
284a5973382SShri Abhyankar   Mat_SeqAIJ        *a;
285a5973382SShri Abhyankar   Mat_BlockMat      *amat;
286a5973382SShri Abhyankar 
287a5973382SShri Abhyankar   PetscFunctionBegin;
288c98fd787SBarry Smith   /* force binary viewer to load .info file if it has not yet done so */
2899566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetUp(viewer));
2909566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &tmpA));
2919566063dSJacob Faibussowitsch   PetscCall(MatSetType(tmpA, MATSEQAIJ));
2929566063dSJacob Faibussowitsch   PetscCall(MatLoad_SeqAIJ(tmpA, viewer));
293a5973382SShri Abhyankar 
2949566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(tmpA, &m, &n));
295d0609cedSBarry Smith   PetscOptionsBegin(PETSC_COMM_SELF, NULL, "Options for loading BlockMat matrix 1", "Mat");
2969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-matload_block_size", "Set the blocksize used to store the matrix", "MatLoad", bs, &bs, NULL));
2979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matload_symmetric", "Store the matrix as symmetric", "MatLoad", flg, &flg, NULL));
298d0609cedSBarry Smith   PetscOptionsEnd();
299a5973382SShri Abhyankar 
300a5973382SShri Abhyankar   /* Determine number of nonzero blocks for each block row */
301a5973382SShri Abhyankar   a   = (Mat_SeqAIJ *)tmpA->data;
302a5973382SShri Abhyankar   mbs = m / bs;
3039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(mbs, &lens, bs, &ii, bs, &ilens));
3049566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(lens, mbs));
305a5973382SShri Abhyankar 
306a5973382SShri Abhyankar   for (i = 0; i < mbs; i++) {
307a5973382SShri Abhyankar     for (j = 0; j < bs; j++) {
308a5973382SShri Abhyankar       ii[j]    = a->j + a->i[i * bs + j];
309a5973382SShri Abhyankar       ilens[j] = a->i[i * bs + j + 1] - a->i[i * bs + j];
310a5973382SShri Abhyankar     }
311a5973382SShri Abhyankar 
312a5973382SShri Abhyankar     currentcol = -1;
313a5973382SShri Abhyankar     while (PETSC_TRUE) {
314a5973382SShri Abhyankar       notdone = PETSC_FALSE;
315a5973382SShri Abhyankar       nextcol = 1000000000;
316a5973382SShri Abhyankar       for (j = 0; j < bs; j++) {
317a5973382SShri Abhyankar         while ((ilens[j] > 0 && ii[j][0] / bs <= currentcol)) {
318a5973382SShri Abhyankar           ii[j]++;
319a5973382SShri Abhyankar           ilens[j]--;
320a5973382SShri Abhyankar         }
321a5973382SShri Abhyankar         if (ilens[j] > 0) {
322a5973382SShri Abhyankar           notdone = PETSC_TRUE;
323a5973382SShri Abhyankar           nextcol = PetscMin(nextcol, ii[j][0] / bs);
324a5973382SShri Abhyankar         }
325a5973382SShri Abhyankar       }
326a5973382SShri Abhyankar       if (!notdone) break;
327a5973382SShri Abhyankar       if (!flg || (nextcol >= i)) lens[i]++;
328a5973382SShri Abhyankar       currentcol = nextcol;
329a5973382SShri Abhyankar     }
330a5973382SShri Abhyankar   }
331a5973382SShri Abhyankar 
33248a46eb9SPierre Jolivet   if (newmat->rmap->n < 0 && newmat->rmap->N < 0 && newmat->cmap->n < 0 && newmat->cmap->N < 0) PetscCall(MatSetSizes(newmat, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
3339566063dSJacob Faibussowitsch   PetscCall(MatBlockMatSetPreallocation(newmat, bs, 0, lens));
3341baa6e33SBarry Smith   if (flg) PetscCall(MatSetOption(newmat, MAT_SYMMETRIC, PETSC_TRUE));
335a5973382SShri Abhyankar   amat = (Mat_BlockMat *)(newmat)->data;
336a5973382SShri Abhyankar 
337a5973382SShri Abhyankar   /* preallocate the submatrices */
3389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bs, &llens));
339a5973382SShri Abhyankar   for (i = 0; i < mbs; i++) { /* loops for block rows */
340a5973382SShri Abhyankar     for (j = 0; j < bs; j++) {
341a5973382SShri Abhyankar       ii[j]    = a->j + a->i[i * bs + j];
342a5973382SShri Abhyankar       ilens[j] = a->i[i * bs + j + 1] - a->i[i * bs + j];
343a5973382SShri Abhyankar     }
344a5973382SShri Abhyankar 
345a5973382SShri Abhyankar     currentcol = 1000000000;
346a5973382SShri Abhyankar     for (j = 0; j < bs; j++) { /* loop over rows in block finding first nonzero block */
347ad540459SPierre Jolivet       if (ilens[j] > 0) currentcol = PetscMin(currentcol, ii[j][0] / bs);
348a5973382SShri Abhyankar     }
349a5973382SShri Abhyankar 
350a5973382SShri Abhyankar     while (PETSC_TRUE) { /* loops over blocks in block row */
351a5973382SShri Abhyankar       notdone = PETSC_FALSE;
352a5973382SShri Abhyankar       nextcol = 1000000000;
3539566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(llens, bs));
354a5973382SShri Abhyankar       for (j = 0; j < bs; j++) {                                /* loop over rows in block */
355a5973382SShri Abhyankar         while ((ilens[j] > 0 && ii[j][0] / bs <= currentcol)) { /* loop over columns in row */
356a5973382SShri Abhyankar           ii[j]++;
357a5973382SShri Abhyankar           ilens[j]--;
358a5973382SShri Abhyankar           llens[j]++;
359a5973382SShri Abhyankar         }
360a5973382SShri Abhyankar         if (ilens[j] > 0) {
361a5973382SShri Abhyankar           notdone = PETSC_TRUE;
362a5973382SShri Abhyankar           nextcol = PetscMin(nextcol, ii[j][0] / bs);
363a5973382SShri Abhyankar         }
364a5973382SShri Abhyankar       }
36508401ef6SPierre Jolivet       PetscCheck(cnt < amat->maxnz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of blocks found greater than expected %" PetscInt_FMT, cnt);
366a5973382SShri Abhyankar       if (!flg || currentcol >= i) {
367a5973382SShri Abhyankar         amat->j[cnt] = currentcol;
3689566063dSJacob Faibussowitsch         PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, bs, bs, 0, llens, amat->a + cnt++));
369a5973382SShri Abhyankar       }
370a5973382SShri Abhyankar 
371a5973382SShri Abhyankar       if (!notdone) break;
372a5973382SShri Abhyankar       currentcol = nextcol;
373a5973382SShri Abhyankar     }
374a5973382SShri Abhyankar     amat->ilen[i] = lens[i];
375a5973382SShri Abhyankar   }
376a5973382SShri Abhyankar 
3779566063dSJacob Faibussowitsch   PetscCall(PetscFree3(lens, ii, ilens));
3789566063dSJacob Faibussowitsch   PetscCall(PetscFree(llens));
379a5973382SShri Abhyankar 
380a5973382SShri Abhyankar   /* copy over the matrix, one row at a time */
381a5973382SShri Abhyankar   for (i = 0; i < m; i++) {
3829566063dSJacob Faibussowitsch     PetscCall(MatGetRow(tmpA, i, &ncols, &cols, &values));
3839566063dSJacob Faibussowitsch     PetscCall(MatSetValues(newmat, 1, &i, ncols, cols, values, INSERT_VALUES));
3849566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(tmpA, i, &ncols, &cols, &values));
385a5973382SShri Abhyankar   }
3869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(newmat, MAT_FINAL_ASSEMBLY));
3879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(newmat, MAT_FINAL_ASSEMBLY));
3883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
389a5973382SShri Abhyankar }
390a5973382SShri Abhyankar 
391d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_BlockMat(Mat A, PetscViewer viewer)
392d71ae5a4SJacob Faibussowitsch {
39364075487SBarry Smith   Mat_BlockMat     *a = (Mat_BlockMat *)A->data;
394ccb205f8SBarry Smith   const char       *name;
395ccb205f8SBarry Smith   PetscViewerFormat format;
396ccb205f8SBarry Smith 
397ccb205f8SBarry Smith   PetscFunctionBegin;
3989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)A, &name));
3999566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
400ccb205f8SBarry Smith   if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO) {
4019566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Nonzero block matrices = %" PetscInt_FMT " \n", a->nz));
402b94d7dedSBarry Smith     if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(PetscViewerASCIIPrintf(viewer, "Only upper triangular part of symmetric matrix is stored\n"));
403ccb205f8SBarry Smith   }
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
405ccb205f8SBarry Smith }
406421e10b8SBarry Smith 
407d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_BlockMat(Mat mat)
408d71ae5a4SJacob Faibussowitsch {
409421e10b8SBarry Smith   Mat_BlockMat *bmat = (Mat_BlockMat *)mat->data;
410ccb205f8SBarry Smith   PetscInt      i;
411421e10b8SBarry Smith 
412421e10b8SBarry Smith   PetscFunctionBegin;
4139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmat->right));
4149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmat->left));
4159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmat->middle));
4169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmat->workb));
417ccb205f8SBarry Smith   if (bmat->diags) {
41848a46eb9SPierre Jolivet     for (i = 0; i < mat->rmap->n / mat->rmap->bs; i++) PetscCall(MatDestroy(&bmat->diags[i]));
419ccb205f8SBarry Smith   }
420ccb205f8SBarry Smith   if (bmat->a) {
42148a46eb9SPierre Jolivet     for (i = 0; i < bmat->nz; i++) PetscCall(MatDestroy(&bmat->a[i]));
422ccb205f8SBarry Smith   }
4239566063dSJacob Faibussowitsch   PetscCall(MatSeqXAIJFreeAIJ(mat, (PetscScalar **)&bmat->a, &bmat->j, &bmat->i));
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
4253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
426421e10b8SBarry Smith }
427421e10b8SBarry Smith 
428d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_BlockMat(Mat A, Vec x, Vec y)
429d71ae5a4SJacob Faibussowitsch {
430421e10b8SBarry Smith   Mat_BlockMat *bmat = (Mat_BlockMat *)A->data;
431421e10b8SBarry Smith   PetscScalar  *xx, *yy;
432d0f46423SBarry Smith   PetscInt     *aj, i, *ii, jrow, m = A->rmap->n / A->rmap->bs, bs = A->rmap->bs, n, j;
433421e10b8SBarry Smith   Mat          *aa;
434421e10b8SBarry Smith 
435421e10b8SBarry Smith   PetscFunctionBegin;
436421e10b8SBarry Smith   /*
437421e10b8SBarry Smith      Standard CSR multiply except each entry is a Mat
438421e10b8SBarry Smith   */
4399566063dSJacob Faibussowitsch   PetscCall(VecGetArray(x, &xx));
440ccb205f8SBarry Smith 
4419566063dSJacob Faibussowitsch   PetscCall(VecSet(y, 0.0));
4429566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yy));
443421e10b8SBarry Smith   aj = bmat->j;
444421e10b8SBarry Smith   aa = bmat->a;
445421e10b8SBarry Smith   ii = bmat->i;
446421e10b8SBarry Smith   for (i = 0; i < m; i++) {
447421e10b8SBarry Smith     jrow = ii[i];
4489566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bmat->left, yy + bs * i));
449421e10b8SBarry Smith     n = ii[i + 1] - jrow;
450421e10b8SBarry Smith     for (j = 0; j < n; j++) {
4519566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(bmat->right, xx + bs * aj[jrow]));
4529566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(aa[jrow], bmat->right, bmat->left, bmat->left));
4539566063dSJacob Faibussowitsch       PetscCall(VecResetArray(bmat->right));
454421e10b8SBarry Smith       jrow++;
455421e10b8SBarry Smith     }
4569566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bmat->left));
457421e10b8SBarry Smith   }
4589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(x, &xx));
4599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yy));
4603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
461421e10b8SBarry Smith }
462421e10b8SBarry Smith 
463d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_BlockMat_Symmetric(Mat A, Vec x, Vec y)
464d71ae5a4SJacob Faibussowitsch {
465290bbb0aSBarry Smith   Mat_BlockMat *bmat = (Mat_BlockMat *)A->data;
466290bbb0aSBarry Smith   PetscScalar  *xx, *yy;
467d0f46423SBarry Smith   PetscInt     *aj, i, *ii, jrow, m = A->rmap->n / A->rmap->bs, bs = A->rmap->bs, n, j;
468290bbb0aSBarry Smith   Mat          *aa;
469290bbb0aSBarry Smith 
470290bbb0aSBarry Smith   PetscFunctionBegin;
471290bbb0aSBarry Smith   /*
472290bbb0aSBarry Smith      Standard CSR multiply except each entry is a Mat
473290bbb0aSBarry Smith   */
4749566063dSJacob Faibussowitsch   PetscCall(VecGetArray(x, &xx));
475290bbb0aSBarry Smith 
4769566063dSJacob Faibussowitsch   PetscCall(VecSet(y, 0.0));
4779566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yy));
478290bbb0aSBarry Smith   aj = bmat->j;
479290bbb0aSBarry Smith   aa = bmat->a;
480290bbb0aSBarry Smith   ii = bmat->i;
481290bbb0aSBarry Smith   for (i = 0; i < m; i++) {
482290bbb0aSBarry Smith     jrow = ii[i];
483290bbb0aSBarry Smith     n    = ii[i + 1] - jrow;
4849566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bmat->left, yy + bs * i));
4859566063dSJacob Faibussowitsch     PetscCall(VecPlaceArray(bmat->middle, xx + bs * i));
486290bbb0aSBarry Smith     /* if we ALWAYS required a diagonal entry then could remove this if test */
487290bbb0aSBarry Smith     if (aj[jrow] == i) {
4889566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(bmat->right, xx + bs * aj[jrow]));
4899566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(aa[jrow], bmat->right, bmat->left, bmat->left));
4909566063dSJacob Faibussowitsch       PetscCall(VecResetArray(bmat->right));
491290bbb0aSBarry Smith       jrow++;
492290bbb0aSBarry Smith       n--;
493290bbb0aSBarry Smith     }
494290bbb0aSBarry Smith     for (j = 0; j < n; j++) {
4959566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(bmat->right, xx + bs * aj[jrow])); /* upper triangular part */
4969566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(aa[jrow], bmat->right, bmat->left, bmat->left));
4979566063dSJacob Faibussowitsch       PetscCall(VecResetArray(bmat->right));
498290bbb0aSBarry Smith 
4999566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(bmat->right, yy + bs * aj[jrow])); /* lower triangular part */
5009566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(aa[jrow], bmat->middle, bmat->right, bmat->right));
5019566063dSJacob Faibussowitsch       PetscCall(VecResetArray(bmat->right));
502290bbb0aSBarry Smith       jrow++;
503290bbb0aSBarry Smith     }
5049566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bmat->left));
5059566063dSJacob Faibussowitsch     PetscCall(VecResetArray(bmat->middle));
506290bbb0aSBarry Smith   }
5079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(x, &xx));
5089566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yy));
5093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
510290bbb0aSBarry Smith }
511290bbb0aSBarry Smith 
512d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_BlockMat(Mat A, Vec x, Vec y, Vec z)
513d71ae5a4SJacob Faibussowitsch {
514421e10b8SBarry Smith   PetscFunctionBegin;
5153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
516421e10b8SBarry Smith }
517421e10b8SBarry Smith 
518d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_BlockMat(Mat A, Vec x, Vec y)
519d71ae5a4SJacob Faibussowitsch {
520421e10b8SBarry Smith   PetscFunctionBegin;
5213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
522421e10b8SBarry Smith }
523421e10b8SBarry Smith 
524d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_BlockMat(Mat A, Vec x, Vec y, Vec z)
525d71ae5a4SJacob Faibussowitsch {
526421e10b8SBarry Smith   PetscFunctionBegin;
5273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
528421e10b8SBarry Smith }
529421e10b8SBarry Smith 
530ccb205f8SBarry Smith /*
531ccb205f8SBarry Smith      Adds diagonal pointers to sparse matrix structure.
532ccb205f8SBarry Smith */
533d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMarkDiagonal_BlockMat(Mat A)
534d71ae5a4SJacob Faibussowitsch {
535ccb205f8SBarry Smith   Mat_BlockMat *a = (Mat_BlockMat *)A->data;
536d0f46423SBarry Smith   PetscInt      i, j, mbs = A->rmap->n / A->rmap->bs;
537ccb205f8SBarry Smith 
538ccb205f8SBarry Smith   PetscFunctionBegin;
53948a46eb9SPierre Jolivet   if (!a->diag) PetscCall(PetscMalloc1(mbs, &a->diag));
540ccb205f8SBarry Smith   for (i = 0; i < mbs; i++) {
541ccb205f8SBarry Smith     a->diag[i] = a->i[i + 1];
542ccb205f8SBarry Smith     for (j = a->i[i]; j < a->i[i + 1]; j++) {
543ccb205f8SBarry Smith       if (a->j[j] == i) {
544ccb205f8SBarry Smith         a->diag[i] = j;
545ccb205f8SBarry Smith         break;
546ccb205f8SBarry Smith       }
547ccb205f8SBarry Smith     }
548ccb205f8SBarry Smith   }
5493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
550ccb205f8SBarry Smith }
551ccb205f8SBarry Smith 
552d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_BlockMat(Mat A, IS isrow, IS iscol, MatReuse scall, Mat *B)
553d71ae5a4SJacob Faibussowitsch {
554ccb205f8SBarry Smith   Mat_BlockMat *a = (Mat_BlockMat *)A->data;
555ccb205f8SBarry Smith   Mat_SeqAIJ   *c;
556ccb205f8SBarry Smith   PetscInt      i, k, first, step, lensi, nrows, ncols;
557d2a212eaSBarry Smith   PetscInt     *j_new, *i_new, *aj = a->j, *ailen = a->ilen;
5581620fd73SBarry Smith   PetscScalar  *a_new;
559ccb205f8SBarry Smith   Mat           C, *aa = a->a;
560ace3abfcSBarry Smith   PetscBool     stride, equal;
561ccb205f8SBarry Smith 
562ccb205f8SBarry Smith   PetscFunctionBegin;
5639566063dSJacob Faibussowitsch   PetscCall(ISEqual(isrow, iscol, &equal));
56428b400f6SJacob Faibussowitsch   PetscCheck(equal, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only for identical column and row indices");
5659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)iscol, ISSTRIDE, &stride));
56628b400f6SJacob Faibussowitsch   PetscCheck(stride, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only for stride indices");
5679566063dSJacob Faibussowitsch   PetscCall(ISStrideGetInfo(iscol, &first, &step));
56808401ef6SPierre Jolivet   PetscCheck(step == A->rmap->bs, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only select one entry from each block");
569ccb205f8SBarry Smith 
5709566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isrow, &nrows));
571ccb205f8SBarry Smith   ncols = nrows;
572ccb205f8SBarry Smith 
573ccb205f8SBarry Smith   /* create submatrix */
574ccb205f8SBarry Smith   if (scall == MAT_REUSE_MATRIX) {
575ccb205f8SBarry Smith     PetscInt n_cols, n_rows;
576ccb205f8SBarry Smith     C = *B;
5779566063dSJacob Faibussowitsch     PetscCall(MatGetSize(C, &n_rows, &n_cols));
578aed4548fSBarry Smith     PetscCheck(n_rows == nrows && n_cols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reused submatrix wrong size");
5799566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(C));
580ccb205f8SBarry Smith   } else {
5819566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
5829566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE));
583b94d7dedSBarry Smith     if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetType(C, MATSEQSBAIJ));
584b94d7dedSBarry Smith     else PetscCall(MatSetType(C, MATSEQAIJ));
5859566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(C, 0, ailen));
5869566063dSJacob Faibussowitsch     PetscCall(MatSeqSBAIJSetPreallocation(C, 1, 0, ailen));
587ccb205f8SBarry Smith   }
588ccb205f8SBarry Smith   c = (Mat_SeqAIJ *)C->data;
589ccb205f8SBarry Smith 
590ccb205f8SBarry Smith   /* loop over rows inserting into submatrix */
591ccb205f8SBarry Smith   a_new = c->a;
592ccb205f8SBarry Smith   j_new = c->j;
593ccb205f8SBarry Smith   i_new = c->i;
594ccb205f8SBarry Smith 
595ccb205f8SBarry Smith   for (i = 0; i < nrows; i++) {
596ccb205f8SBarry Smith     lensi = ailen[i];
597ccb205f8SBarry Smith     for (k = 0; k < lensi; k++) {
598ccb205f8SBarry Smith       *j_new++ = *aj++;
5999566063dSJacob Faibussowitsch       PetscCall(MatGetValue(*aa++, first, first, a_new++));
600ccb205f8SBarry Smith     }
601ccb205f8SBarry Smith     i_new[i + 1] = i_new[i] + lensi;
602ccb205f8SBarry Smith     c->ilen[i]   = lensi;
603ccb205f8SBarry Smith   }
604ccb205f8SBarry Smith 
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
6069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
607ccb205f8SBarry Smith   *B = C;
6083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
609ccb205f8SBarry Smith }
610ccb205f8SBarry Smith 
611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_BlockMat(Mat A, MatAssemblyType mode)
612d71ae5a4SJacob Faibussowitsch {
613421e10b8SBarry Smith   Mat_BlockMat *a      = (Mat_BlockMat *)A->data;
614421e10b8SBarry Smith   PetscInt      fshift = 0, i, j, *ai = a->i, *aj = a->j, *imax = a->imax;
615ccb205f8SBarry Smith   PetscInt      m = a->mbs, *ip, N, *ailen = a->ilen, rmax = 0;
616421e10b8SBarry Smith   Mat          *aa = a->a, *ap;
617421e10b8SBarry Smith 
618421e10b8SBarry Smith   PetscFunctionBegin;
6193ba16761SJacob Faibussowitsch   if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(PETSC_SUCCESS);
620421e10b8SBarry Smith 
621421e10b8SBarry Smith   if (m) rmax = ailen[0]; /* determine row with most nonzeros */
622421e10b8SBarry Smith   for (i = 1; i < m; i++) {
623421e10b8SBarry Smith     /* move each row back by the amount of empty slots (fshift) before it*/
624421e10b8SBarry Smith     fshift += imax[i - 1] - ailen[i - 1];
625421e10b8SBarry Smith     rmax = PetscMax(rmax, ailen[i]);
626421e10b8SBarry Smith     if (fshift) {
627421e10b8SBarry Smith       ip = aj + ai[i];
628421e10b8SBarry Smith       ap = aa + ai[i];
629421e10b8SBarry Smith       N  = ailen[i];
630421e10b8SBarry Smith       for (j = 0; j < N; j++) {
631421e10b8SBarry Smith         ip[j - fshift] = ip[j];
632421e10b8SBarry Smith         ap[j - fshift] = ap[j];
633421e10b8SBarry Smith       }
634421e10b8SBarry Smith     }
635421e10b8SBarry Smith     ai[i] = ai[i - 1] + ailen[i - 1];
636421e10b8SBarry Smith   }
637421e10b8SBarry Smith   if (m) {
638421e10b8SBarry Smith     fshift += imax[m - 1] - ailen[m - 1];
639421e10b8SBarry Smith     ai[m] = ai[m - 1] + ailen[m - 1];
640421e10b8SBarry Smith   }
641421e10b8SBarry Smith   /* reset ilen and imax for each row */
642ad540459SPierre Jolivet   for (i = 0; i < m; i++) ailen[i] = imax[i] = ai[i + 1] - ai[i];
643421e10b8SBarry Smith   a->nz = ai[m];
644ccb205f8SBarry Smith   for (i = 0; i < a->nz; i++) {
6456bdcaf15SBarry Smith     PetscAssert(aa[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Null matrix at location %" PetscInt_FMT " column %" PetscInt_FMT " nz %" PetscInt_FMT, i, aj[i], a->nz);
6469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(aa[i], MAT_FINAL_ASSEMBLY));
6479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(aa[i], MAT_FINAL_ASSEMBLY));
648ccb205f8SBarry Smith   }
6499566063dSJacob Faibussowitsch   PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded,%" PetscInt_FMT " used\n", m, A->cmap->n / A->cmap->bs, fshift, a->nz));
6509566063dSJacob Faibussowitsch   PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues() is %" PetscInt_FMT "\n", a->reallocs));
6519566063dSJacob Faibussowitsch   PetscCall(PetscInfo(A, "Maximum nonzeros in any row is %" PetscInt_FMT "\n", rmax));
6522205254eSKarl Rupp 
6538e58a170SBarry Smith   A->info.mallocs += a->reallocs;
654421e10b8SBarry Smith   a->reallocs         = 0;
655421e10b8SBarry Smith   A->info.nz_unneeded = (double)fshift;
656421e10b8SBarry Smith   a->rmax             = rmax;
6579566063dSJacob Faibussowitsch   PetscCall(MatMarkDiagonal_BlockMat(A));
6583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
659421e10b8SBarry Smith }
660421e10b8SBarry Smith 
661d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_BlockMat(Mat A, MatOption opt, PetscBool flg)
662d71ae5a4SJacob Faibussowitsch {
663290bbb0aSBarry Smith   PetscFunctionBegin;
6644e0d8c25SBarry Smith   if (opt == MAT_SYMMETRIC && flg) {
66541f059aeSBarry Smith     A->ops->sor  = MatSOR_BlockMat_Symmetric;
666290bbb0aSBarry Smith     A->ops->mult = MatMult_BlockMat_Symmetric;
667290bbb0aSBarry Smith   } else {
6689566063dSJacob Faibussowitsch     PetscCall(PetscInfo(A, "Unused matrix option %s\n", MatOptions[opt]));
669290bbb0aSBarry Smith   }
6703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
671290bbb0aSBarry Smith }
672290bbb0aSBarry Smith 
6733964eb88SJed Brown static struct _MatOps MatOps_Values = {MatSetValues_BlockMat,
674f4259b30SLisandro Dalcin                                        NULL,
675f4259b30SLisandro Dalcin                                        NULL,
676421e10b8SBarry Smith                                        MatMult_BlockMat,
677421e10b8SBarry Smith                                        /*  4*/ MatMultAdd_BlockMat,
678421e10b8SBarry Smith                                        MatMultTranspose_BlockMat,
679421e10b8SBarry Smith                                        MatMultTransposeAdd_BlockMat,
680f4259b30SLisandro Dalcin                                        NULL,
681f4259b30SLisandro Dalcin                                        NULL,
682f4259b30SLisandro Dalcin                                        NULL,
683f4259b30SLisandro Dalcin                                        /* 10*/ NULL,
684f4259b30SLisandro Dalcin                                        NULL,
685f4259b30SLisandro Dalcin                                        NULL,
68641f059aeSBarry Smith                                        MatSOR_BlockMat,
687f4259b30SLisandro Dalcin                                        NULL,
688f4259b30SLisandro Dalcin                                        /* 15*/ NULL,
689f4259b30SLisandro Dalcin                                        NULL,
690f4259b30SLisandro Dalcin                                        NULL,
691f4259b30SLisandro Dalcin                                        NULL,
692f4259b30SLisandro Dalcin                                        NULL,
693f4259b30SLisandro Dalcin                                        /* 20*/ NULL,
694421e10b8SBarry Smith                                        MatAssemblyEnd_BlockMat,
695290bbb0aSBarry Smith                                        MatSetOption_BlockMat,
696f4259b30SLisandro Dalcin                                        NULL,
697f4259b30SLisandro Dalcin                                        /* 24*/ NULL,
698f4259b30SLisandro Dalcin                                        NULL,
699f4259b30SLisandro Dalcin                                        NULL,
700f4259b30SLisandro Dalcin                                        NULL,
701f4259b30SLisandro Dalcin                                        NULL,
702f4259b30SLisandro Dalcin                                        /* 29*/ NULL,
703f4259b30SLisandro Dalcin                                        NULL,
704f4259b30SLisandro Dalcin                                        NULL,
705f4259b30SLisandro Dalcin                                        NULL,
706f4259b30SLisandro Dalcin                                        NULL,
707f4259b30SLisandro Dalcin                                        /* 34*/ NULL,
708f4259b30SLisandro Dalcin                                        NULL,
709f4259b30SLisandro Dalcin                                        NULL,
710f4259b30SLisandro Dalcin                                        NULL,
711f4259b30SLisandro Dalcin                                        NULL,
712f4259b30SLisandro Dalcin                                        /* 39*/ NULL,
713f4259b30SLisandro Dalcin                                        NULL,
714f4259b30SLisandro Dalcin                                        NULL,
715f4259b30SLisandro Dalcin                                        NULL,
716f4259b30SLisandro Dalcin                                        NULL,
717f4259b30SLisandro Dalcin                                        /* 44*/ NULL,
718f4259b30SLisandro Dalcin                                        NULL,
7197d68702bSBarry Smith                                        MatShift_Basic,
720f4259b30SLisandro Dalcin                                        NULL,
721f4259b30SLisandro Dalcin                                        NULL,
722f4259b30SLisandro Dalcin                                        /* 49*/ NULL,
723f4259b30SLisandro Dalcin                                        NULL,
724f4259b30SLisandro Dalcin                                        NULL,
725f4259b30SLisandro Dalcin                                        NULL,
726f4259b30SLisandro Dalcin                                        NULL,
727f4259b30SLisandro Dalcin                                        /* 54*/ NULL,
728f4259b30SLisandro Dalcin                                        NULL,
729f4259b30SLisandro Dalcin                                        NULL,
730f4259b30SLisandro Dalcin                                        NULL,
731f4259b30SLisandro Dalcin                                        NULL,
7327dae84e0SHong Zhang                                        /* 59*/ MatCreateSubMatrix_BlockMat,
733421e10b8SBarry Smith                                        MatDestroy_BlockMat,
734ccb205f8SBarry Smith                                        MatView_BlockMat,
735f4259b30SLisandro Dalcin                                        NULL,
736f4259b30SLisandro Dalcin                                        NULL,
737f4259b30SLisandro Dalcin                                        /* 64*/ NULL,
738f4259b30SLisandro Dalcin                                        NULL,
739f4259b30SLisandro Dalcin                                        NULL,
740f4259b30SLisandro Dalcin                                        NULL,
741f4259b30SLisandro Dalcin                                        NULL,
742f4259b30SLisandro Dalcin                                        /* 69*/ NULL,
743f4259b30SLisandro Dalcin                                        NULL,
744f4259b30SLisandro Dalcin                                        NULL,
745f4259b30SLisandro Dalcin                                        NULL,
746f4259b30SLisandro Dalcin                                        NULL,
747f4259b30SLisandro Dalcin                                        /* 74*/ NULL,
748f4259b30SLisandro Dalcin                                        NULL,
749f4259b30SLisandro Dalcin                                        NULL,
750f4259b30SLisandro Dalcin                                        NULL,
751f4259b30SLisandro Dalcin                                        NULL,
752f4259b30SLisandro Dalcin                                        /* 79*/ NULL,
753f4259b30SLisandro Dalcin                                        NULL,
754f4259b30SLisandro Dalcin                                        NULL,
755f4259b30SLisandro Dalcin                                        NULL,
7565bba2384SShri Abhyankar                                        MatLoad_BlockMat,
757f4259b30SLisandro Dalcin                                        /* 84*/ NULL,
758f4259b30SLisandro Dalcin                                        NULL,
759f4259b30SLisandro Dalcin                                        NULL,
760f4259b30SLisandro Dalcin                                        NULL,
761f4259b30SLisandro Dalcin                                        NULL,
762f4259b30SLisandro Dalcin                                        /* 89*/ NULL,
763f4259b30SLisandro Dalcin                                        NULL,
764f4259b30SLisandro Dalcin                                        NULL,
765f4259b30SLisandro Dalcin                                        NULL,
766f4259b30SLisandro Dalcin                                        NULL,
767f4259b30SLisandro Dalcin                                        /* 94*/ NULL,
768f4259b30SLisandro Dalcin                                        NULL,
769f4259b30SLisandro Dalcin                                        NULL,
770f4259b30SLisandro Dalcin                                        NULL,
771f4259b30SLisandro Dalcin                                        NULL,
772f4259b30SLisandro Dalcin                                        /* 99*/ NULL,
773f4259b30SLisandro Dalcin                                        NULL,
774f4259b30SLisandro Dalcin                                        NULL,
775f4259b30SLisandro Dalcin                                        NULL,
776f4259b30SLisandro Dalcin                                        NULL,
777f4259b30SLisandro Dalcin                                        /*104*/ NULL,
778f4259b30SLisandro Dalcin                                        NULL,
779f4259b30SLisandro Dalcin                                        NULL,
780f4259b30SLisandro Dalcin                                        NULL,
781f4259b30SLisandro Dalcin                                        NULL,
782f4259b30SLisandro Dalcin                                        /*109*/ NULL,
783f4259b30SLisandro Dalcin                                        NULL,
784f4259b30SLisandro Dalcin                                        NULL,
785f4259b30SLisandro Dalcin                                        NULL,
786f4259b30SLisandro Dalcin                                        NULL,
787f4259b30SLisandro Dalcin                                        /*114*/ NULL,
788f4259b30SLisandro Dalcin                                        NULL,
789f4259b30SLisandro Dalcin                                        NULL,
790f4259b30SLisandro Dalcin                                        NULL,
791f4259b30SLisandro Dalcin                                        NULL,
792f4259b30SLisandro Dalcin                                        /*119*/ NULL,
793f4259b30SLisandro Dalcin                                        NULL,
794f4259b30SLisandro Dalcin                                        NULL,
795f4259b30SLisandro Dalcin                                        NULL,
796f4259b30SLisandro Dalcin                                        NULL,
797f4259b30SLisandro Dalcin                                        /*124*/ NULL,
798f4259b30SLisandro Dalcin                                        NULL,
799f4259b30SLisandro Dalcin                                        NULL,
800f4259b30SLisandro Dalcin                                        NULL,
801f4259b30SLisandro Dalcin                                        NULL,
802f4259b30SLisandro Dalcin                                        /*129*/ NULL,
803f4259b30SLisandro Dalcin                                        NULL,
804f4259b30SLisandro Dalcin                                        NULL,
805f4259b30SLisandro Dalcin                                        NULL,
806f4259b30SLisandro Dalcin                                        NULL,
807f4259b30SLisandro Dalcin                                        /*134*/ NULL,
808f4259b30SLisandro Dalcin                                        NULL,
809f4259b30SLisandro Dalcin                                        NULL,
810f4259b30SLisandro Dalcin                                        NULL,
811f4259b30SLisandro Dalcin                                        NULL,
812f4259b30SLisandro Dalcin                                        /*139*/ NULL,
813f4259b30SLisandro Dalcin                                        NULL,
814d70f29a3SPierre Jolivet                                        NULL,
815d70f29a3SPierre Jolivet                                        NULL,
816d70f29a3SPierre Jolivet                                        NULL,
817d70f29a3SPierre Jolivet                                        /*144*/ NULL,
818d70f29a3SPierre Jolivet                                        NULL,
819d70f29a3SPierre Jolivet                                        NULL,
82099a7f59eSMark Adams                                        NULL,
82199a7f59eSMark Adams                                        NULL,
8227fb60732SBarry Smith                                        NULL,
823dec0b466SHong Zhang                                        /*150*/ NULL,
824dec0b466SHong Zhang                                        NULL};
825421e10b8SBarry Smith 
8268cdf2d9bSBarry Smith /*@C
8278cdf2d9bSBarry Smith    MatBlockMatSetPreallocation - For good matrix assembly performance
8288cdf2d9bSBarry Smith    the user should preallocate the matrix storage by setting the parameter nz
8298cdf2d9bSBarry Smith    (or the array nnz).  By setting these parameters accurately, performance
8308cdf2d9bSBarry Smith    during matrix assembly can be increased by more than a factor of 50.
8318cdf2d9bSBarry Smith 
832d083f849SBarry Smith    Collective
8338cdf2d9bSBarry Smith 
8348cdf2d9bSBarry Smith    Input Parameters:
8358cdf2d9bSBarry Smith +  B - The matrix
8368cdf2d9bSBarry Smith .  bs - size of each block in matrix
8378cdf2d9bSBarry Smith .  nz - number of nonzeros per block row (same for all rows)
8388cdf2d9bSBarry Smith -  nnz - array containing the number of nonzeros in the various block rows
8392ef1f0ffSBarry Smith          (possibly different for each row) or `NULL`
8408cdf2d9bSBarry Smith 
8418cdf2d9bSBarry Smith    Level: intermediate
8428cdf2d9bSBarry Smith 
8432ef1f0ffSBarry Smith    Notes:
8442ef1f0ffSBarry Smith      If `nnz` is given then `nz` is ignored
8452ef1f0ffSBarry Smith 
8462ef1f0ffSBarry Smith    Specify the preallocated storage with either `nz` or `nnz` (not both).
8472ef1f0ffSBarry Smith    Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory
8482ef1f0ffSBarry Smith    allocation.
8492ef1f0ffSBarry Smith 
850*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateBlockMat()`, `MatSetValues()`
8518cdf2d9bSBarry Smith @*/
852d71ae5a4SJacob Faibussowitsch PetscErrorCode MatBlockMatSetPreallocation(Mat B, PetscInt bs, PetscInt nz, const PetscInt nnz[])
853d71ae5a4SJacob Faibussowitsch {
8548cdf2d9bSBarry Smith   PetscFunctionBegin;
855cac4c232SBarry Smith   PetscTryMethod(B, "MatBlockMatSetPreallocation_C", (Mat, PetscInt, PetscInt, const PetscInt[]), (B, bs, nz, nnz));
8563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8578cdf2d9bSBarry Smith }
8588cdf2d9bSBarry Smith 
859d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatBlockMatSetPreallocation_BlockMat(Mat A, PetscInt bs, PetscInt nz, PetscInt *nnz)
860d71ae5a4SJacob Faibussowitsch {
8618cdf2d9bSBarry Smith   Mat_BlockMat *bmat = (Mat_BlockMat *)A->data;
8628cdf2d9bSBarry Smith   PetscInt      i;
8638cdf2d9bSBarry Smith 
8648cdf2d9bSBarry Smith   PetscFunctionBegin;
8659566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, bs));
8669566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, bs));
8679566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
8689566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
8699566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetBlockSize(A->rmap, &bs));
87034ef9618SShri Abhyankar 
8718cdf2d9bSBarry Smith   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
87208401ef6SPierre Jolivet   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz);
8738cdf2d9bSBarry Smith   if (nnz) {
874d0f46423SBarry Smith     for (i = 0; i < A->rmap->n / bs; i++) {
87508401ef6SPierre Jolivet       PetscCheck(nnz[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be less than 0: local row %" PetscInt_FMT " value %" PetscInt_FMT, i, nnz[i]);
87608401ef6SPierre Jolivet       PetscCheck(nnz[i] <= A->cmap->n / bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be greater than row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " rowlength %" PetscInt_FMT, i, nnz[i], A->cmap->n / bs);
8778cdf2d9bSBarry Smith     }
8788cdf2d9bSBarry Smith   }
879d0f46423SBarry Smith   bmat->mbs = A->rmap->n / bs;
8808cdf2d9bSBarry Smith 
8819566063dSJacob Faibussowitsch   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, bs, NULL, &bmat->right));
8829566063dSJacob Faibussowitsch   PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, bs, NULL, &bmat->middle));
8839566063dSJacob Faibussowitsch   PetscCall(VecCreateSeq(PETSC_COMM_SELF, bs, &bmat->left));
8848cdf2d9bSBarry Smith 
885aa624791SPierre Jolivet   if (!bmat->imax) PetscCall(PetscMalloc2(A->rmap->n, &bmat->imax, A->rmap->n, &bmat->ilen));
886c0aa6a63SJacob Faibussowitsch   if (PetscLikely(nnz)) {
8878cdf2d9bSBarry Smith     nz = 0;
888d0f46423SBarry Smith     for (i = 0; i < A->rmap->n / A->rmap->bs; i++) {
8898cdf2d9bSBarry Smith       bmat->imax[i] = nnz[i];
8908cdf2d9bSBarry Smith       nz += nnz[i];
8918cdf2d9bSBarry Smith     }
892f23aa3ddSBarry Smith   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Currently requires block row by row preallocation");
8938cdf2d9bSBarry Smith 
8948cdf2d9bSBarry Smith   /* bmat->ilen will count nonzeros in each row so far. */
8959566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(bmat->ilen, bmat->mbs));
8968cdf2d9bSBarry Smith 
8978cdf2d9bSBarry Smith   /* allocate the matrix space */
8989566063dSJacob Faibussowitsch   PetscCall(MatSeqXAIJFreeAIJ(A, (PetscScalar **)&bmat->a, &bmat->j, &bmat->i));
8999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(nz, &bmat->a, nz, &bmat->j, A->rmap->n + 1, &bmat->i));
9008cdf2d9bSBarry Smith   bmat->i[0] = 0;
901ad540459SPierre Jolivet   for (i = 1; i < bmat->mbs + 1; i++) bmat->i[i] = bmat->i[i - 1] + bmat->imax[i - 1];
9028cdf2d9bSBarry Smith   bmat->singlemalloc = PETSC_TRUE;
9038cdf2d9bSBarry Smith   bmat->free_a       = PETSC_TRUE;
9048cdf2d9bSBarry Smith   bmat->free_ij      = PETSC_TRUE;
9058cdf2d9bSBarry Smith 
9068cdf2d9bSBarry Smith   bmat->nz            = 0;
9078cdf2d9bSBarry Smith   bmat->maxnz         = nz;
9088cdf2d9bSBarry Smith   A->info.nz_unneeded = (double)bmat->maxnz;
9099566063dSJacob Faibussowitsch   PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
9103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9118cdf2d9bSBarry Smith }
9128cdf2d9bSBarry Smith 
913421e10b8SBarry Smith /*MC
91411a5261eSBarry Smith    MATBLOCKMAT - A matrix that is defined by a set of `Mat`'s that represents a sparse block matrix
915421e10b8SBarry Smith                  consisting of (usually) sparse blocks.
916421e10b8SBarry Smith 
917421e10b8SBarry Smith   Level: advanced
918421e10b8SBarry Smith 
919*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateBlockMat()`
920421e10b8SBarry Smith M*/
921421e10b8SBarry Smith 
922d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_BlockMat(Mat A)
923d71ae5a4SJacob Faibussowitsch {
924421e10b8SBarry Smith   Mat_BlockMat *b;
925421e10b8SBarry Smith 
926421e10b8SBarry Smith   PetscFunctionBegin;
9274dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
928421e10b8SBarry Smith   A->data = (void *)b;
9299566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
930421e10b8SBarry Smith 
931421e10b8SBarry Smith   A->assembled    = PETSC_TRUE;
932421e10b8SBarry Smith   A->preallocated = PETSC_FALSE;
9339566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATBLOCKMAT));
934290bbb0aSBarry Smith 
9359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatBlockMatSetPreallocation_C", MatBlockMatSetPreallocation_BlockMat));
9363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
937421e10b8SBarry Smith }
938421e10b8SBarry Smith 
939421e10b8SBarry Smith /*@C
94011a5261eSBarry Smith    MatCreateBlockMat - Creates a new matrix in which each block contains a uniform-size sequential `Mat` object
941421e10b8SBarry Smith 
942d083f849SBarry Smith   Collective
943421e10b8SBarry Smith 
944421e10b8SBarry Smith    Input Parameters:
945421e10b8SBarry Smith +  comm - MPI communicator
946421e10b8SBarry Smith .  m - number of rows
947421e10b8SBarry Smith .  n  - number of columns
9488cdf2d9bSBarry Smith .  bs - size of each submatrix
94911a5261eSBarry Smith .  nz  - expected maximum number of nonzero blocks in row (use `PETSC_DEFAULT` if not known)
9502ef1f0ffSBarry Smith -  nnz - expected number of nonzers per block row if known (use `NULL` otherwise)
951421e10b8SBarry Smith 
952421e10b8SBarry Smith    Output Parameter:
953421e10b8SBarry Smith .  A - the matrix
954421e10b8SBarry Smith 
955421e10b8SBarry Smith    Level: intermediate
956421e10b8SBarry Smith 
95795452b02SPatrick Sanan    Notes:
95811a5261eSBarry Smith     Matrices of this type are nominally-sparse matrices in which each "entry" is a `Mat` object.  Each `Mat` must
959bbd3f336SJed Brown    have the same size and be sequential.  The local and global sizes must be compatible with this decomposition.
960bbd3f336SJed Brown 
96111a5261eSBarry Smith    For matrices containing parallel submatrices and variable block sizes, see `MATNEST`.
96211a5261eSBarry Smith 
96311a5261eSBarry Smith    Developer Note:
96411a5261eSBarry Smith    I don't like the name, it is not `MATNESTMAT`
965421e10b8SBarry Smith 
966*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATBLOCKMAT`, `MatCreateNest()`
967421e10b8SBarry Smith @*/
968d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateBlockMat(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt bs, PetscInt nz, PetscInt *nnz, Mat *A)
969d71ae5a4SJacob Faibussowitsch {
970421e10b8SBarry Smith   PetscFunctionBegin;
9719566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
9729566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
9739566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATBLOCKMAT));
9749566063dSJacob Faibussowitsch   PetscCall(MatBlockMatSetPreallocation(*A, bs, nz, nnz));
9753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
976421e10b8SBarry Smith }
977