xref: /petsc/src/mat/impls/sbaij/seq/aijsbaij.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
159557b74SHong Zhang 
2c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/aij.h>
3c6db04a5SJed Brown #include <../src/mat/impls/baij/seq/baij.h>
4c6db04a5SJed Brown #include <../src/mat/impls/sbaij/seq/sbaij.h>
559557b74SHong Zhang 
6*9371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
74e5e7fe4SHong Zhang   Mat           B;
84e5e7fe4SHong Zhang   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
94e5e7fe4SHong Zhang   Mat_SeqAIJ   *b;
10d0f46423SBarry Smith   PetscInt     *ai = a->i, *aj = a->j, m = A->rmap->N, n = A->cmap->n, i, j, k, *bi, *bj, *rowlengths, nz, *rowstart, itmp;
1101be0148SBarry Smith   PetscInt      bs = A->rmap->bs, bs2 = bs * bs, mbs = A->rmap->N / bs, diagcnt = 0;
12dd6ea824SBarry Smith   MatScalar    *av, *bv;
13eb1ec7c1SStefano Zampini #if defined(PETSC_USE_COMPLEX)
14b94d7dedSBarry Smith   const int aconj = A->hermitian == PETSC_BOOL3_TRUE ? 1 : 0;
15eb1ec7c1SStefano Zampini #else
16eb1ec7c1SStefano Zampini   const int aconj = 0;
17eb1ec7c1SStefano Zampini #endif
184e5e7fe4SHong Zhang 
194e5e7fe4SHong Zhang   PetscFunctionBegin;
204e5e7fe4SHong Zhang   /* compute rowlengths of newmat */
219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(m, &rowlengths, m + 1, &rowstart));
22a7a3a9ebSHong Zhang 
23a7a3a9ebSHong Zhang   for (i = 0; i < mbs; i++) rowlengths[i * bs] = 0;
24a7a3a9ebSHong Zhang   k = 0;
25a7a3a9ebSHong Zhang   for (i = 0; i < mbs; i++) {
264e5e7fe4SHong Zhang     nz = ai[i + 1] - ai[i];
2701be0148SBarry Smith     if (nz) {
2801be0148SBarry Smith       rowlengths[k] += nz; /* no. of upper triangular blocks */
29*9371c9d4SSatish Balay       if (*aj == i) {
30*9371c9d4SSatish Balay         aj++;
31*9371c9d4SSatish Balay         diagcnt++;
32*9371c9d4SSatish Balay         nz--;
33*9371c9d4SSatish Balay       }                          /* skip diagonal */
3401be0148SBarry Smith       for (j = 0; j < nz; j++) { /* no. of lower triangular blocks */
35*9371c9d4SSatish Balay         rowlengths[(*aj) * bs]++;
36*9371c9d4SSatish Balay         aj++;
37a7a3a9ebSHong Zhang       }
3801be0148SBarry Smith     }
39a7a3a9ebSHong Zhang     rowlengths[k] *= bs;
40*9371c9d4SSatish Balay     for (j = 1; j < bs; j++) { rowlengths[k + j] = rowlengths[k]; }
41a7a3a9ebSHong Zhang     k += bs;
424e5e7fe4SHong Zhang   }
434e5e7fe4SHong Zhang 
44bd019fc1SStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
459566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
469566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, m, n, m, n));
479566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATSEQAIJ));
489566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(B, 0, rowlengths));
499566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSize(B, A->rmap->bs));
50bd019fc1SStefano Zampini   } else B = *newmat;
514e5e7fe4SHong Zhang 
524e5e7fe4SHong Zhang   b  = (Mat_SeqAIJ *)(B->data);
534e5e7fe4SHong Zhang   bi = b->i;
544e5e7fe4SHong Zhang   bj = b->j;
554e5e7fe4SHong Zhang   bv = b->a;
564e5e7fe4SHong Zhang 
574e5e7fe4SHong Zhang   /* set b->i */
58*9371c9d4SSatish Balay   bi[0]       = 0;
59*9371c9d4SSatish Balay   rowstart[0] = 0;
60a7a3a9ebSHong Zhang   for (i = 0; i < mbs; i++) {
61a7a3a9ebSHong Zhang     for (j = 0; j < bs; j++) {
62a7a3a9ebSHong Zhang       b->ilen[i * bs + j]      = rowlengths[i * bs];
63a7a3a9ebSHong Zhang       rowstart[i * bs + j + 1] = rowstart[i * bs + j] + rowlengths[i * bs];
644e5e7fe4SHong Zhang     }
65a7a3a9ebSHong Zhang     bi[i + 1] = bi[i] + rowlengths[i * bs] / bs;
66a7a3a9ebSHong Zhang   }
67aed4548fSBarry Smith   PetscCheck(bi[mbs] == 2 * a->nz - diagcnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "bi[mbs]: %" PetscInt_FMT " != 2*a->nz-diagcnt: %" PetscInt_FMT, bi[mbs], 2 * a->nz - diagcnt);
684e5e7fe4SHong Zhang 
694e5e7fe4SHong Zhang   /* set b->j and b->a */
70*9371c9d4SSatish Balay   aj = a->j;
71*9371c9d4SSatish Balay   av = a->a;
72a7a3a9ebSHong Zhang   for (i = 0; i < mbs; i++) {
7301be0148SBarry Smith     nz = ai[i + 1] - ai[i];
74a7a3a9ebSHong Zhang     /* diagonal block */
7501be0148SBarry Smith     if (nz && *aj == i) {
7601be0148SBarry Smith       nz--;
77a7a3a9ebSHong Zhang       for (j = 0; j < bs; j++) { /* row i*bs+j */
78a7a3a9ebSHong Zhang         itmp = i * bs + j;
79a7a3a9ebSHong Zhang         for (k = 0; k < bs; k++) { /* col i*bs+k */
80a7a3a9ebSHong Zhang           *(bj + rowstart[itmp]) = (*aj) * bs + k;
81a7a3a9ebSHong Zhang           *(bv + rowstart[itmp]) = *(av + k * bs + j);
82a7a3a9ebSHong Zhang           rowstart[itmp]++;
83a7a3a9ebSHong Zhang         }
84a7a3a9ebSHong Zhang       }
85*9371c9d4SSatish Balay       aj++;
86*9371c9d4SSatish Balay       av += bs2;
8701be0148SBarry Smith     }
88a7a3a9ebSHong Zhang 
894e5e7fe4SHong Zhang     while (nz--) {
90a7a3a9ebSHong Zhang       /* lower triangular blocks */
91a7a3a9ebSHong Zhang       for (j = 0; j < bs; j++) { /* row (*aj)*bs+j */
92a7a3a9ebSHong Zhang         itmp = (*aj) * bs + j;
93a7a3a9ebSHong Zhang         for (k = 0; k < bs; k++) { /* col i*bs+k */
94a7a3a9ebSHong Zhang           *(bj + rowstart[itmp]) = i * bs + k;
95eb1ec7c1SStefano Zampini           *(bv + rowstart[itmp]) = aconj ? PetscConj(*(av + j * bs + k)) : *(av + j * bs + k);
96a7a3a9ebSHong Zhang           rowstart[itmp]++;
97a7a3a9ebSHong Zhang         }
98a7a3a9ebSHong Zhang       }
99a7a3a9ebSHong Zhang       /* upper triangular blocks */
100a7a3a9ebSHong Zhang       for (j = 0; j < bs; j++) { /* row i*bs+j */
101a7a3a9ebSHong Zhang         itmp = i * bs + j;
102a7a3a9ebSHong Zhang         for (k = 0; k < bs; k++) { /* col (*aj)*bs+k */
103a7a3a9ebSHong Zhang           *(bj + rowstart[itmp]) = (*aj) * bs + k;
104a7a3a9ebSHong Zhang           *(bv + rowstart[itmp]) = *(av + k * bs + j);
105a7a3a9ebSHong Zhang           rowstart[itmp]++;
106a7a3a9ebSHong Zhang         }
107a7a3a9ebSHong Zhang       }
108*9371c9d4SSatish Balay       aj++;
109*9371c9d4SSatish Balay       av += bs2;
1104e5e7fe4SHong Zhang     }
1114e5e7fe4SHong Zhang   }
1129566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rowlengths, rowstart));
1139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1154e5e7fe4SHong Zhang 
116511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
1179566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
118c3d102feSKris Buschelman   } else {
1194e5e7fe4SHong Zhang     *newmat = B;
120c3d102feSKris Buschelman   }
1214e5e7fe4SHong Zhang   PetscFunctionReturn(0);
1224e5e7fe4SHong Zhang }
123be1d678aSKris Buschelman 
124*9371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqSBAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
125676c34cdSKris Buschelman   Mat           B;
12659557b74SHong Zhang   Mat_SeqAIJ   *a = (Mat_SeqAIJ *)A->data;
127861ba921SHong Zhang   Mat_SeqSBAIJ *b;
128ae8d29abSPierre Jolivet   PetscInt     *ai = a->i, *aj, m = A->rmap->N, n = A->cmap->N, i, j, *bi, *bj, *rowlengths, bs = PetscAbs(A->rmap->bs);
129dd6ea824SBarry Smith   MatScalar    *av, *bv;
130b05258aeSStefano Zampini   PetscBool     miss = PETSC_FALSE;
13159557b74SHong Zhang 
13259557b74SHong Zhang   PetscFunctionBegin;
133b05258aeSStefano Zampini #if !defined(PETSC_USE_COMPLEX)
134b94d7dedSBarry Smith   PetscCheck(A->symmetric == PETSC_BOOL3_TRUE, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Matrix must be symmetric. Call MatSetOption(mat,MAT_SYMMETRIC,PETSC_TRUE)");
135b05258aeSStefano Zampini #else
136b94d7dedSBarry Smith   PetscCheck(A->symmetric == PETSC_BOOL3_TRUE || A->hermitian == PETSC_BOOL3_TRUE, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Matrix must be either symmetric or hermitian. Call MatSetOption(mat,MAT_SYMMETRIC,PETSC_TRUE) and/or MatSetOption(mat,MAT_HERMITIAN,PETSC_TRUE)");
137b05258aeSStefano Zampini #endif
13808401ef6SPierre Jolivet   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix must be square");
13959557b74SHong Zhang 
1409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m / bs, &rowlengths));
141ae8d29abSPierre Jolivet   for (i = 0; i < m / bs; i++) {
142b05258aeSStefano Zampini     if (a->diag[i * bs] == ai[i * bs + 1]) {              /* missing diagonal */
143b05258aeSStefano Zampini       rowlengths[i] = (ai[i * bs + 1] - ai[i * bs]) / bs; /* allocate some extra space */
144b05258aeSStefano Zampini       miss          = PETSC_TRUE;
145b05258aeSStefano Zampini     } else {
146ae8d29abSPierre Jolivet       rowlengths[i] = (ai[i * bs + 1] - a->diag[i * bs]) / bs;
14759557b74SHong Zhang     }
148b05258aeSStefano Zampini   }
149bd019fc1SStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
1509566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
1519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, m, n, m, n));
1529566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATSEQSBAIJ));
1539566063dSJacob Faibussowitsch     PetscCall(MatSeqSBAIJSetPreallocation(B, bs, 0, rowlengths));
154bd019fc1SStefano Zampini   } else B = *newmat;
15559557b74SHong Zhang 
156b05258aeSStefano Zampini   if (bs == 1 && !miss) {
157676c34cdSKris Buschelman     b  = (Mat_SeqSBAIJ *)(B->data);
158861ba921SHong Zhang     bi = b->i;
159861ba921SHong Zhang     bj = b->j;
160861ba921SHong Zhang     bv = b->a;
161861ba921SHong Zhang 
162861ba921SHong Zhang     bi[0] = 0;
16359557b74SHong Zhang     for (i = 0; i < m; i++) {
16459557b74SHong Zhang       aj = a->j + a->diag[i];
16559557b74SHong Zhang       av = a->a + a->diag[i];
166861ba921SHong Zhang       for (j = 0; j < rowlengths[i]; j++) {
167*9371c9d4SSatish Balay         *bj = *aj;
168*9371c9d4SSatish Balay         bj++;
169*9371c9d4SSatish Balay         aj++;
170*9371c9d4SSatish Balay         *bv = *av;
171*9371c9d4SSatish Balay         bv++;
172*9371c9d4SSatish Balay         av++;
173861ba921SHong Zhang       }
174861ba921SHong Zhang       bi[i + 1]  = bi[i] + rowlengths[i];
175861ba921SHong Zhang       b->ilen[i] = rowlengths[i];
17659557b74SHong Zhang     }
1779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1789566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
179ae8d29abSPierre Jolivet   } else {
1809566063dSJacob Faibussowitsch     PetscCall(MatSetOption(B, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE));
181ae8d29abSPierre Jolivet     /* reuse may not be equal to MAT_REUSE_MATRIX, but the basic converter will reallocate or replace newmat if this value is not used */
182ae8d29abSPierre Jolivet     /* if reuse is equal to MAT_INITIAL_MATRIX, it has been appropriately preallocated before                                          */
183ae8d29abSPierre Jolivet     /*                      MAT_INPLACE_MATRIX, it will be replaced with MatHeaderReplace below                                        */
1849566063dSJacob Faibussowitsch     PetscCall(MatConvert_Basic(A, newtype, MAT_REUSE_MATRIX, &B));
185ae8d29abSPierre Jolivet   }
1869566063dSJacob Faibussowitsch   PetscCall(PetscFree(rowlengths));
187511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
1889566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
189ae8d29abSPierre Jolivet   } else *newmat = B;
19059557b74SHong Zhang   PetscFunctionReturn(0);
19159557b74SHong Zhang }
19259557b74SHong Zhang 
193*9371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqBAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
194a0e1a404SHong Zhang   Mat           B;
195a0e1a404SHong Zhang   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
196a0e1a404SHong Zhang   Mat_SeqBAIJ  *b;
197d0f46423SBarry Smith   PetscInt     *ai = a->i, *aj = a->j, m = A->rmap->N, n = A->cmap->n, i, k, *bi, *bj, *browlengths, nz, *browstart, itmp;
19874ee4d9fSHong Zhang   PetscInt      bs = A->rmap->bs, bs2 = bs * bs, mbs = m / bs, col, row;
199dd6ea824SBarry Smith   MatScalar    *av, *bv;
200eb1ec7c1SStefano Zampini #if defined(PETSC_USE_COMPLEX)
201b94d7dedSBarry Smith   const int aconj = A->hermitian == PETSC_BOOL3_TRUE ? 1 : 0;
202eb1ec7c1SStefano Zampini #else
203eb1ec7c1SStefano Zampini   const int aconj = 0;
204eb1ec7c1SStefano Zampini #endif
205a0e1a404SHong Zhang 
206a0e1a404SHong Zhang   PetscFunctionBegin;
207a0e1a404SHong Zhang   /* compute browlengths of newmat */
2089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(mbs, &browlengths, mbs, &browstart));
209a0e1a404SHong Zhang   for (i = 0; i < mbs; i++) browlengths[i] = 0;
210a0e1a404SHong Zhang   for (i = 0; i < mbs; i++) {
211a0e1a404SHong Zhang     nz = ai[i + 1] - ai[i];
212a0e1a404SHong Zhang     aj++;                      /* skip diagonal */
213a0e1a404SHong Zhang     for (k = 1; k < nz; k++) { /* no. of lower triangular blocks */
214*9371c9d4SSatish Balay       browlengths[*aj]++;
215*9371c9d4SSatish Balay       aj++;
216a0e1a404SHong Zhang     }
217a0e1a404SHong Zhang     browlengths[i] += nz; /* no. of upper triangular blocks */
218a0e1a404SHong Zhang   }
219a0e1a404SHong Zhang 
220bd019fc1SStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
2219566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
2229566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, m, n, m, n));
2239566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATSEQBAIJ));
2249566063dSJacob Faibussowitsch     PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, browlengths));
225bd019fc1SStefano Zampini   } else B = *newmat;
226a0e1a404SHong Zhang 
227a0e1a404SHong Zhang   b  = (Mat_SeqBAIJ *)(B->data);
228a0e1a404SHong Zhang   bi = b->i;
229a0e1a404SHong Zhang   bj = b->j;
230a0e1a404SHong Zhang   bv = b->a;
231a0e1a404SHong Zhang 
232a0e1a404SHong Zhang   /* set b->i */
233a0e1a404SHong Zhang   bi[0] = 0;
234a0e1a404SHong Zhang   for (i = 0; i < mbs; i++) {
235a0e1a404SHong Zhang     b->ilen[i]   = browlengths[i];
236a0e1a404SHong Zhang     bi[i + 1]    = bi[i] + browlengths[i];
237a0e1a404SHong Zhang     browstart[i] = bi[i];
238a0e1a404SHong Zhang   }
239aed4548fSBarry Smith   PetscCheck(bi[mbs] == 2 * a->nz - mbs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "bi[mbs]: %" PetscInt_FMT " != 2*a->nz - mbs: %" PetscInt_FMT, bi[mbs], 2 * a->nz - mbs);
240a0e1a404SHong Zhang 
241a0e1a404SHong Zhang   /* set b->j and b->a */
242*9371c9d4SSatish Balay   aj = a->j;
243*9371c9d4SSatish Balay   av = a->a;
244a0e1a404SHong Zhang   for (i = 0; i < mbs; i++) {
245a0e1a404SHong Zhang     /* diagonal block */
246*9371c9d4SSatish Balay     *(bj + browstart[i]) = *aj;
247*9371c9d4SSatish Balay     aj++;
24826fbe8dcSKarl Rupp 
249a0e1a404SHong Zhang     itmp = bs2 * browstart[i];
250a0e1a404SHong Zhang     for (k = 0; k < bs2; k++) {
251*9371c9d4SSatish Balay       *(bv + itmp + k) = *av;
252*9371c9d4SSatish Balay       av++;
253a0e1a404SHong Zhang     }
254a0e1a404SHong Zhang     browstart[i]++;
255a0e1a404SHong Zhang 
256a0e1a404SHong Zhang     nz = ai[i + 1] - ai[i] - 1;
257a0e1a404SHong Zhang     while (nz--) {
25874ee4d9fSHong Zhang       /* lower triangular blocks - transpose blocks of A */
25974ee4d9fSHong Zhang       *(bj + browstart[*aj]) = i; /* block col index */
26026fbe8dcSKarl Rupp 
26174ee4d9fSHong Zhang       itmp = bs2 * browstart[*aj]; /* row index */
26274ee4d9fSHong Zhang       for (col = 0; col < bs; col++) {
26374ee4d9fSHong Zhang         k = col;
26474ee4d9fSHong Zhang         for (row = 0; row < bs; row++) {
265eb1ec7c1SStefano Zampini           bv[itmp + col * bs + row] = aconj ? PetscConj(av[k]) : av[k];
266eb1ec7c1SStefano Zampini           k += bs;
26774ee4d9fSHong Zhang         }
268a0e1a404SHong Zhang       }
269a0e1a404SHong Zhang       browstart[*aj]++;
270a0e1a404SHong Zhang 
271a0e1a404SHong Zhang       /* upper triangular blocks */
272*9371c9d4SSatish Balay       *(bj + browstart[i]) = *aj;
273*9371c9d4SSatish Balay       aj++;
27426fbe8dcSKarl Rupp 
275a0e1a404SHong Zhang       itmp = bs2 * browstart[i];
276*9371c9d4SSatish Balay       for (k = 0; k < bs2; k++) { bv[itmp + k] = av[k]; }
27774ee4d9fSHong Zhang       av += bs2;
278a0e1a404SHong Zhang       browstart[i]++;
279a0e1a404SHong Zhang     }
280a0e1a404SHong Zhang   }
2819566063dSJacob Faibussowitsch   PetscCall(PetscFree2(browlengths, browstart));
2829566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2839566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
284a0e1a404SHong Zhang 
285511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
2869566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
287ae8d29abSPierre Jolivet   } else *newmat = B;
288a0e1a404SHong Zhang   PetscFunctionReturn(0);
289a0e1a404SHong Zhang }
290be1d678aSKris Buschelman 
291*9371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_SeqBAIJ_SeqSBAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
292a0e1a404SHong Zhang   Mat           B;
293a0e1a404SHong Zhang   Mat_SeqBAIJ  *a = (Mat_SeqBAIJ *)A->data;
294a0e1a404SHong Zhang   Mat_SeqSBAIJ *b;
295d0f46423SBarry Smith   PetscInt     *ai = a->i, *aj, m = A->rmap->N, n = A->cmap->n, i, j, k, *bi, *bj, *browlengths;
296d0f46423SBarry Smith   PetscInt      bs = A->rmap->bs, bs2 = bs * bs, mbs = m / bs, dd;
297dd6ea824SBarry Smith   MatScalar    *av, *bv;
298ace3abfcSBarry Smith   PetscBool     flg;
299a0e1a404SHong Zhang 
300a0e1a404SHong Zhang   PetscFunctionBegin;
30128b400f6SJacob Faibussowitsch   PetscCheck(A->symmetric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Matrix must be symmetric. Call MatSetOption(mat,MAT_SYMMETRIC,PETSC_TRUE)");
30208401ef6SPierre Jolivet   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix must be square");
3039566063dSJacob Faibussowitsch   PetscCall(MatMissingDiagonal_SeqBAIJ(A, &flg, &dd)); /* check for missing diagonals, then mark diag */
30428b400f6SJacob Faibussowitsch   PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal %" PetscInt_FMT, dd);
305a0e1a404SHong Zhang 
3069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mbs, &browlengths));
307*9371c9d4SSatish Balay   for (i = 0; i < mbs; i++) { browlengths[i] = ai[i + 1] - a->diag[i]; }
308a0e1a404SHong Zhang 
309bd019fc1SStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
3109566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
3119566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, m, n, m, n));
3129566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATSEQSBAIJ));
3139566063dSJacob Faibussowitsch     PetscCall(MatSeqSBAIJSetPreallocation(B, bs, 0, browlengths));
314bd019fc1SStefano Zampini   } else B = *newmat;
315a0e1a404SHong Zhang 
316a0e1a404SHong Zhang   b  = (Mat_SeqSBAIJ *)(B->data);
317a0e1a404SHong Zhang   bi = b->i;
318a0e1a404SHong Zhang   bj = b->j;
319a0e1a404SHong Zhang   bv = b->a;
320a0e1a404SHong Zhang 
321a0e1a404SHong Zhang   bi[0] = 0;
322a0e1a404SHong Zhang   for (i = 0; i < mbs; i++) {
323a0e1a404SHong Zhang     aj = a->j + a->diag[i];
324a0e1a404SHong Zhang     av = a->a + (a->diag[i]) * bs2;
325a0e1a404SHong Zhang     for (j = 0; j < browlengths[i]; j++) {
326*9371c9d4SSatish Balay       *bj = *aj;
327*9371c9d4SSatish Balay       bj++;
328*9371c9d4SSatish Balay       aj++;
329a0e1a404SHong Zhang       for (k = 0; k < bs2; k++) {
330*9371c9d4SSatish Balay         *bv = *av;
331*9371c9d4SSatish Balay         bv++;
332*9371c9d4SSatish Balay         av++;
333a0e1a404SHong Zhang       }
334a0e1a404SHong Zhang     }
335a0e1a404SHong Zhang     bi[i + 1]  = bi[i] + browlengths[i];
336a0e1a404SHong Zhang     b->ilen[i] = browlengths[i];
337a0e1a404SHong Zhang   }
3389566063dSJacob Faibussowitsch   PetscCall(PetscFree(browlengths));
3399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
341a0e1a404SHong Zhang 
342511c6705SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
3439566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
344ae8d29abSPierre Jolivet   } else *newmat = B;
345a0e1a404SHong Zhang   PetscFunctionReturn(0);
346a0e1a404SHong Zhang }
347