xref: /petsc/src/mat/impls/sbaij/seq/sbaij.c (revision 8fb5bd83c3955fefcf33a54e3bb66920a9fa884b)
1 
2 /*
3     Defines the basic matrix operations for the SBAIJ (compressed row)
4   matrix storage format.
5 */
6 #include <../src/mat/impls/baij/seq/baij.h>         /*I "petscmat.h" I*/
7 #include <../src/mat/impls/sbaij/seq/sbaij.h>
8 #include <petscblaslapack.h>
9 
10 #include <../src/mat/impls/sbaij/seq/relax.h>
11 #define USESHORT
12 #include <../src/mat/impls/sbaij/seq/relax.h>
13 
14 #if defined(PETSC_HAVE_ELEMENTAL)
15 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat,MatType,MatReuse,Mat*);
16 #endif
17 #if defined(PETSC_HAVE_SCALAPACK)
18 PETSC_INTERN PetscErrorCode MatConvert_SBAIJ_ScaLAPACK(Mat,MatType,MatReuse,Mat*);
19 #endif
20 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Basic(Mat,MatType,MatReuse,Mat*);
21 
22 /*
23      Checks for missing diagonals
24 */
25 PetscErrorCode MatMissingDiagonal_SeqSBAIJ(Mat A,PetscBool  *missing,PetscInt *dd)
26 {
27   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
28   PetscInt       *diag,*ii = a->i,i;
29 
30   PetscFunctionBegin;
31   PetscCall(MatMarkDiagonal_SeqSBAIJ(A));
32   *missing = PETSC_FALSE;
33   if (A->rmap->n > 0 && !ii) {
34     *missing = PETSC_TRUE;
35     if (dd) *dd = 0;
36     PetscCall(PetscInfo(A,"Matrix has no entries therefore is missing diagonal\n"));
37   } else {
38     diag = a->diag;
39     for (i=0; i<a->mbs; i++) {
40       if (diag[i] >= ii[i+1]) {
41         *missing = PETSC_TRUE;
42         if (dd) *dd = i;
43         break;
44       }
45     }
46   }
47   PetscFunctionReturn(0);
48 }
49 
50 PetscErrorCode MatMarkDiagonal_SeqSBAIJ(Mat A)
51 {
52   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
53   PetscInt       i,j;
54 
55   PetscFunctionBegin;
56   if (!a->diag) {
57     PetscCall(PetscMalloc1(a->mbs,&a->diag));
58     PetscCall(PetscLogObjectMemory((PetscObject)A,a->mbs*sizeof(PetscInt)));
59     a->free_diag = PETSC_TRUE;
60   }
61   for (i=0; i<a->mbs; i++) {
62     a->diag[i] = a->i[i+1];
63     for (j=a->i[i]; j<a->i[i+1]; j++) {
64       if (a->j[j] == i) {
65         a->diag[i] = j;
66         break;
67       }
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 static PetscErrorCode MatGetRowIJ_SeqSBAIJ(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *nn,const PetscInt *inia[],const PetscInt *inja[],PetscBool  *done)
74 {
75   Mat_SeqSBAIJ    *a = (Mat_SeqSBAIJ*)A->data;
76   PetscInt       i,j,n = a->mbs,nz = a->i[n],*tia,*tja,bs = A->rmap->bs,k,l,cnt;
77   PetscInt       **ia = (PetscInt**)inia,**ja = (PetscInt**)inja;
78 
79   PetscFunctionBegin;
80   *nn = n;
81   if (!ia) PetscFunctionReturn(0);
82   if (symmetric) {
83     PetscCall(MatToSymmetricIJ_SeqAIJ(n,a->i,a->j,PETSC_FALSE,0,0,&tia,&tja));
84     nz   = tia[n];
85   } else {
86     tia = a->i; tja = a->j;
87   }
88 
89   if (!blockcompressed && bs > 1) {
90     (*nn) *= bs;
91     /* malloc & create the natural set of indices */
92     PetscCall(PetscMalloc1((n+1)*bs,ia));
93     if (n) {
94       (*ia)[0] = oshift;
95       for (j=1; j<bs; j++) {
96         (*ia)[j] = (tia[1]-tia[0])*bs+(*ia)[j-1];
97       }
98     }
99 
100     for (i=1; i<n; i++) {
101       (*ia)[i*bs] = (tia[i]-tia[i-1])*bs + (*ia)[i*bs-1];
102       for (j=1; j<bs; j++) {
103         (*ia)[i*bs+j] = (tia[i+1]-tia[i])*bs + (*ia)[i*bs+j-1];
104       }
105     }
106     if (n) {
107       (*ia)[n*bs] = (tia[n]-tia[n-1])*bs + (*ia)[n*bs-1];
108     }
109 
110     if (inja) {
111       PetscCall(PetscMalloc1(nz*bs*bs,ja));
112       cnt = 0;
113       for (i=0; i<n; i++) {
114         for (j=0; j<bs; j++) {
115           for (k=tia[i]; k<tia[i+1]; k++) {
116             for (l=0; l<bs; l++) {
117               (*ja)[cnt++] = bs*tja[k] + l;
118             }
119           }
120         }
121       }
122     }
123 
124     if (symmetric) { /* deallocate memory allocated in MatToSymmetricIJ_SeqAIJ() */
125       PetscCall(PetscFree(tia));
126       PetscCall(PetscFree(tja));
127     }
128   } else if (oshift == 1) {
129     if (symmetric) {
130       nz = tia[A->rmap->n/bs];
131       /*  add 1 to i and j indices */
132       for (i=0; i<A->rmap->n/bs+1; i++) tia[i] = tia[i] + 1;
133       *ia = tia;
134       if (ja) {
135         for (i=0; i<nz; i++) tja[i] = tja[i] + 1;
136         *ja = tja;
137       }
138     } else {
139       nz = a->i[A->rmap->n/bs];
140       /* malloc space and  add 1 to i and j indices */
141       PetscCall(PetscMalloc1(A->rmap->n/bs+1,ia));
142       for (i=0; i<A->rmap->n/bs+1; i++) (*ia)[i] = a->i[i] + 1;
143       if (ja) {
144         PetscCall(PetscMalloc1(nz,ja));
145         for (i=0; i<nz; i++) (*ja)[i] = a->j[i] + 1;
146       }
147     }
148   } else {
149     *ia = tia;
150     if (ja) *ja = tja;
151   }
152   PetscFunctionReturn(0);
153 }
154 
155 static PetscErrorCode MatRestoreRowIJ_SeqSBAIJ(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *nn,const PetscInt *ia[],const PetscInt *ja[],PetscBool  *done)
156 {
157   PetscFunctionBegin;
158   if (!ia) PetscFunctionReturn(0);
159   if ((!blockcompressed && A->rmap->bs > 1) || (symmetric || oshift == 1)) {
160     PetscCall(PetscFree(*ia));
161     if (ja) PetscCall(PetscFree(*ja));
162   }
163   PetscFunctionReturn(0);
164 }
165 
166 PetscErrorCode MatDestroy_SeqSBAIJ(Mat A)
167 {
168   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
169 
170   PetscFunctionBegin;
171 #if defined(PETSC_USE_LOG)
172   PetscLogObjectState((PetscObject)A,"Rows=%" PetscInt_FMT ", NZ=%" PetscInt_FMT,A->rmap->N,a->nz);
173 #endif
174   PetscCall(MatSeqXAIJFreeAIJ(A,&a->a,&a->j,&a->i));
175   if (a->free_diag) PetscCall(PetscFree(a->diag));
176   PetscCall(ISDestroy(&a->row));
177   PetscCall(ISDestroy(&a->col));
178   PetscCall(ISDestroy(&a->icol));
179   PetscCall(PetscFree(a->idiag));
180   PetscCall(PetscFree(a->inode.size));
181   if (a->free_imax_ilen) PetscCall(PetscFree2(a->imax,a->ilen));
182   PetscCall(PetscFree(a->solve_work));
183   PetscCall(PetscFree(a->sor_work));
184   PetscCall(PetscFree(a->solves_work));
185   PetscCall(PetscFree(a->mult_work));
186   PetscCall(PetscFree(a->saved_values));
187   if (a->free_jshort) PetscCall(PetscFree(a->jshort));
188   PetscCall(PetscFree(a->inew));
189   PetscCall(MatDestroy(&a->parent));
190   PetscCall(PetscFree(A->data));
191 
192   PetscCall(PetscObjectChangeTypeName((PetscObject)A,NULL));
193   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSeqSBAIJGetArray_C",NULL));
194   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSeqSBAIJRestoreArray_C",NULL));
195   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatStoreValues_C",NULL));
196   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatRetrieveValues_C",NULL));
197   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSeqSBAIJSetColumnIndices_C",NULL));
198   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqsbaij_seqaij_C",NULL));
199   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqsbaij_seqbaij_C",NULL));
200   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSeqSBAIJSetPreallocation_C",NULL));
201   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSeqSBAIJSetPreallocationCSR_C",NULL));
202 #if defined(PETSC_HAVE_ELEMENTAL)
203   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqsbaij_elemental_C",NULL));
204 #endif
205 #if defined(PETSC_HAVE_SCALAPACK)
206   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqsbaij_scalapack_C",NULL));
207 #endif
208   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverType_C",NULL));
209   PetscFunctionReturn(0);
210 }
211 
212 PetscErrorCode MatSetOption_SeqSBAIJ(Mat A,MatOption op,PetscBool flg)
213 {
214   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
215 #if defined(PETSC_USE_COMPLEX)
216   PetscInt       bs;
217 #endif
218 
219   PetscFunctionBegin;
220 #if defined(PETSC_USE_COMPLEX)
221   PetscCall(MatGetBlockSize(A,&bs));
222 #endif
223   switch (op) {
224   case MAT_ROW_ORIENTED:
225     a->roworiented = flg;
226     break;
227   case MAT_KEEP_NONZERO_PATTERN:
228     a->keepnonzeropattern = flg;
229     break;
230   case MAT_NEW_NONZERO_LOCATIONS:
231     a->nonew = (flg ? 0 : 1);
232     break;
233   case MAT_NEW_NONZERO_LOCATION_ERR:
234     a->nonew = (flg ? -1 : 0);
235     break;
236   case MAT_NEW_NONZERO_ALLOCATION_ERR:
237     a->nonew = (flg ? -2 : 0);
238     break;
239   case MAT_UNUSED_NONZERO_LOCATION_ERR:
240     a->nounused = (flg ? -1 : 0);
241     break;
242   case MAT_FORCE_DIAGONAL_ENTRIES:
243   case MAT_IGNORE_OFF_PROC_ENTRIES:
244   case MAT_USE_HASH_TABLE:
245   case MAT_SORTED_FULL:
246     PetscCall(PetscInfo(A,"Option %s ignored\n",MatOptions[op]));
247     break;
248   case MAT_HERMITIAN:
249 #if defined(PETSC_USE_COMPLEX)
250     if (flg) { /* disable transpose ops */
251       PetscCheck(bs <= 1,PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for Hermitian with block size greater than 1");
252       A->ops->multtranspose    = NULL;
253       A->ops->multtransposeadd = NULL;
254       A->symmetric             = PETSC_FALSE;
255     }
256 #endif
257     break;
258   case MAT_SYMMETRIC:
259   case MAT_SPD:
260 #if defined(PETSC_USE_COMPLEX)
261     if (flg) { /* An hermitian and symmetric matrix has zero imaginary part (restore back transpose ops) */
262       A->ops->multtranspose    = A->ops->mult;
263       A->ops->multtransposeadd = A->ops->multadd;
264     }
265 #endif
266     break;
267     /* These options are handled directly by MatSetOption() */
268   case MAT_STRUCTURALLY_SYMMETRIC:
269   case MAT_SYMMETRY_ETERNAL:
270   case MAT_STRUCTURE_ONLY:
271     /* These options are handled directly by MatSetOption() */
272     break;
273   case MAT_IGNORE_LOWER_TRIANGULAR:
274     a->ignore_ltriangular = flg;
275     break;
276   case MAT_ERROR_LOWER_TRIANGULAR:
277     a->ignore_ltriangular = flg;
278     break;
279   case MAT_GETROW_UPPERTRIANGULAR:
280     a->getrow_utriangular = flg;
281     break;
282   case MAT_SUBMAT_SINGLEIS:
283     break;
284   default:
285     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"unknown option %d",op);
286   }
287   PetscFunctionReturn(0);
288 }
289 
290 PetscErrorCode MatGetRow_SeqSBAIJ(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
291 {
292   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
293 
294   PetscFunctionBegin;
295   PetscCheck(!A || a->getrow_utriangular,PETSC_COMM_SELF,PETSC_ERR_SUP,"MatGetRow is not supported for SBAIJ matrix format. Getting the upper triangular part of row, run with -mat_getrow_uppertriangular, call MatSetOption(mat,MAT_GETROW_UPPERTRIANGULAR,PETSC_TRUE) or MatGetRowUpperTriangular()");
296 
297   /* Get the upper triangular part of the row */
298   PetscCall(MatGetRow_SeqBAIJ_private(A,row,nz,idx,v,a->i,a->j,a->a));
299   PetscFunctionReturn(0);
300 }
301 
302 PetscErrorCode MatRestoreRow_SeqSBAIJ(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
303 {
304   PetscFunctionBegin;
305   if (nz)  *nz = 0;
306   if (idx) PetscCall(PetscFree(*idx));
307   if (v)   PetscCall(PetscFree(*v));
308   PetscFunctionReturn(0);
309 }
310 
311 PetscErrorCode MatGetRowUpperTriangular_SeqSBAIJ(Mat A)
312 {
313   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
314 
315   PetscFunctionBegin;
316   a->getrow_utriangular = PETSC_TRUE;
317   PetscFunctionReturn(0);
318 }
319 
320 PetscErrorCode MatRestoreRowUpperTriangular_SeqSBAIJ(Mat A)
321 {
322   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
323 
324   PetscFunctionBegin;
325   a->getrow_utriangular = PETSC_FALSE;
326   PetscFunctionReturn(0);
327 }
328 
329 PetscErrorCode MatTranspose_SeqSBAIJ(Mat A,MatReuse reuse,Mat *B)
330 {
331   PetscFunctionBegin;
332   if (reuse == MAT_INITIAL_MATRIX) {
333     PetscCall(MatDuplicate(A,MAT_COPY_VALUES,B));
334   } else if (reuse == MAT_REUSE_MATRIX) {
335     PetscCall(MatCopy(A,*B,SAME_NONZERO_PATTERN));
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 PetscErrorCode MatView_SeqSBAIJ_ASCII(Mat A,PetscViewer viewer)
341 {
342   Mat_SeqSBAIJ      *a = (Mat_SeqSBAIJ*)A->data;
343   PetscInt          i,j,bs = A->rmap->bs,k,l,bs2=a->bs2;
344   PetscViewerFormat format;
345   PetscInt          *diag;
346 
347   PetscFunctionBegin;
348   PetscCall(PetscViewerGetFormat(viewer,&format));
349   if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
350     PetscCall(PetscViewerASCIIPrintf(viewer,"  block size is %" PetscInt_FMT "\n",bs));
351   } else if (format == PETSC_VIEWER_ASCII_MATLAB) {
352     Mat        aij;
353     const char *matname;
354 
355     if (A->factortype && bs>1) {
356       PetscCall(PetscPrintf(PETSC_COMM_SELF,"Warning: matrix is factored with bs>1. MatView() with PETSC_VIEWER_ASCII_MATLAB is not supported and ignored!\n"));
357       PetscFunctionReturn(0);
358     }
359     PetscCall(MatConvert(A,MATSEQAIJ,MAT_INITIAL_MATRIX,&aij));
360     PetscCall(PetscObjectGetName((PetscObject)A,&matname));
361     PetscCall(PetscObjectSetName((PetscObject)aij,matname));
362     PetscCall(MatView(aij,viewer));
363     PetscCall(MatDestroy(&aij));
364   } else if (format == PETSC_VIEWER_ASCII_COMMON) {
365     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
366     for (i=0; i<a->mbs; i++) {
367       for (j=0; j<bs; j++) {
368         PetscCall(PetscViewerASCIIPrintf(viewer,"row %" PetscInt_FMT ":",i*bs+j));
369         for (k=a->i[i]; k<a->i[i+1]; k++) {
370           for (l=0; l<bs; l++) {
371 #if defined(PETSC_USE_COMPLEX)
372             if (PetscImaginaryPart(a->a[bs2*k + l*bs + j]) > 0.0 && PetscRealPart(a->a[bs2*k + l*bs + j]) != 0.0) {
373               PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g + %g i) ",bs*a->j[k]+l,
374                                              (double)PetscRealPart(a->a[bs2*k + l*bs + j]),(double)PetscImaginaryPart(a->a[bs2*k + l*bs + j])));
375             } else if (PetscImaginaryPart(a->a[bs2*k + l*bs + j]) < 0.0 && PetscRealPart(a->a[bs2*k + l*bs + j]) != 0.0) {
376               PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g - %g i) ",bs*a->j[k]+l,
377                                              (double)PetscRealPart(a->a[bs2*k + l*bs + j]),-(double)PetscImaginaryPart(a->a[bs2*k + l*bs + j])));
378             } else if (PetscRealPart(a->a[bs2*k + l*bs + j]) != 0.0) {
379               PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",bs*a->j[k]+l,(double)PetscRealPart(a->a[bs2*k + l*bs + j])));
380             }
381 #else
382             if (a->a[bs2*k + l*bs + j] != 0.0) {
383               PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",bs*a->j[k]+l,(double)a->a[bs2*k + l*bs + j]));
384             }
385 #endif
386           }
387         }
388         PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
389       }
390     }
391     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
392   } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
393     PetscFunctionReturn(0);
394   } else {
395     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
396     if (A->factortype) { /* for factored matrix */
397       PetscCheck(bs<=1,PETSC_COMM_SELF,PETSC_ERR_SUP,"matrix is factored with bs>1. Not implemented yet");
398 
399       diag=a->diag;
400       for (i=0; i<a->mbs; i++) { /* for row block i */
401         PetscCall(PetscViewerASCIIPrintf(viewer,"row %" PetscInt_FMT ":",i));
402         /* diagonal entry */
403 #if defined(PETSC_USE_COMPLEX)
404         if (PetscImaginaryPart(a->a[diag[i]]) > 0.0) {
405           PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g + %g i) ",a->j[diag[i]],(double)PetscRealPart(1.0/a->a[diag[i]]),(double)PetscImaginaryPart(1.0/a->a[diag[i]])));
406         } else if (PetscImaginaryPart(a->a[diag[i]]) < 0.0) {
407           PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g - %g i) ",a->j[diag[i]],(double)PetscRealPart(1.0/a->a[diag[i]]),-(double)PetscImaginaryPart(1.0/a->a[diag[i]])));
408         } else {
409           PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",a->j[diag[i]],(double)PetscRealPart(1.0/a->a[diag[i]])));
410         }
411 #else
412         PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",a->j[diag[i]],(double)(1.0/a->a[diag[i]])));
413 #endif
414         /* off-diagonal entries */
415         for (k=a->i[i]; k<a->i[i+1]-1; k++) {
416 #if defined(PETSC_USE_COMPLEX)
417           if (PetscImaginaryPart(a->a[k]) > 0.0) {
418             PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g + %g i) ",bs*a->j[k],(double)PetscRealPart(a->a[k]),(double)PetscImaginaryPart(a->a[k])));
419           } else if (PetscImaginaryPart(a->a[k]) < 0.0) {
420             PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g - %g i) ",bs*a->j[k],(double)PetscRealPart(a->a[k]),-(double)PetscImaginaryPart(a->a[k])));
421           } else {
422             PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",bs*a->j[k],(double)PetscRealPart(a->a[k])));
423           }
424 #else
425           PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",a->j[k],(double)a->a[k]));
426 #endif
427         }
428         PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
429       }
430 
431     } else { /* for non-factored matrix */
432       for (i=0; i<a->mbs; i++) { /* for row block i */
433         for (j=0; j<bs; j++) {   /* for row bs*i + j */
434           PetscCall(PetscViewerASCIIPrintf(viewer,"row %" PetscInt_FMT ":",i*bs+j));
435           for (k=a->i[i]; k<a->i[i+1]; k++) { /* for column block */
436             for (l=0; l<bs; l++) {            /* for column */
437 #if defined(PETSC_USE_COMPLEX)
438               if (PetscImaginaryPart(a->a[bs2*k + l*bs + j]) > 0.0) {
439                 PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g + %g i) ",bs*a->j[k]+l,
440                                                (double)PetscRealPart(a->a[bs2*k + l*bs + j]),(double)PetscImaginaryPart(a->a[bs2*k + l*bs + j])));
441               } else if (PetscImaginaryPart(a->a[bs2*k + l*bs + j]) < 0.0) {
442                 PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g - %g i) ",bs*a->j[k]+l,
443                                                (double)PetscRealPart(a->a[bs2*k + l*bs + j]),-(double)PetscImaginaryPart(a->a[bs2*k + l*bs + j])));
444               } else {
445                 PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",bs*a->j[k]+l,(double)PetscRealPart(a->a[bs2*k + l*bs + j])));
446               }
447 #else
448               PetscCall(PetscViewerASCIIPrintf(viewer," (%" PetscInt_FMT ", %g) ",bs*a->j[k]+l,(double)a->a[bs2*k + l*bs + j]));
449 #endif
450             }
451           }
452           PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
453         }
454       }
455     }
456     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
457   }
458   PetscCall(PetscViewerFlush(viewer));
459   PetscFunctionReturn(0);
460 }
461 
462 #include <petscdraw.h>
463 static PetscErrorCode MatView_SeqSBAIJ_Draw_Zoom(PetscDraw draw,void *Aa)
464 {
465   Mat            A = (Mat) Aa;
466   Mat_SeqSBAIJ   *a=(Mat_SeqSBAIJ*)A->data;
467   PetscInt       row,i,j,k,l,mbs=a->mbs,color,bs=A->rmap->bs,bs2=a->bs2;
468   PetscReal      xl,yl,xr,yr,x_l,x_r,y_l,y_r;
469   MatScalar      *aa;
470   PetscViewer    viewer;
471 
472   PetscFunctionBegin;
473   PetscCall(PetscObjectQuery((PetscObject)A,"Zoomviewer",(PetscObject*)&viewer));
474   PetscCall(PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr));
475 
476   /* loop over matrix elements drawing boxes */
477 
478   PetscDrawCollectiveBegin(draw);
479   PetscCall(PetscDrawString(draw, .3*(xl+xr), .3*(yl+yr), PETSC_DRAW_BLACK, "symmetric"));
480   /* Blue for negative, Cyan for zero and  Red for positive */
481   color = PETSC_DRAW_BLUE;
482   for (i=0,row=0; i<mbs; i++,row+=bs) {
483     for (j=a->i[i]; j<a->i[i+1]; j++) {
484       y_l = A->rmap->N - row - 1.0; y_r = y_l + 1.0;
485       x_l = a->j[j]*bs; x_r = x_l + 1.0;
486       aa  = a->a + j*bs2;
487       for (k=0; k<bs; k++) {
488         for (l=0; l<bs; l++) {
489           if (PetscRealPart(*aa++) >=  0.) continue;
490           PetscCall(PetscDrawRectangle(draw,x_l+k,y_l-l,x_r+k,y_r-l,color,color,color,color));
491         }
492       }
493     }
494   }
495   color = PETSC_DRAW_CYAN;
496   for (i=0,row=0; i<mbs; i++,row+=bs) {
497     for (j=a->i[i]; j<a->i[i+1]; j++) {
498       y_l = A->rmap->N - row - 1.0; y_r = y_l + 1.0;
499       x_l = a->j[j]*bs; x_r = x_l + 1.0;
500       aa = a->a + j*bs2;
501       for (k=0; k<bs; k++) {
502         for (l=0; l<bs; l++) {
503           if (PetscRealPart(*aa++) != 0.) continue;
504           PetscCall(PetscDrawRectangle(draw,x_l+k,y_l-l,x_r+k,y_r-l,color,color,color,color));
505         }
506       }
507     }
508   }
509   color = PETSC_DRAW_RED;
510   for (i=0,row=0; i<mbs; i++,row+=bs) {
511     for (j=a->i[i]; j<a->i[i+1]; j++) {
512       y_l = A->rmap->N - row - 1.0; y_r = y_l + 1.0;
513       x_l = a->j[j]*bs; x_r = x_l + 1.0;
514       aa = a->a + j*bs2;
515       for (k=0; k<bs; k++) {
516         for (l=0; l<bs; l++) {
517           if (PetscRealPart(*aa++) <= 0.) continue;
518           PetscCall(PetscDrawRectangle(draw,x_l+k,y_l-l,x_r+k,y_r-l,color,color,color,color));
519         }
520       }
521     }
522   }
523   PetscDrawCollectiveEnd(draw);
524   PetscFunctionReturn(0);
525 }
526 
527 static PetscErrorCode MatView_SeqSBAIJ_Draw(Mat A,PetscViewer viewer)
528 {
529   PetscReal      xl,yl,xr,yr,w,h;
530   PetscDraw      draw;
531   PetscBool      isnull;
532 
533   PetscFunctionBegin;
534   PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
535   PetscCall(PetscDrawIsNull(draw,&isnull));
536   if (isnull) PetscFunctionReturn(0);
537 
538   xr   = A->rmap->N; yr = A->rmap->N; h = yr/10.0; w = xr/10.0;
539   xr  += w;          yr += h;        xl = -w;     yl = -h;
540   PetscCall(PetscDrawSetCoordinates(draw,xl,yl,xr,yr));
541   PetscCall(PetscObjectCompose((PetscObject)A,"Zoomviewer",(PetscObject)viewer));
542   PetscCall(PetscDrawZoom(draw,MatView_SeqSBAIJ_Draw_Zoom,A));
543   PetscCall(PetscObjectCompose((PetscObject)A,"Zoomviewer",NULL));
544   PetscCall(PetscDrawSave(draw));
545   PetscFunctionReturn(0);
546 }
547 
548 /* Used for both MPIBAIJ and MPISBAIJ matrices */
549 #define MatView_SeqSBAIJ_Binary MatView_SeqBAIJ_Binary
550 
551 PetscErrorCode MatView_SeqSBAIJ(Mat A,PetscViewer viewer)
552 {
553   PetscBool      iascii,isbinary,isdraw;
554 
555   PetscFunctionBegin;
556   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
557   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary));
558   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
559   if (iascii) {
560     PetscCall(MatView_SeqSBAIJ_ASCII(A,viewer));
561   } else if (isbinary) {
562     PetscCall(MatView_SeqSBAIJ_Binary(A,viewer));
563   } else if (isdraw) {
564     PetscCall(MatView_SeqSBAIJ_Draw(A,viewer));
565   } else {
566     Mat        B;
567     const char *matname;
568     PetscCall(MatConvert(A,MATSEQAIJ,MAT_INITIAL_MATRIX,&B));
569     PetscCall(PetscObjectGetName((PetscObject)A,&matname));
570     PetscCall(PetscObjectSetName((PetscObject)B,matname));
571     PetscCall(MatView(B,viewer));
572     PetscCall(MatDestroy(&B));
573   }
574   PetscFunctionReturn(0);
575 }
576 
577 PetscErrorCode MatGetValues_SeqSBAIJ(Mat A,PetscInt m,const PetscInt im[],PetscInt n,const PetscInt in[],PetscScalar v[])
578 {
579   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
580   PetscInt     *rp,k,low,high,t,row,nrow,i,col,l,*aj = a->j;
581   PetscInt     *ai = a->i,*ailen = a->ilen;
582   PetscInt     brow,bcol,ridx,cidx,bs=A->rmap->bs,bs2=a->bs2;
583   MatScalar    *ap,*aa = a->a;
584 
585   PetscFunctionBegin;
586   for (k=0; k<m; k++) { /* loop over rows */
587     row = im[k]; brow = row/bs;
588     if (row < 0) {v += n; continue;} /* negative row */
589     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);
590     rp   = aj + ai[brow]; ap = aa + bs2*ai[brow];
591     nrow = ailen[brow];
592     for (l=0; l<n; l++) { /* loop over columns */
593       if (in[l] < 0) {v++; continue;} /* negative column */
594       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);
595       col  = in[l];
596       bcol = col/bs;
597       cidx = col%bs;
598       ridx = row%bs;
599       high = nrow;
600       low  = 0; /* assume unsorted */
601       while (high-low > 5) {
602         t = (low+high)/2;
603         if (rp[t] > bcol) high = t;
604         else              low  = t;
605       }
606       for (i=low; i<high; i++) {
607         if (rp[i] > bcol) break;
608         if (rp[i] == bcol) {
609           *v++ = ap[bs2*i+bs*cidx+ridx];
610           goto finished;
611         }
612       }
613       *v++ = 0.0;
614 finished:;
615     }
616   }
617   PetscFunctionReturn(0);
618 }
619 
620 PetscErrorCode MatPermute_SeqSBAIJ(Mat A,IS rowp,IS colp,Mat *B)
621 {
622   Mat            C;
623 
624   PetscFunctionBegin;
625   PetscCall(MatConvert(A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&C));
626   PetscCall(MatPermute(C,rowp,colp,B));
627   PetscCall(MatDestroy(&C));
628   if (rowp == colp) {
629     PetscCall(MatConvert(*B,MATSEQSBAIJ,MAT_INPLACE_MATRIX,B));
630   }
631   PetscFunctionReturn(0);
632 }
633 
634 PetscErrorCode MatSetValuesBlocked_SeqSBAIJ(Mat A,PetscInt m,const PetscInt im[],PetscInt n,const PetscInt in[],const PetscScalar v[],InsertMode is)
635 {
636   Mat_SeqSBAIJ      *a = (Mat_SeqSBAIJ*)A->data;
637   PetscInt          *rp,k,low,high,t,ii,jj,row,nrow,i,col,l,rmax,N,lastcol = -1;
638   PetscInt          *imax      =a->imax,*ai=a->i,*ailen=a->ilen;
639   PetscInt          *aj        =a->j,nonew=a->nonew,bs2=a->bs2,bs=A->rmap->bs,stepval;
640   PetscBool         roworiented=a->roworiented;
641   const PetscScalar *value     = v;
642   MatScalar         *ap,*aa = a->a,*bap;
643 
644   PetscFunctionBegin;
645   if (roworiented) stepval = (n-1)*bs;
646   else stepval = (m-1)*bs;
647 
648   for (k=0; k<m; k++) { /* loop over added rows */
649     row = im[k];
650     if (row < 0) continue;
651     PetscCheck(row < a->mbs,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Block index row too large %" PetscInt_FMT " max %" PetscInt_FMT,row,a->mbs-1);
652     rp   = aj + ai[row];
653     ap   = aa + bs2*ai[row];
654     rmax = imax[row];
655     nrow = ailen[row];
656     low  = 0;
657     high = nrow;
658     for (l=0; l<n; l++) { /* loop over added columns */
659       if (in[l] < 0) continue;
660       col = in[l];
661       PetscCheck(col < a->nbs,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Block index column too large %" PetscInt_FMT " max %" PetscInt_FMT,col,a->nbs-1);
662       if (col < row) {
663         if (a->ignore_ltriangular) continue; /* ignore lower triangular block */
664         else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Lower triangular value cannot be set for sbaij format. Ignoring these values, run with -mat_ignore_lower_triangular or call MatSetOption(mat,MAT_IGNORE_LOWER_TRIANGULAR,PETSC_TRUE)");
665       }
666       if (roworiented) value = v + k*(stepval+bs)*bs + l*bs;
667       else value = v + l*(stepval+bs)*bs + k*bs;
668 
669       if (col <= lastcol) low = 0;
670       else high = nrow;
671 
672       lastcol = col;
673       while (high-low > 7) {
674         t = (low+high)/2;
675         if (rp[t] > col) high = t;
676         else             low  = t;
677       }
678       for (i=low; i<high; i++) {
679         if (rp[i] > col) break;
680         if (rp[i] == col) {
681           bap = ap +  bs2*i;
682           if (roworiented) {
683             if (is == ADD_VALUES) {
684               for (ii=0; ii<bs; ii++,value+=stepval) {
685                 for (jj=ii; jj<bs2; jj+=bs) {
686                   bap[jj] += *value++;
687                 }
688               }
689             } else {
690               for (ii=0; ii<bs; ii++,value+=stepval) {
691                 for (jj=ii; jj<bs2; jj+=bs) {
692                   bap[jj] = *value++;
693                 }
694                }
695             }
696           } else {
697             if (is == ADD_VALUES) {
698               for (ii=0; ii<bs; ii++,value+=stepval) {
699                 for (jj=0; jj<bs; jj++) {
700                   *bap++ += *value++;
701                 }
702               }
703             } else {
704               for (ii=0; ii<bs; ii++,value+=stepval) {
705                 for (jj=0; jj<bs; jj++) {
706                   *bap++  = *value++;
707                 }
708               }
709             }
710           }
711           goto noinsert2;
712         }
713       }
714       if (nonew == 1) goto noinsert2;
715       PetscCheck(nonew != -1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Inserting a new block index nonzero block (%" PetscInt_FMT ", %" PetscInt_FMT ") in the matrix", row, col);
716       MatSeqXAIJReallocateAIJ(A,a->mbs,bs2,nrow,row,col,rmax,aa,ai,aj,rp,ap,imax,nonew,MatScalar);
717       N = nrow++ - 1; high++;
718       /* shift up all the later entries in this row */
719       PetscCall(PetscArraymove(rp+i+1,rp+i,N-i+1));
720       PetscCall(PetscArraymove(ap+bs2*(i+1),ap+bs2*i,bs2*(N-i+1)));
721       PetscCall(PetscArrayzero(ap+bs2*i,bs2));
722       rp[i] = col;
723       bap   = ap +  bs2*i;
724       if (roworiented) {
725         for (ii=0; ii<bs; ii++,value+=stepval) {
726           for (jj=ii; jj<bs2; jj+=bs) {
727             bap[jj] = *value++;
728           }
729         }
730       } else {
731         for (ii=0; ii<bs; ii++,value+=stepval) {
732           for (jj=0; jj<bs; jj++) {
733             *bap++ = *value++;
734           }
735         }
736        }
737     noinsert2:;
738       low = i;
739     }
740     ailen[row] = nrow;
741   }
742   PetscFunctionReturn(0);
743 }
744 
745 /*
746     This is not yet used
747 */
748 PetscErrorCode MatAssemblyEnd_SeqSBAIJ_SeqAIJ_Inode(Mat A)
749 {
750   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
751   const PetscInt *ai = a->i, *aj = a->j,*cols;
752   PetscInt       i   = 0,j,blk_size,m = A->rmap->n,node_count = 0,nzx,nzy,*ns,row,nz,cnt,cnt2,*counts;
753   PetscBool      flag;
754 
755   PetscFunctionBegin;
756   PetscCall(PetscMalloc1(m,&ns));
757   while (i < m) {
758     nzx = ai[i+1] - ai[i];       /* Number of nonzeros */
759     /* Limits the number of elements in a node to 'a->inode.limit' */
760     for (j=i+1,blk_size=1; j<m && blk_size <a->inode.limit; ++j,++blk_size) {
761       nzy = ai[j+1] - ai[j];
762       if (nzy != (nzx - j + i)) break;
763       PetscCall(PetscArraycmp(aj + ai[i] + j - i,aj + ai[j],nzy,&flag));
764       if (!flag) break;
765     }
766     ns[node_count++] = blk_size;
767 
768     i = j;
769   }
770   if (!a->inode.size && m && node_count > .9*m) {
771     PetscCall(PetscFree(ns));
772     PetscCall(PetscInfo(A,"Found %" PetscInt_FMT " nodes out of %" PetscInt_FMT " rows. Not using Inode routines\n",node_count,m));
773   } else {
774     a->inode.node_count = node_count;
775 
776     PetscCall(PetscMalloc1(node_count,&a->inode.size));
777     PetscCall(PetscLogObjectMemory((PetscObject)A,node_count*sizeof(PetscInt)));
778     PetscCall(PetscArraycpy(a->inode.size,ns,node_count));
779     PetscCall(PetscFree(ns));
780     PetscCall(PetscInfo(A,"Found %" PetscInt_FMT " nodes of %" PetscInt_FMT ". Limit used: %" PetscInt_FMT ". Using Inode routines\n",node_count,m,a->inode.limit));
781 
782     /* count collections of adjacent columns in each inode */
783     row = 0;
784     cnt = 0;
785     for (i=0; i<node_count; i++) {
786       cols = aj + ai[row] + a->inode.size[i];
787       nz   = ai[row+1] - ai[row] - a->inode.size[i];
788       for (j=1; j<nz; j++) {
789         if (cols[j] != cols[j-1]+1) cnt++;
790       }
791       cnt++;
792       row += a->inode.size[i];
793     }
794     PetscCall(PetscMalloc1(2*cnt,&counts));
795     cnt  = 0;
796     row  = 0;
797     for (i=0; i<node_count; i++) {
798       cols = aj + ai[row] + a->inode.size[i];
799       counts[2*cnt] = cols[0];
800       nz   = ai[row+1] - ai[row] - a->inode.size[i];
801       cnt2 = 1;
802       for (j=1; j<nz; j++) {
803         if (cols[j] != cols[j-1]+1) {
804           counts[2*(cnt++)+1] = cnt2;
805           counts[2*cnt]       = cols[j];
806           cnt2 = 1;
807         } else cnt2++;
808       }
809       counts[2*(cnt++)+1] = cnt2;
810       row += a->inode.size[i];
811     }
812     PetscCall(PetscIntView(2*cnt,counts,NULL));
813   }
814   PetscFunctionReturn(0);
815 }
816 
817 PetscErrorCode MatAssemblyEnd_SeqSBAIJ(Mat A,MatAssemblyType mode)
818 {
819   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
820   PetscInt       fshift = 0,i,*ai = a->i,*aj = a->j,*imax = a->imax;
821   PetscInt       m      = A->rmap->N,*ip,N,*ailen = a->ilen;
822   PetscInt       mbs    = a->mbs,bs2 = a->bs2,rmax = 0;
823   MatScalar      *aa    = a->a,*ap;
824 
825   PetscFunctionBegin;
826   if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(0);
827 
828   if (m) rmax = ailen[0];
829   for (i=1; i<mbs; i++) {
830     /* move each row back by the amount of empty slots (fshift) before it*/
831     fshift += imax[i-1] - ailen[i-1];
832     rmax    = PetscMax(rmax,ailen[i]);
833     if (fshift) {
834       ip = aj + ai[i];
835       ap = aa + bs2*ai[i];
836       N  = ailen[i];
837       PetscCall(PetscArraymove(ip-fshift,ip,N));
838       PetscCall(PetscArraymove(ap-bs2*fshift,ap,bs2*N));
839     }
840     ai[i] = ai[i-1] + ailen[i-1];
841   }
842   if (mbs) {
843     fshift += imax[mbs-1] - ailen[mbs-1];
844     ai[mbs] = ai[mbs-1] + ailen[mbs-1];
845   }
846   /* reset ilen and imax for each row */
847   for (i=0; i<mbs; i++) {
848     ailen[i] = imax[i] = ai[i+1] - ai[i];
849   }
850   a->nz = ai[mbs];
851 
852   /* diagonals may have moved, reset it */
853   if (a->diag) PetscCall(PetscArraycpy(a->diag,ai,mbs));
854   PetscCheck(!fshift || a->nounused != -1,PETSC_COMM_SELF,PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT " block size %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, A->rmap->bs, fshift*bs2);
855 
856   PetscCall(PetscInfo(A,"Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT ", block size %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded, %" PetscInt_FMT " used\n",m,A->rmap->N,A->rmap->bs,fshift*bs2,a->nz*bs2));
857   PetscCall(PetscInfo(A,"Number of mallocs during MatSetValues is %" PetscInt_FMT "\n",a->reallocs));
858   PetscCall(PetscInfo(A,"Most nonzeros blocks in any row is %" PetscInt_FMT "\n",rmax));
859 
860   A->info.mallocs    += a->reallocs;
861   a->reallocs         = 0;
862   A->info.nz_unneeded = (PetscReal)fshift*bs2;
863   a->idiagvalid       = PETSC_FALSE;
864   a->rmax             = rmax;
865 
866   if (A->cmap->n < 65536 && A->cmap->bs == 1) {
867     if (a->jshort && a->free_jshort) {
868       /* when matrix data structure is changed, previous jshort must be replaced */
869       PetscCall(PetscFree(a->jshort));
870     }
871     PetscCall(PetscMalloc1(a->i[A->rmap->n],&a->jshort));
872     PetscCall(PetscLogObjectMemory((PetscObject)A,a->i[A->rmap->n]*sizeof(unsigned short)));
873     for (i=0; i<a->i[A->rmap->n]; i++) a->jshort[i] = a->j[i];
874     A->ops->mult   = MatMult_SeqSBAIJ_1_ushort;
875     A->ops->sor    = MatSOR_SeqSBAIJ_ushort;
876     a->free_jshort = PETSC_TRUE;
877   }
878   PetscFunctionReturn(0);
879 }
880 
881 /*
882    This function returns an array of flags which indicate the locations of contiguous
883    blocks that should be zeroed. for eg: if bs = 3  and is = [0,1,2,3,5,6,7,8,9]
884    then the resulting sizes = [3,1,1,3,1] corresponding to sets [(0,1,2),(3),(5),(6,7,8),(9)]
885    Assume: sizes should be long enough to hold all the values.
886 */
887 PetscErrorCode MatZeroRows_SeqSBAIJ_Check_Blocks(PetscInt idx[],PetscInt n,PetscInt bs,PetscInt sizes[], PetscInt *bs_max)
888 {
889   PetscInt  i,j,k,row;
890   PetscBool flg;
891 
892   PetscFunctionBegin;
893   for (i=0,j=0; i<n; j++) {
894     row = idx[i];
895     if (row%bs!=0) { /* Not the beginning of a block */
896       sizes[j] = 1;
897       i++;
898     } else if (i+bs > n) { /* Beginning of a block, but complete block doesn't exist (at idx end) */
899       sizes[j] = 1;         /* Also makes sure at least 'bs' values exist for next else */
900       i++;
901     } else { /* Beginning of the block, so check if the complete block exists */
902       flg = PETSC_TRUE;
903       for (k=1; k<bs; k++) {
904         if (row+k != idx[i+k]) { /* break in the block */
905           flg = PETSC_FALSE;
906           break;
907         }
908       }
909       if (flg) { /* No break in the bs */
910         sizes[j] = bs;
911         i       += bs;
912       } else {
913         sizes[j] = 1;
914         i++;
915       }
916     }
917   }
918   *bs_max = j;
919   PetscFunctionReturn(0);
920 }
921 
922 /* Only add/insert a(i,j) with i<=j (blocks).
923    Any a(i,j) with i>j input by user is ingored.
924 */
925 
926 PetscErrorCode MatSetValues_SeqSBAIJ(Mat A,PetscInt m,const PetscInt im[],PetscInt n,const PetscInt in[],const PetscScalar v[],InsertMode is)
927 {
928   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)A->data;
929   PetscInt       *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax,N,lastcol = -1;
930   PetscInt       *imax=a->imax,*ai=a->i,*ailen=a->ilen,roworiented=a->roworiented;
931   PetscInt       *aj  =a->j,nonew=a->nonew,bs=A->rmap->bs,brow,bcol;
932   PetscInt       ridx,cidx,bs2=a->bs2;
933   MatScalar      *ap,value,*aa=a->a,*bap;
934 
935   PetscFunctionBegin;
936   for (k=0; k<m; k++) { /* loop over added rows */
937     row  = im[k];       /* row number */
938     brow = row/bs;      /* block row number */
939     if (row < 0) continue;
940     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);
941     rp   = aj + ai[brow]; /*ptr to beginning of column value of the row block*/
942     ap   = aa + bs2*ai[brow]; /*ptr to beginning of element value of the row block*/
943     rmax = imax[brow];  /* maximum space allocated for this row */
944     nrow = ailen[brow]; /* actual length of this row */
945     low  = 0;
946     high = nrow;
947     for (l=0; l<n; l++) { /* loop over added columns */
948       if (in[l] < 0) continue;
949       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);
950       col  = in[l];
951       bcol = col/bs;              /* block col number */
952 
953       if (brow > bcol) {
954         if (a->ignore_ltriangular) continue; /* ignore lower triangular values */
955         else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Lower triangular value cannot be set for sbaij format. Ignoring these values, run with -mat_ignore_lower_triangular or call MatSetOption(mat,MAT_IGNORE_LOWER_TRIANGULAR,PETSC_TRUE)");
956       }
957 
958       ridx = row % bs; cidx = col % bs; /*row and col index inside the block */
959       if ((brow==bcol && ridx<=cidx) || (brow<bcol)) {
960         /* element value a(k,l) */
961         if (roworiented) value = v[l + k*n];
962         else value = v[k + l*m];
963 
964         /* move pointer bap to a(k,l) quickly and add/insert value */
965         if (col <= lastcol) low = 0;
966         else high = nrow;
967 
968         lastcol = col;
969         while (high-low > 7) {
970           t = (low+high)/2;
971           if (rp[t] > bcol) high = t;
972           else              low  = t;
973         }
974         for (i=low; i<high; i++) {
975           if (rp[i] > bcol) break;
976           if (rp[i] == bcol) {
977             bap = ap +  bs2*i + bs*cidx + ridx;
978             if (is == ADD_VALUES) *bap += value;
979             else                  *bap  = value;
980             /* for diag block, add/insert its symmetric element a(cidx,ridx) */
981             if (brow == bcol && ridx < cidx) {
982               bap = ap +  bs2*i + bs*ridx + cidx;
983               if (is == ADD_VALUES) *bap += value;
984               else                  *bap  = value;
985             }
986             goto noinsert1;
987           }
988         }
989 
990         if (nonew == 1) goto noinsert1;
991         PetscCheck(nonew != -1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Inserting a new nonzero (%" PetscInt_FMT ", %" PetscInt_FMT ") in the matrix", row, col);
992         MatSeqXAIJReallocateAIJ(A,a->mbs,bs2,nrow,brow,bcol,rmax,aa,ai,aj,rp,ap,imax,nonew,MatScalar);
993 
994         N = nrow++ - 1; high++;
995         /* shift up all the later entries in this row */
996         PetscCall(PetscArraymove(rp+i+1,rp+i,N-i+1));
997         PetscCall(PetscArraymove(ap+bs2*(i+1),ap+bs2*i,bs2*(N-i+1)));
998         PetscCall(PetscArrayzero(ap+bs2*i,bs2));
999         rp[i]                      = bcol;
1000         ap[bs2*i + bs*cidx + ridx] = value;
1001         /* for diag block, add/insert its symmetric element a(cidx,ridx) */
1002         if (brow == bcol && ridx < cidx) {
1003           ap[bs2*i + bs*ridx + cidx] = value;
1004         }
1005         A->nonzerostate++;
1006 noinsert1:;
1007         low = i;
1008       }
1009     }   /* end of loop over added columns */
1010     ailen[brow] = nrow;
1011   }   /* end of loop over added rows */
1012   PetscFunctionReturn(0);
1013 }
1014 
1015 PetscErrorCode MatICCFactor_SeqSBAIJ(Mat inA,IS row,const MatFactorInfo *info)
1016 {
1017   Mat_SeqSBAIJ   *a = (Mat_SeqSBAIJ*)inA->data;
1018   Mat            outA;
1019   PetscBool      row_identity;
1020 
1021   PetscFunctionBegin;
1022   PetscCheck(info->levels == 0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Only levels=0 is supported for in-place icc");
1023   PetscCall(ISIdentity(row,&row_identity));
1024   PetscCheck(row_identity,PETSC_COMM_SELF,PETSC_ERR_SUP,"Matrix reordering is not supported");
1025   PetscCheck(inA->rmap->bs == 1,PETSC_COMM_SELF,PETSC_ERR_SUP,"Matrix block size %" PetscInt_FMT " is not supported",inA->rmap->bs); /* Need to replace MatCholeskyFactorSymbolic_SeqSBAIJ_MSR()! */
1026 
1027   outA            = inA;
1028   inA->factortype = MAT_FACTOR_ICC;
1029   PetscCall(PetscFree(inA->solvertype));
1030   PetscCall(PetscStrallocpy(MATSOLVERPETSC,&inA->solvertype));
1031 
1032   PetscCall(MatMarkDiagonal_SeqSBAIJ(inA));
1033   PetscCall(MatSeqSBAIJSetNumericFactorization_inplace(inA,row_identity));
1034 
1035   PetscCall(PetscObjectReference((PetscObject)row));
1036   PetscCall(ISDestroy(&a->row));
1037   a->row = row;
1038   PetscCall(PetscObjectReference((PetscObject)row));
1039   PetscCall(ISDestroy(&a->col));
1040   a->col = row;
1041 
1042   /* Create the invert permutation so that it can be used in MatCholeskyFactorNumeric() */
1043   if (a->icol) PetscCall(ISInvertPermutation(row,PETSC_DECIDE, &a->icol));
1044   PetscCall(PetscLogObjectParent((PetscObject)inA,(PetscObject)a->icol));
1045 
1046   if (!a->solve_work) {
1047     PetscCall(PetscMalloc1(inA->rmap->N+inA->rmap->bs,&a->solve_work));
1048     PetscCall(PetscLogObjectMemory((PetscObject)inA,(inA->rmap->N+inA->rmap->bs)*sizeof(PetscScalar)));
1049   }
1050 
1051   PetscCall(MatCholeskyFactorNumeric(outA,inA,info));
1052   PetscFunctionReturn(0);
1053 }
1054 
1055 PetscErrorCode  MatSeqSBAIJSetColumnIndices_SeqSBAIJ(Mat mat,PetscInt *indices)
1056 {
1057   Mat_SeqSBAIJ   *baij = (Mat_SeqSBAIJ*)mat->data;
1058   PetscInt       i,nz,n;
1059 
1060   PetscFunctionBegin;
1061   nz = baij->maxnz;
1062   n  = mat->cmap->n;
1063   for (i=0; i<nz; i++) baij->j[i] = indices[i];
1064 
1065   baij->nz = nz;
1066   for (i=0; i<n; i++) baij->ilen[i] = baij->imax[i];
1067 
1068   PetscCall(MatSetOption(mat,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE));
1069   PetscFunctionReturn(0);
1070 }
1071 
1072 /*@
1073   MatSeqSBAIJSetColumnIndices - Set the column indices for all the rows
1074   in the matrix.
1075 
1076   Input Parameters:
1077   +  mat     - the SeqSBAIJ matrix
1078   -  indices - the column indices
1079 
1080   Level: advanced
1081 
1082   Notes:
1083   This can be called if you have precomputed the nonzero structure of the
1084   matrix and want to provide it to the matrix object to improve the performance
1085   of the MatSetValues() operation.
1086 
1087   You MUST have set the correct numbers of nonzeros per row in the call to
1088   MatCreateSeqSBAIJ(), and the columns indices MUST be sorted.
1089 
1090   MUST be called before any calls to MatSetValues()
1091 
1092   .seealso: `MatCreateSeqSBAIJ`
1093 @*/
1094 PetscErrorCode  MatSeqSBAIJSetColumnIndices(Mat mat,PetscInt *indices)
1095 {
1096   PetscFunctionBegin;
1097   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1098   PetscValidIntPointer(indices,2);
1099   PetscUseMethod(mat,"MatSeqSBAIJSetColumnIndices_C",(Mat,PetscInt*),(mat,indices));
1100   PetscFunctionReturn(0);
1101 }
1102 
1103 PetscErrorCode MatCopy_SeqSBAIJ(Mat A,Mat B,MatStructure str)
1104 {
1105   PetscBool      isbaij;
1106 
1107   PetscFunctionBegin;
1108   PetscCall(PetscObjectTypeCompareAny((PetscObject)B,&isbaij,MATSEQSBAIJ,MATMPISBAIJ,""));
1109   PetscCheck(isbaij,PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)B)->type_name);
1110   /* If the two matrices have the same copy implementation and nonzero pattern, use fast copy. */
1111   if (str == SAME_NONZERO_PATTERN && A->ops->copy == B->ops->copy) {
1112     Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
1113     Mat_SeqSBAIJ *b = (Mat_SeqSBAIJ*)B->data;
1114 
1115     PetscCheck(a->i[a->mbs] == b->i[b->mbs],PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of nonzeros in two matrices are different");
1116     PetscCheck(a->mbs == b->mbs,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of rows in two matrices are different");
1117     PetscCheck(a->bs2 == b->bs2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Different block size");
1118     PetscCall(PetscArraycpy(b->a,a->a,a->bs2*a->i[a->mbs]));
1119     PetscCall(PetscObjectStateIncrease((PetscObject)B));
1120   } else {
1121     PetscCall(MatGetRowUpperTriangular(A));
1122     PetscCall(MatCopy_Basic(A,B,str));
1123     PetscCall(MatRestoreRowUpperTriangular(A));
1124   }
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 PetscErrorCode MatSetUp_SeqSBAIJ(Mat A)
1129 {
1130   PetscFunctionBegin;
1131   PetscCall(MatSeqSBAIJSetPreallocation(A,A->rmap->bs,PETSC_DEFAULT,NULL));
1132   PetscFunctionReturn(0);
1133 }
1134 
1135 static PetscErrorCode MatSeqSBAIJGetArray_SeqSBAIJ(Mat A,PetscScalar *array[])
1136 {
1137   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
1138 
1139   PetscFunctionBegin;
1140   *array = a->a;
1141   PetscFunctionReturn(0);
1142 }
1143 
1144 static PetscErrorCode MatSeqSBAIJRestoreArray_SeqSBAIJ(Mat A,PetscScalar *array[])
1145 {
1146   PetscFunctionBegin;
1147   *array = NULL;
1148   PetscFunctionReturn(0);
1149 }
1150 
1151 PetscErrorCode MatAXPYGetPreallocation_SeqSBAIJ(Mat Y,Mat X,PetscInt *nnz)
1152 {
1153   PetscInt       bs = Y->rmap->bs,mbs = Y->rmap->N/bs;
1154   Mat_SeqSBAIJ   *x = (Mat_SeqSBAIJ*)X->data;
1155   Mat_SeqSBAIJ   *y = (Mat_SeqSBAIJ*)Y->data;
1156 
1157   PetscFunctionBegin;
1158   /* Set the number of nonzeros in the new matrix */
1159   PetscCall(MatAXPYGetPreallocation_SeqX_private(mbs,x->i,x->j,y->i,y->j,nnz));
1160   PetscFunctionReturn(0);
1161 }
1162 
1163 PetscErrorCode MatAXPY_SeqSBAIJ(Mat Y,PetscScalar a,Mat X,MatStructure str)
1164 {
1165   Mat_SeqSBAIJ   *x=(Mat_SeqSBAIJ*)X->data, *y=(Mat_SeqSBAIJ*)Y->data;
1166   PetscInt       bs=Y->rmap->bs,bs2=bs*bs;
1167   PetscBLASInt   one = 1;
1168 
1169   PetscFunctionBegin;
1170   if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) {
1171     PetscBool e = x->nz == y->nz && x->mbs == y->mbs ? PETSC_TRUE : PETSC_FALSE;
1172     if (e) {
1173       PetscCall(PetscArraycmp(x->i,y->i,x->mbs+1,&e));
1174       if (e) {
1175         PetscCall(PetscArraycmp(x->j,y->j,x->i[x->mbs],&e));
1176         if (e) str = SAME_NONZERO_PATTERN;
1177       }
1178     }
1179     if (!e) PetscCheck(str != SAME_NONZERO_PATTERN,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"MatStructure is not SAME_NONZERO_PATTERN");
1180   }
1181   if (str == SAME_NONZERO_PATTERN) {
1182     PetscScalar  alpha = a;
1183     PetscBLASInt bnz;
1184     PetscCall(PetscBLASIntCast(x->nz*bs2,&bnz));
1185     PetscStackCallBLAS("BLASaxpy",BLASaxpy_(&bnz,&alpha,x->a,&one,y->a,&one));
1186     PetscCall(PetscObjectStateIncrease((PetscObject)Y));
1187   } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */
1188     PetscCall(MatSetOption(X,MAT_GETROW_UPPERTRIANGULAR,PETSC_TRUE));
1189     PetscCall(MatAXPY_Basic(Y,a,X,str));
1190     PetscCall(MatSetOption(X,MAT_GETROW_UPPERTRIANGULAR,PETSC_FALSE));
1191   } else {
1192     Mat      B;
1193     PetscInt *nnz;
1194     PetscCheck(bs == X->rmap->bs,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Matrices must have same block size");
1195     PetscCall(MatGetRowUpperTriangular(X));
1196     PetscCall(MatGetRowUpperTriangular(Y));
1197     PetscCall(PetscMalloc1(Y->rmap->N,&nnz));
1198     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y),&B));
1199     PetscCall(PetscObjectSetName((PetscObject)B,((PetscObject)Y)->name));
1200     PetscCall(MatSetSizes(B,Y->rmap->n,Y->cmap->n,Y->rmap->N,Y->cmap->N));
1201     PetscCall(MatSetBlockSizesFromMats(B,Y,Y));
1202     PetscCall(MatSetType(B,((PetscObject)Y)->type_name));
1203     PetscCall(MatAXPYGetPreallocation_SeqSBAIJ(Y,X,nnz));
1204     PetscCall(MatSeqSBAIJSetPreallocation(B,bs,0,nnz));
1205 
1206     PetscCall(MatAXPY_BasicWithPreallocation(B,Y,a,X,str));
1207 
1208     PetscCall(MatHeaderMerge(Y,&B));
1209     PetscCall(PetscFree(nnz));
1210     PetscCall(MatRestoreRowUpperTriangular(X));
1211     PetscCall(MatRestoreRowUpperTriangular(Y));
1212   }
1213   PetscFunctionReturn(0);
1214 }
1215 
1216 PetscErrorCode MatIsSymmetric_SeqSBAIJ(Mat A,PetscReal tol,PetscBool  *flg)
1217 {
1218   PetscFunctionBegin;
1219   *flg = PETSC_TRUE;
1220   PetscFunctionReturn(0);
1221 }
1222 
1223 PetscErrorCode MatIsStructurallySymmetric_SeqSBAIJ(Mat A,PetscBool  *flg)
1224 {
1225   PetscFunctionBegin;
1226   *flg = PETSC_TRUE;
1227   PetscFunctionReturn(0);
1228 }
1229 
1230 PetscErrorCode MatIsHermitian_SeqSBAIJ(Mat A,PetscReal tol,PetscBool  *flg)
1231 {
1232   PetscFunctionBegin;
1233   *flg = PETSC_FALSE;
1234   PetscFunctionReturn(0);
1235 }
1236 
1237 PetscErrorCode MatConjugate_SeqSBAIJ(Mat A)
1238 {
1239 #if defined(PETSC_USE_COMPLEX)
1240   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
1241   PetscInt     i,nz = a->bs2*a->i[a->mbs];
1242   MatScalar    *aa = a->a;
1243 
1244   PetscFunctionBegin;
1245   for (i=0; i<nz; i++) aa[i] = PetscConj(aa[i]);
1246 #else
1247   PetscFunctionBegin;
1248 #endif
1249   PetscFunctionReturn(0);
1250 }
1251 
1252 PetscErrorCode MatRealPart_SeqSBAIJ(Mat A)
1253 {
1254   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
1255   PetscInt     i,nz = a->bs2*a->i[a->mbs];
1256   MatScalar    *aa = a->a;
1257 
1258   PetscFunctionBegin;
1259   for (i=0; i<nz; i++) aa[i] = PetscRealPart(aa[i]);
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 PetscErrorCode MatImaginaryPart_SeqSBAIJ(Mat A)
1264 {
1265   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ*)A->data;
1266   PetscInt     i,nz = a->bs2*a->i[a->mbs];
1267   MatScalar    *aa = a->a;
1268 
1269   PetscFunctionBegin;
1270   for (i=0; i<nz; i++) aa[i] = PetscImaginaryPart(aa[i]);
1271   PetscFunctionReturn(0);
1272 }
1273 
1274 PetscErrorCode MatZeroRowsColumns_SeqSBAIJ(Mat A,PetscInt is_n,const PetscInt is_idx[],PetscScalar diag,Vec x, Vec b)
1275 {
1276   Mat_SeqSBAIJ      *baij=(Mat_SeqSBAIJ*)A->data;
1277   PetscInt          i,j,k,count;
1278   PetscInt          bs   =A->rmap->bs,bs2=baij->bs2,row,col;
1279   PetscScalar       zero = 0.0;
1280   MatScalar         *aa;
1281   const PetscScalar *xx;
1282   PetscScalar       *bb;
1283   PetscBool         *zeroed,vecs = PETSC_FALSE;
1284 
1285   PetscFunctionBegin;
1286   /* fix right hand side if needed */
1287   if (x && b) {
1288     PetscCall(VecGetArrayRead(x,&xx));
1289     PetscCall(VecGetArray(b,&bb));
1290     vecs = PETSC_TRUE;
1291   }
1292 
1293   /* zero the columns */
1294   PetscCall(PetscCalloc1(A->rmap->n,&zeroed));
1295   for (i=0; i<is_n; i++) {
1296     PetscCheck(is_idx[i] >= 0 && is_idx[i] < A->rmap->N,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"row %" PetscInt_FMT " out of range",is_idx[i]);
1297     zeroed[is_idx[i]] = PETSC_TRUE;
1298   }
1299   if (vecs) {
1300     for (i=0; i<A->rmap->N; i++) {
1301       row = i/bs;
1302       for (j=baij->i[row]; j<baij->i[row+1]; j++) {
1303         for (k=0; k<bs; k++) {
1304           col = bs*baij->j[j] + k;
1305           if (col <= i) continue;
1306           aa = ((MatScalar*)(baij->a)) + j*bs2 + (i%bs) + bs*k;
1307           if (!zeroed[i] && zeroed[col]) bb[i]   -= aa[0]*xx[col];
1308           if (zeroed[i] && !zeroed[col]) bb[col] -= aa[0]*xx[i];
1309         }
1310       }
1311     }
1312     for (i=0; i<is_n; i++) bb[is_idx[i]] = diag*xx[is_idx[i]];
1313   }
1314 
1315   for (i=0; i<A->rmap->N; i++) {
1316     if (!zeroed[i]) {
1317       row = i/bs;
1318       for (j=baij->i[row]; j<baij->i[row+1]; j++) {
1319         for (k=0; k<bs; k++) {
1320           col = bs*baij->j[j] + k;
1321           if (zeroed[col]) {
1322             aa = ((MatScalar*)(baij->a)) + j*bs2 + (i%bs) + bs*k;
1323             aa[0] = 0.0;
1324           }
1325         }
1326       }
1327     }
1328   }
1329   PetscCall(PetscFree(zeroed));
1330   if (vecs) {
1331     PetscCall(VecRestoreArrayRead(x,&xx));
1332     PetscCall(VecRestoreArray(b,&bb));
1333   }
1334 
1335   /* zero the rows */
1336   for (i=0; i<is_n; i++) {
1337     row   = is_idx[i];
1338     count = (baij->i[row/bs +1] - baij->i[row/bs])*bs;
1339     aa    = ((MatScalar*)(baij->a)) + baij->i[row/bs]*bs2 + (row%bs);
1340     for (k=0; k<count; k++) {
1341       aa[0] =  zero;
1342       aa   += bs;
1343     }
1344     if (diag != 0.0) {
1345       PetscCall((*A->ops->setvalues)(A,1,&row,1,&row,&diag,INSERT_VALUES));
1346     }
1347   }
1348   PetscCall(MatAssemblyEnd_SeqSBAIJ(A,MAT_FINAL_ASSEMBLY));
1349   PetscFunctionReturn(0);
1350 }
1351 
1352 PetscErrorCode MatShift_SeqSBAIJ(Mat Y,PetscScalar a)
1353 {
1354   Mat_SeqSBAIJ    *aij = (Mat_SeqSBAIJ*)Y->data;
1355 
1356   PetscFunctionBegin;
1357   if (!Y->preallocated || !aij->nz) {
1358     PetscCall(MatSeqSBAIJSetPreallocation(Y,Y->rmap->bs,1,NULL));
1359   }
1360   PetscCall(MatShift_Basic(Y,a));
1361   PetscFunctionReturn(0);
1362 }
1363 
1364 /* -------------------------------------------------------------------*/
1365 static struct _MatOps MatOps_Values = {MatSetValues_SeqSBAIJ,
1366                                        MatGetRow_SeqSBAIJ,
1367                                        MatRestoreRow_SeqSBAIJ,
1368                                        MatMult_SeqSBAIJ_N,
1369                                /*  4*/ MatMultAdd_SeqSBAIJ_N,
1370                                        MatMult_SeqSBAIJ_N,       /* transpose versions are same as non-transpose versions */
1371                                        MatMultAdd_SeqSBAIJ_N,
1372                                        NULL,
1373                                        NULL,
1374                                        NULL,
1375                                /* 10*/ NULL,
1376                                        NULL,
1377                                        MatCholeskyFactor_SeqSBAIJ,
1378                                        MatSOR_SeqSBAIJ,
1379                                        MatTranspose_SeqSBAIJ,
1380                                /* 15*/ MatGetInfo_SeqSBAIJ,
1381                                        MatEqual_SeqSBAIJ,
1382                                        MatGetDiagonal_SeqSBAIJ,
1383                                        MatDiagonalScale_SeqSBAIJ,
1384                                        MatNorm_SeqSBAIJ,
1385                                /* 20*/ NULL,
1386                                        MatAssemblyEnd_SeqSBAIJ,
1387                                        MatSetOption_SeqSBAIJ,
1388                                        MatZeroEntries_SeqSBAIJ,
1389                                /* 24*/ NULL,
1390                                        NULL,
1391                                        NULL,
1392                                        NULL,
1393                                        NULL,
1394                                /* 29*/ MatSetUp_SeqSBAIJ,
1395                                        NULL,
1396                                        NULL,
1397                                        NULL,
1398                                        NULL,
1399                                /* 34*/ MatDuplicate_SeqSBAIJ,
1400                                        NULL,
1401                                        NULL,
1402                                        NULL,
1403                                        MatICCFactor_SeqSBAIJ,
1404                                /* 39*/ MatAXPY_SeqSBAIJ,
1405                                        MatCreateSubMatrices_SeqSBAIJ,
1406                                        MatIncreaseOverlap_SeqSBAIJ,
1407                                        MatGetValues_SeqSBAIJ,
1408                                        MatCopy_SeqSBAIJ,
1409                                /* 44*/ NULL,
1410                                        MatScale_SeqSBAIJ,
1411                                        MatShift_SeqSBAIJ,
1412                                        NULL,
1413                                        MatZeroRowsColumns_SeqSBAIJ,
1414                                /* 49*/ NULL,
1415                                        MatGetRowIJ_SeqSBAIJ,
1416                                        MatRestoreRowIJ_SeqSBAIJ,
1417                                        NULL,
1418                                        NULL,
1419                                /* 54*/ NULL,
1420                                        NULL,
1421                                        NULL,
1422                                        MatPermute_SeqSBAIJ,
1423                                        MatSetValuesBlocked_SeqSBAIJ,
1424                                /* 59*/ MatCreateSubMatrix_SeqSBAIJ,
1425                                        NULL,
1426                                        NULL,
1427                                        NULL,
1428                                        NULL,
1429                                /* 64*/ NULL,
1430                                        NULL,
1431                                        NULL,
1432                                        NULL,
1433                                        NULL,
1434                                /* 69*/ MatGetRowMaxAbs_SeqSBAIJ,
1435                                        NULL,
1436                                        MatConvert_MPISBAIJ_Basic,
1437                                        NULL,
1438                                        NULL,
1439                                /* 74*/ NULL,
1440                                        NULL,
1441                                        NULL,
1442                                        NULL,
1443                                        NULL,
1444                                /* 79*/ NULL,
1445                                        NULL,
1446                                        NULL,
1447                                        MatGetInertia_SeqSBAIJ,
1448                                        MatLoad_SeqSBAIJ,
1449                                /* 84*/ MatIsSymmetric_SeqSBAIJ,
1450                                        MatIsHermitian_SeqSBAIJ,
1451                                        MatIsStructurallySymmetric_SeqSBAIJ,
1452                                        NULL,
1453                                        NULL,
1454                                /* 89*/ NULL,
1455                                        NULL,
1456                                        NULL,
1457                                        NULL,
1458                                        NULL,
1459                                /* 94*/ NULL,
1460                                        NULL,
1461                                        NULL,
1462                                        NULL,
1463                                        NULL,
1464                                /* 99*/ NULL,
1465                                        NULL,
1466                                        NULL,
1467                                        MatConjugate_SeqSBAIJ,
1468                                        NULL,
1469                                /*104*/ NULL,
1470                                        MatRealPart_SeqSBAIJ,
1471                                        MatImaginaryPart_SeqSBAIJ,
1472                                        MatGetRowUpperTriangular_SeqSBAIJ,
1473                                        MatRestoreRowUpperTriangular_SeqSBAIJ,
1474                                /*109*/ NULL,
1475                                        NULL,
1476                                        NULL,
1477                                        NULL,
1478                                        MatMissingDiagonal_SeqSBAIJ,
1479                                /*114*/ NULL,
1480                                        NULL,
1481                                        NULL,
1482                                        NULL,
1483                                        NULL,
1484                                /*119*/ NULL,
1485                                        NULL,
1486                                        NULL,
1487                                        NULL,
1488                                        NULL,
1489                                /*124*/ NULL,
1490                                        NULL,
1491                                        NULL,
1492                                        NULL,
1493                                        NULL,
1494                                /*129*/ NULL,
1495                                        NULL,
1496                                        NULL,
1497                                        NULL,
1498                                        NULL,
1499                                /*134*/ NULL,
1500                                        NULL,
1501                                        NULL,
1502                                        NULL,
1503                                        NULL,
1504                                /*139*/ MatSetBlockSizes_Default,
1505                                        NULL,
1506                                        NULL,
1507                                        NULL,
1508                                        NULL,
1509                                 /*144*/MatCreateMPIMatConcatenateSeqMat_SeqSBAIJ,
1510                                        NULL,
1511                                        NULL,
1512                                        NULL
1513 };
1514 
1515 PetscErrorCode  MatStoreValues_SeqSBAIJ(Mat mat)
1516 {
1517   Mat_SeqSBAIJ   *aij = (Mat_SeqSBAIJ*)mat->data;
1518   PetscInt       nz   = aij->i[mat->rmap->N]*mat->rmap->bs*aij->bs2;
1519 
1520   PetscFunctionBegin;
1521   PetscCheck(aij->nonew == 1,PETSC_COMM_SELF,PETSC_ERR_ORDER,"Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
1522 
1523   /* allocate space for values if not already there */
1524   if (!aij->saved_values) {
1525     PetscCall(PetscMalloc1(nz+1,&aij->saved_values));
1526   }
1527 
1528   /* copy values over */
1529   PetscCall(PetscArraycpy(aij->saved_values,aij->a,nz));
1530   PetscFunctionReturn(0);
1531 }
1532 
1533 PetscErrorCode  MatRetrieveValues_SeqSBAIJ(Mat mat)
1534 {
1535   Mat_SeqSBAIJ   *aij = (Mat_SeqSBAIJ*)mat->data;
1536   PetscInt       nz = aij->i[mat->rmap->N]*mat->rmap->bs*aij->bs2;
1537 
1538   PetscFunctionBegin;
1539   PetscCheck(aij->nonew == 1,PETSC_COMM_SELF,PETSC_ERR_ORDER,"Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
1540   PetscCheck(aij->saved_values,PETSC_COMM_SELF,PETSC_ERR_ORDER,"Must call MatStoreValues(A);first");
1541 
1542   /* copy values over */
1543   PetscCall(PetscArraycpy(aij->a,aij->saved_values,nz));
1544   PetscFunctionReturn(0);
1545 }
1546 
1547 static PetscErrorCode  MatSeqSBAIJSetPreallocation_SeqSBAIJ(Mat B,PetscInt bs,PetscInt nz,PetscInt *nnz)
1548 {
1549   Mat_SeqSBAIJ   *b = (Mat_SeqSBAIJ*)B->data;
1550   PetscInt       i,mbs,nbs,bs2;
1551   PetscBool      skipallocation = PETSC_FALSE,flg = PETSC_FALSE,realalloc = PETSC_FALSE;
1552 
1553   PetscFunctionBegin;
1554   if (nz >= 0 || nnz) realalloc = PETSC_TRUE;
1555 
1556   PetscCall(MatSetBlockSize(B,PetscAbs(bs)));
1557   PetscCall(PetscLayoutSetUp(B->rmap));
1558   PetscCall(PetscLayoutSetUp(B->cmap));
1559   PetscCheck(B->rmap->N <= B->cmap->N,PETSC_COMM_SELF,PETSC_ERR_SUP,"SEQSBAIJ matrix cannot have more rows %" PetscInt_FMT " than columns %" PetscInt_FMT,B->rmap->N,B->cmap->N);
1560   PetscCall(PetscLayoutGetBlockSize(B->rmap,&bs));
1561 
1562   B->preallocated = PETSC_TRUE;
1563 
1564   mbs = B->rmap->N/bs;
1565   nbs = B->cmap->n/bs;
1566   bs2 = bs*bs;
1567 
1568   PetscCheck(mbs*bs == B->rmap->N && nbs*bs == B->cmap->n,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Number rows, cols must be divisible by blocksize");
1569 
1570   if (nz == MAT_SKIP_ALLOCATION) {
1571     skipallocation = PETSC_TRUE;
1572     nz             = 0;
1573   }
1574 
1575   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 3;
1576   PetscCheck(nz >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nz cannot be less than 0: value %" PetscInt_FMT,nz);
1577   if (nnz) {
1578     for (i=0; i<mbs; i++) {
1579       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]);
1580       PetscCheck(nnz[i] <= nbs,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nnz cannot be greater than block row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " block rowlength %" PetscInt_FMT,i,nnz[i],nbs);
1581     }
1582   }
1583 
1584   B->ops->mult             = MatMult_SeqSBAIJ_N;
1585   B->ops->multadd          = MatMultAdd_SeqSBAIJ_N;
1586   B->ops->multtranspose    = MatMult_SeqSBAIJ_N;
1587   B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_N;
1588 
1589   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options,((PetscObject)B)->prefix,"-mat_no_unroll",&flg,NULL));
1590   if (!flg) {
1591     switch (bs) {
1592     case 1:
1593       B->ops->mult             = MatMult_SeqSBAIJ_1;
1594       B->ops->multadd          = MatMultAdd_SeqSBAIJ_1;
1595       B->ops->multtranspose    = MatMult_SeqSBAIJ_1;
1596       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_1;
1597       break;
1598     case 2:
1599       B->ops->mult             = MatMult_SeqSBAIJ_2;
1600       B->ops->multadd          = MatMultAdd_SeqSBAIJ_2;
1601       B->ops->multtranspose    = MatMult_SeqSBAIJ_2;
1602       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_2;
1603       break;
1604     case 3:
1605       B->ops->mult             = MatMult_SeqSBAIJ_3;
1606       B->ops->multadd          = MatMultAdd_SeqSBAIJ_3;
1607       B->ops->multtranspose    = MatMult_SeqSBAIJ_3;
1608       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_3;
1609       break;
1610     case 4:
1611       B->ops->mult             = MatMult_SeqSBAIJ_4;
1612       B->ops->multadd          = MatMultAdd_SeqSBAIJ_4;
1613       B->ops->multtranspose    = MatMult_SeqSBAIJ_4;
1614       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_4;
1615       break;
1616     case 5:
1617       B->ops->mult             = MatMult_SeqSBAIJ_5;
1618       B->ops->multadd          = MatMultAdd_SeqSBAIJ_5;
1619       B->ops->multtranspose    = MatMult_SeqSBAIJ_5;
1620       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_5;
1621       break;
1622     case 6:
1623       B->ops->mult             = MatMult_SeqSBAIJ_6;
1624       B->ops->multadd          = MatMultAdd_SeqSBAIJ_6;
1625       B->ops->multtranspose    = MatMult_SeqSBAIJ_6;
1626       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_6;
1627       break;
1628     case 7:
1629       B->ops->mult             = MatMult_SeqSBAIJ_7;
1630       B->ops->multadd          = MatMultAdd_SeqSBAIJ_7;
1631       B->ops->multtranspose    = MatMult_SeqSBAIJ_7;
1632       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_7;
1633       break;
1634     }
1635   }
1636 
1637   b->mbs = mbs;
1638   b->nbs = nbs;
1639   if (!skipallocation) {
1640     if (!b->imax) {
1641       PetscCall(PetscMalloc2(mbs,&b->imax,mbs,&b->ilen));
1642 
1643       b->free_imax_ilen = PETSC_TRUE;
1644 
1645       PetscCall(PetscLogObjectMemory((PetscObject)B,2*mbs*sizeof(PetscInt)));
1646     }
1647     if (!nnz) {
1648       if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
1649       else if (nz <= 0) nz = 1;
1650       nz = PetscMin(nbs,nz);
1651       for (i=0; i<mbs; i++) b->imax[i] = nz;
1652       PetscCall(PetscIntMultError(nz,mbs,&nz));
1653     } else {
1654       PetscInt64 nz64 = 0;
1655       for (i=0; i<mbs; i++) {b->imax[i] = nnz[i]; nz64 += nnz[i];}
1656       PetscCall(PetscIntCast(nz64,&nz));
1657     }
1658     /* b->ilen will count nonzeros in each block row so far. */
1659     for (i=0; i<mbs; i++) b->ilen[i] = 0;
1660     /* nz=(nz+mbs)/2; */ /* total diagonal and superdiagonal nonzero blocks */
1661 
1662     /* allocate the matrix space */
1663     PetscCall(MatSeqXAIJFreeAIJ(B,&b->a,&b->j,&b->i));
1664     PetscCall(PetscMalloc3(bs2*nz,&b->a,nz,&b->j,B->rmap->N+1,&b->i));
1665     PetscCall(PetscLogObjectMemory((PetscObject)B,(B->rmap->N+1)*sizeof(PetscInt)+nz*(bs2*sizeof(PetscScalar)+sizeof(PetscInt))));
1666     PetscCall(PetscArrayzero(b->a,nz*bs2));
1667     PetscCall(PetscArrayzero(b->j,nz));
1668 
1669     b->singlemalloc = PETSC_TRUE;
1670 
1671     /* pointer to beginning of each row */
1672     b->i[0] = 0;
1673     for (i=1; i<mbs+1; i++) b->i[i] = b->i[i-1] + b->imax[i-1];
1674 
1675     b->free_a  = PETSC_TRUE;
1676     b->free_ij = PETSC_TRUE;
1677   } else {
1678     b->free_a  = PETSC_FALSE;
1679     b->free_ij = PETSC_FALSE;
1680   }
1681 
1682   b->bs2     = bs2;
1683   b->nz      = 0;
1684   b->maxnz   = nz;
1685   b->inew    = NULL;
1686   b->jnew    = NULL;
1687   b->anew    = NULL;
1688   b->a2anew  = NULL;
1689   b->permute = PETSC_FALSE;
1690 
1691   B->was_assembled = PETSC_FALSE;
1692   B->assembled     = PETSC_FALSE;
1693   if (realalloc) PetscCall(MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE));
1694   PetscFunctionReturn(0);
1695 }
1696 
1697 PetscErrorCode MatSeqSBAIJSetPreallocationCSR_SeqSBAIJ(Mat B,PetscInt bs,const PetscInt ii[],const PetscInt jj[], const PetscScalar V[])
1698 {
1699   PetscInt       i,j,m,nz,anz, nz_max=0,*nnz;
1700   PetscScalar    *values=NULL;
1701   PetscBool      roworiented = ((Mat_SeqSBAIJ*)B->data)->roworiented;
1702 
1703   PetscFunctionBegin;
1704   PetscCheck(bs >= 1,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_OUTOFRANGE,"Invalid block size specified, must be positive but it is %" PetscInt_FMT,bs);
1705   PetscCall(PetscLayoutSetBlockSize(B->rmap,bs));
1706   PetscCall(PetscLayoutSetBlockSize(B->cmap,bs));
1707   PetscCall(PetscLayoutSetUp(B->rmap));
1708   PetscCall(PetscLayoutSetUp(B->cmap));
1709   PetscCall(PetscLayoutGetBlockSize(B->rmap,&bs));
1710   m      = B->rmap->n/bs;
1711 
1712   PetscCheck(!ii[0],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"ii[0] must be 0 but it is %" PetscInt_FMT,ii[0]);
1713   PetscCall(PetscMalloc1(m+1,&nnz));
1714   for (i=0; i<m; i++) {
1715     nz = ii[i+1] - ii[i];
1716     PetscCheck(nz >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT,i,nz);
1717     anz = 0;
1718     for (j=0; j<nz; j++) {
1719       /* count only values on the diagonal or above */
1720       if (jj[ii[i] + j] >= i) {
1721         anz = nz - j;
1722         break;
1723       }
1724     }
1725     nz_max = PetscMax(nz_max,anz);
1726     nnz[i] = anz;
1727   }
1728   PetscCall(MatSeqSBAIJSetPreallocation(B,bs,0,nnz));
1729   PetscCall(PetscFree(nnz));
1730 
1731   values = (PetscScalar*)V;
1732   if (!values) {
1733     PetscCall(PetscCalloc1(bs*bs*nz_max,&values));
1734   }
1735   for (i=0; i<m; i++) {
1736     PetscInt          ncols  = ii[i+1] - ii[i];
1737     const PetscInt    *icols = jj + ii[i];
1738     if (!roworiented || bs == 1) {
1739       const PetscScalar *svals = values + (V ? (bs*bs*ii[i]) : 0);
1740       PetscCall(MatSetValuesBlocked_SeqSBAIJ(B,1,&i,ncols,icols,svals,INSERT_VALUES));
1741     } else {
1742       for (j=0; j<ncols; j++) {
1743         const PetscScalar *svals = values + (V ? (bs*bs*(ii[i]+j)) : 0);
1744         PetscCall(MatSetValuesBlocked_SeqSBAIJ(B,1,&i,1,&icols[j],svals,INSERT_VALUES));
1745       }
1746     }
1747   }
1748   if (!V) PetscCall(PetscFree(values));
1749   PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY));
1750   PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY));
1751   PetscCall(MatSetOption(B,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE));
1752   PetscFunctionReturn(0);
1753 }
1754 
1755 /*
1756    This is used to set the numeric factorization for both Cholesky and ICC symbolic factorization
1757 */
1758 PetscErrorCode MatSeqSBAIJSetNumericFactorization_inplace(Mat B,PetscBool natural)
1759 {
1760   PetscBool      flg = PETSC_FALSE;
1761   PetscInt       bs  = B->rmap->bs;
1762 
1763   PetscFunctionBegin;
1764   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options,((PetscObject)B)->prefix,"-mat_no_unroll",&flg,NULL));
1765   if (flg) bs = 8;
1766 
1767   if (!natural) {
1768     switch (bs) {
1769     case 1:
1770       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_1_inplace;
1771       break;
1772     case 2:
1773       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_2;
1774       break;
1775     case 3:
1776       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_3;
1777       break;
1778     case 4:
1779       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_4;
1780       break;
1781     case 5:
1782       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_5;
1783       break;
1784     case 6:
1785       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_6;
1786       break;
1787     case 7:
1788       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_7;
1789       break;
1790     default:
1791       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_N;
1792       break;
1793     }
1794   } else {
1795     switch (bs) {
1796     case 1:
1797       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_1_NaturalOrdering_inplace;
1798       break;
1799     case 2:
1800       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_2_NaturalOrdering;
1801       break;
1802     case 3:
1803       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_3_NaturalOrdering;
1804       break;
1805     case 4:
1806       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_4_NaturalOrdering;
1807       break;
1808     case 5:
1809       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_5_NaturalOrdering;
1810       break;
1811     case 6:
1812       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_6_NaturalOrdering;
1813       break;
1814     case 7:
1815       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_7_NaturalOrdering;
1816       break;
1817     default:
1818       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_N_NaturalOrdering;
1819       break;
1820     }
1821   }
1822   PetscFunctionReturn(0);
1823 }
1824 
1825 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqAIJ(Mat,MatType,MatReuse,Mat*);
1826 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqBAIJ(Mat,MatType,MatReuse,Mat*);
1827 static PetscErrorCode MatFactorGetSolverType_petsc(Mat A,MatSolverType *type)
1828 {
1829   PetscFunctionBegin;
1830   *type = MATSOLVERPETSC;
1831   PetscFunctionReturn(0);
1832 }
1833 
1834 PETSC_INTERN PetscErrorCode MatGetFactor_seqsbaij_petsc(Mat A,MatFactorType ftype,Mat *B)
1835 {
1836   PetscInt       n = A->rmap->n;
1837 
1838   PetscFunctionBegin;
1839 #if defined(PETSC_USE_COMPLEX)
1840   PetscCheck(!A->hermitian || A->symmetric || (ftype != MAT_FACTOR_CHOLESKY && ftype != MAT_FACTOR_ICC),PETSC_COMM_SELF,PETSC_ERR_SUP,"Hermitian CHOLESKY or ICC Factor is not supported");
1841 #endif
1842 
1843   PetscCall(MatCreate(PetscObjectComm((PetscObject)A),B));
1844   PetscCall(MatSetSizes(*B,n,n,n,n));
1845   if (ftype == MAT_FACTOR_CHOLESKY || ftype == MAT_FACTOR_ICC) {
1846     PetscCall(MatSetType(*B,MATSEQSBAIJ));
1847     PetscCall(MatSeqSBAIJSetPreallocation(*B,A->rmap->bs,MAT_SKIP_ALLOCATION,NULL));
1848 
1849     (*B)->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_SeqSBAIJ;
1850     (*B)->ops->iccfactorsymbolic      = MatICCFactorSymbolic_SeqSBAIJ;
1851     PetscCall(PetscStrallocpy(MATORDERINGNATURAL,(char**)&(*B)->preferredordering[MAT_FACTOR_CHOLESKY]));
1852     PetscCall(PetscStrallocpy(MATORDERINGNATURAL,(char**)&(*B)->preferredordering[MAT_FACTOR_ICC]));
1853   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Factor type not supported");
1854 
1855   (*B)->factortype = ftype;
1856   (*B)->canuseordering = PETSC_TRUE;
1857   PetscCall(PetscFree((*B)->solvertype));
1858   PetscCall(PetscStrallocpy(MATSOLVERPETSC,&(*B)->solvertype));
1859   PetscCall(PetscObjectComposeFunction((PetscObject)*B,"MatFactorGetSolverType_C",MatFactorGetSolverType_petsc));
1860   PetscFunctionReturn(0);
1861 }
1862 
1863 /*@C
1864    MatSeqSBAIJGetArray - gives access to the array where the data for a MATSEQSBAIJ matrix is stored
1865 
1866    Not Collective
1867 
1868    Input Parameter:
1869 .  mat - a MATSEQSBAIJ matrix
1870 
1871    Output Parameter:
1872 .   array - pointer to the data
1873 
1874    Level: intermediate
1875 
1876 .seealso: `MatSeqSBAIJRestoreArray()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`
1877 @*/
1878 PetscErrorCode  MatSeqSBAIJGetArray(Mat A,PetscScalar **array)
1879 {
1880   PetscFunctionBegin;
1881   PetscUseMethod(A,"MatSeqSBAIJGetArray_C",(Mat,PetscScalar**),(A,array));
1882   PetscFunctionReturn(0);
1883 }
1884 
1885 /*@C
1886    MatSeqSBAIJRestoreArray - returns access to the array where the data for a MATSEQSBAIJ matrix is stored obtained by MatSeqSBAIJGetArray()
1887 
1888    Not Collective
1889 
1890    Input Parameters:
1891 +  mat - a MATSEQSBAIJ matrix
1892 -  array - pointer to the data
1893 
1894    Level: intermediate
1895 
1896 .seealso: `MatSeqSBAIJGetArray()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`
1897 @*/
1898 PetscErrorCode  MatSeqSBAIJRestoreArray(Mat A,PetscScalar **array)
1899 {
1900   PetscFunctionBegin;
1901   PetscUseMethod(A,"MatSeqSBAIJRestoreArray_C",(Mat,PetscScalar**),(A,array));
1902   PetscFunctionReturn(0);
1903 }
1904 
1905 /*MC
1906   MATSEQSBAIJ - MATSEQSBAIJ = "seqsbaij" - A matrix type to be used for sequential symmetric block sparse matrices,
1907   based on block compressed sparse row format.  Only the upper triangular portion of the matrix is stored.
1908 
1909   For complex numbers by default this matrix is symmetric, NOT Hermitian symmetric. To make it Hermitian symmetric you
1910   can call MatSetOption(Mat, MAT_HERMITIAN).
1911 
1912   Options Database Keys:
1913   . -mat_type seqsbaij - sets the matrix type to "seqsbaij" during a call to MatSetFromOptions()
1914 
1915   Notes:
1916     By default if you insert values into the lower triangular part of the matrix they are simply ignored (since they are not
1917      stored and it is assumed they symmetric to the upper triangular). If you call MatSetOption(Mat,MAT_IGNORE_LOWER_TRIANGULAR,PETSC_FALSE) or use
1918      the options database -mat_ignore_lower_triangular false it will generate an error if you try to set a value in the lower triangular portion.
1919 
1920     The number of rows in the matrix must be less than or equal to the number of columns
1921 
1922   Level: beginner
1923 
1924   .seealso: `MatCreateSeqSBAIJ()`, `MatType`, `MATMPISBAIJ`
1925 M*/
1926 PETSC_EXTERN PetscErrorCode MatCreate_SeqSBAIJ(Mat B)
1927 {
1928   Mat_SeqSBAIJ   *b;
1929   PetscMPIInt    size;
1930   PetscBool      no_unroll = PETSC_FALSE,no_inode = PETSC_FALSE;
1931 
1932   PetscFunctionBegin;
1933   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B),&size));
1934   PetscCheck(size <= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Comm must be of size 1");
1935 
1936   PetscCall(PetscNewLog(B,&b));
1937   B->data = (void*)b;
1938   PetscCall(PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps)));
1939 
1940   B->ops->destroy    = MatDestroy_SeqSBAIJ;
1941   B->ops->view       = MatView_SeqSBAIJ;
1942   b->row             = NULL;
1943   b->icol            = NULL;
1944   b->reallocs        = 0;
1945   b->saved_values    = NULL;
1946   b->inode.limit     = 5;
1947   b->inode.max_limit = 5;
1948 
1949   b->roworiented        = PETSC_TRUE;
1950   b->nonew              = 0;
1951   b->diag               = NULL;
1952   b->solve_work         = NULL;
1953   b->mult_work          = NULL;
1954   B->spptr              = NULL;
1955   B->info.nz_unneeded   = (PetscReal)b->maxnz*b->bs2;
1956   b->keepnonzeropattern = PETSC_FALSE;
1957 
1958   b->inew    = NULL;
1959   b->jnew    = NULL;
1960   b->anew    = NULL;
1961   b->a2anew  = NULL;
1962   b->permute = PETSC_FALSE;
1963 
1964   b->ignore_ltriangular = PETSC_TRUE;
1965 
1966   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options,((PetscObject)B)->prefix,"-mat_ignore_lower_triangular",&b->ignore_ltriangular,NULL));
1967 
1968   b->getrow_utriangular = PETSC_FALSE;
1969 
1970   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options,((PetscObject)B)->prefix,"-mat_getrow_uppertriangular",&b->getrow_utriangular,NULL));
1971 
1972   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatSeqSBAIJGetArray_C",MatSeqSBAIJGetArray_SeqSBAIJ));
1973   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatSeqSBAIJRestoreArray_C",MatSeqSBAIJRestoreArray_SeqSBAIJ));
1974   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatStoreValues_C",MatStoreValues_SeqSBAIJ));
1975   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatRetrieveValues_C",MatRetrieveValues_SeqSBAIJ));
1976   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatSeqSBAIJSetColumnIndices_C",MatSeqSBAIJSetColumnIndices_SeqSBAIJ));
1977   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqsbaij_seqaij_C",MatConvert_SeqSBAIJ_SeqAIJ));
1978   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqsbaij_seqbaij_C",MatConvert_SeqSBAIJ_SeqBAIJ));
1979   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatSeqSBAIJSetPreallocation_C",MatSeqSBAIJSetPreallocation_SeqSBAIJ));
1980   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatSeqSBAIJSetPreallocationCSR_C",MatSeqSBAIJSetPreallocationCSR_SeqSBAIJ));
1981 #if defined(PETSC_HAVE_ELEMENTAL)
1982   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqsbaij_elemental_C",MatConvert_SeqSBAIJ_Elemental));
1983 #endif
1984 #if defined(PETSC_HAVE_SCALAPACK)
1985   PetscCall(PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqsbaij_scalapack_C",MatConvert_SBAIJ_ScaLAPACK));
1986 #endif
1987 
1988   B->symmetric                  = PETSC_TRUE;
1989   B->structurally_symmetric     = PETSC_TRUE;
1990   B->symmetric_set              = PETSC_TRUE;
1991   B->structurally_symmetric_set = PETSC_TRUE;
1992   B->symmetric_eternal          = PETSC_TRUE;
1993 #if defined(PETSC_USE_COMPLEX)
1994   B->hermitian                  = PETSC_FALSE;
1995   B->hermitian_set              = PETSC_FALSE;
1996 #else
1997   B->hermitian                  = PETSC_TRUE;
1998   B->hermitian_set              = PETSC_TRUE;
1999 #endif
2000 
2001   PetscCall(PetscObjectChangeTypeName((PetscObject)B,MATSEQSBAIJ));
2002 
2003   PetscOptionsBegin(PetscObjectComm((PetscObject)B),((PetscObject)B)->prefix,"Options for SEQSBAIJ matrix","Mat");
2004   PetscCall(PetscOptionsBool("-mat_no_unroll","Do not optimize for inodes (slower)",NULL,no_unroll,&no_unroll,NULL));
2005   if (no_unroll) {
2006     PetscCall(PetscInfo(B,"Not using Inode routines due to -mat_no_unroll\n"));
2007   }
2008   PetscCall(PetscOptionsBool("-mat_no_inode","Do not optimize for inodes (slower)",NULL,no_inode,&no_inode,NULL));
2009   if (no_inode) PetscCall(PetscInfo(B,"Not using Inode routines due to -mat_no_inode\n"));
2010   PetscCall(PetscOptionsInt("-mat_inode_limit","Do not use inodes larger then this value",NULL,b->inode.limit,&b->inode.limit,NULL));
2011   PetscOptionsEnd();
2012   b->inode.use = (PetscBool)(!(no_unroll || no_inode));
2013   if (b->inode.limit > b->inode.max_limit) b->inode.limit = b->inode.max_limit;
2014   PetscFunctionReturn(0);
2015 }
2016 
2017 /*@C
2018    MatSeqSBAIJSetPreallocation - Creates a sparse symmetric matrix in block AIJ (block
2019    compressed row) format.  For good matrix assembly performance the
2020    user should preallocate the matrix storage by setting the parameter nz
2021    (or the array nnz).  By setting these parameters accurately, performance
2022    during matrix assembly can be increased by more than a factor of 50.
2023 
2024    Collective on Mat
2025 
2026    Input Parameters:
2027 +  B - the symmetric matrix
2028 .  bs - size of block, the blocks are ALWAYS square. One can use MatSetBlockSizes() to set a different row and column blocksize but the row
2029           blocksize always defines the size of the blocks. The column blocksize sets the blocksize of the vectors obtained with MatCreateVecs()
2030 .  nz - number of block nonzeros per block row (same for all rows)
2031 -  nnz - array containing the number of block nonzeros in the upper triangular plus
2032          diagonal portion of each block (possibly different for each block row) or NULL
2033 
2034    Options Database Keys:
2035 +   -mat_no_unroll - uses code that does not unroll the loops in the
2036                      block calculations (much slower)
2037 -   -mat_block_size - size of the blocks to use (only works if a negative bs is passed in
2038 
2039    Level: intermediate
2040 
2041    Notes:
2042    Specify the preallocated storage with either nz or nnz (not both).
2043    Set nz=PETSC_DEFAULT and nnz=NULL for PETSc to control dynamic memory
2044    allocation.  See Users-Manual: ch_mat for details.
2045 
2046    You can call MatGetInfo() to get information on how effective the preallocation was;
2047    for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
2048    You can also run with the option -info and look for messages with the string
2049    malloc in them to see if additional memory allocation was needed.
2050 
2051    If the nnz parameter is given then the nz parameter is ignored
2052 
2053 .seealso: `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatCreateSBAIJ()`
2054 @*/
2055 PetscErrorCode  MatSeqSBAIJSetPreallocation(Mat B,PetscInt bs,PetscInt nz,const PetscInt nnz[])
2056 {
2057   PetscFunctionBegin;
2058   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
2059   PetscValidType(B,1);
2060   PetscValidLogicalCollectiveInt(B,bs,2);
2061   PetscTryMethod(B,"MatSeqSBAIJSetPreallocation_C",(Mat,PetscInt,PetscInt,const PetscInt[]),(B,bs,nz,nnz));
2062   PetscFunctionReturn(0);
2063 }
2064 
2065 /*@C
2066    MatSeqSBAIJSetPreallocationCSR - Creates a sparse parallel matrix in SBAIJ format using the given nonzero structure and (optional) numerical values
2067 
2068    Input Parameters:
2069 +  B - the matrix
2070 .  bs - size of block, the blocks are ALWAYS square.
2071 .  i - the indices into j for the start of each local row (starts with zero)
2072 .  j - the column indices for each local row (starts with zero) these must be sorted for each row
2073 -  v - optional values in the matrix
2074 
2075    Level: advanced
2076 
2077    Notes:
2078    The order of the entries in values is specified by the MatOption MAT_ROW_ORIENTED.  For example, C programs
2079    may want to use the default MAT_ROW_ORIENTED=PETSC_TRUE and use an array v[nnz][bs][bs] where the second index is
2080    over rows within a block and the last index is over columns within a block row.  Fortran programs will likely set
2081    MAT_ROW_ORIENTED=PETSC_FALSE and use a Fortran array v(bs,bs,nnz) in which the first index is over rows within a
2082    block column and the second index is over columns within a block.
2083 
2084    Any entries below the diagonal are ignored
2085 
2086    Though this routine has Preallocation() in the name it also sets the exact nonzero locations of the matrix entries
2087    and usually the numerical values as well
2088 
2089 .seealso: `MatCreate()`, `MatCreateSeqSBAIJ()`, `MatSetValuesBlocked()`, `MatSeqSBAIJSetPreallocation()`, `MATSEQSBAIJ`
2090 @*/
2091 PetscErrorCode MatSeqSBAIJSetPreallocationCSR(Mat B,PetscInt bs,const PetscInt i[],const PetscInt j[], const PetscScalar v[])
2092 {
2093   PetscFunctionBegin;
2094   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
2095   PetscValidType(B,1);
2096   PetscValidLogicalCollectiveInt(B,bs,2);
2097   PetscTryMethod(B,"MatSeqSBAIJSetPreallocationCSR_C",(Mat,PetscInt,const PetscInt[],const PetscInt[],const PetscScalar[]),(B,bs,i,j,v));
2098   PetscFunctionReturn(0);
2099 }
2100 
2101 /*@C
2102    MatCreateSeqSBAIJ - Creates a sparse symmetric matrix in block AIJ (block
2103    compressed row) format.  For good matrix assembly performance the
2104    user should preallocate the matrix storage by setting the parameter nz
2105    (or the array nnz).  By setting these parameters accurately, performance
2106    during matrix assembly can be increased by more than a factor of 50.
2107 
2108    Collective
2109 
2110    Input Parameters:
2111 +  comm - MPI communicator, set to PETSC_COMM_SELF
2112 .  bs - size of block, the blocks are ALWAYS square. One can use MatSetBlockSizes() to set a different row and column blocksize but the row
2113           blocksize always defines the size of the blocks. The column blocksize sets the blocksize of the vectors obtained with MatCreateVecs()
2114 .  m - number of rows, or number of columns
2115 .  nz - number of block nonzeros per block row (same for all rows)
2116 -  nnz - array containing the number of block nonzeros in the upper triangular plus
2117          diagonal portion of each block (possibly different for each block row) or NULL
2118 
2119    Output Parameter:
2120 .  A - the symmetric matrix
2121 
2122    Options Database Keys:
2123 +   -mat_no_unroll - uses code that does not unroll the loops in the
2124                      block calculations (much slower)
2125 -   -mat_block_size - size of the blocks to use
2126 
2127    Level: intermediate
2128 
2129    It is recommended that one use the MatCreate(), MatSetType() and/or MatSetFromOptions(),
2130    MatXXXXSetPreallocation() paradigm instead of this routine directly.
2131    [MatXXXXSetPreallocation() is, for example, MatSeqAIJSetPreallocation]
2132 
2133    Notes:
2134    The number of rows and columns must be divisible by blocksize.
2135    This matrix type does not support complex Hermitian operation.
2136 
2137    Specify the preallocated storage with either nz or nnz (not both).
2138    Set nz=PETSC_DEFAULT and nnz=NULL for PETSc to control dynamic memory
2139    allocation.  See Users-Manual: ch_mat for details.
2140 
2141    If the nnz parameter is given then the nz parameter is ignored
2142 
2143 .seealso: `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatCreateSBAIJ()`
2144 @*/
2145 PetscErrorCode  MatCreateSeqSBAIJ(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt nz,const PetscInt nnz[],Mat *A)
2146 {
2147   PetscFunctionBegin;
2148   PetscCall(MatCreate(comm,A));
2149   PetscCall(MatSetSizes(*A,m,n,m,n));
2150   PetscCall(MatSetType(*A,MATSEQSBAIJ));
2151   PetscCall(MatSeqSBAIJSetPreallocation(*A,bs,nz,(PetscInt*)nnz));
2152   PetscFunctionReturn(0);
2153 }
2154 
2155 PetscErrorCode MatDuplicate_SeqSBAIJ(Mat A,MatDuplicateOption cpvalues,Mat *B)
2156 {
2157   Mat            C;
2158   Mat_SeqSBAIJ   *c,*a = (Mat_SeqSBAIJ*)A->data;
2159   PetscInt       i,mbs = a->mbs,nz = a->nz,bs2 =a->bs2;
2160 
2161   PetscFunctionBegin;
2162   PetscCheck(a->i[mbs] == nz,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Corrupt matrix");
2163 
2164   *B   = NULL;
2165   PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C));
2166   PetscCall(MatSetSizes(C,A->rmap->N,A->cmap->n,A->rmap->N,A->cmap->n));
2167   PetscCall(MatSetBlockSizesFromMats(C,A,A));
2168   PetscCall(MatSetType(C,MATSEQSBAIJ));
2169   c    = (Mat_SeqSBAIJ*)C->data;
2170 
2171   C->preallocated       = PETSC_TRUE;
2172   C->factortype         = A->factortype;
2173   c->row                = NULL;
2174   c->icol               = NULL;
2175   c->saved_values       = NULL;
2176   c->keepnonzeropattern = a->keepnonzeropattern;
2177   C->assembled          = PETSC_TRUE;
2178 
2179   PetscCall(PetscLayoutReference(A->rmap,&C->rmap));
2180   PetscCall(PetscLayoutReference(A->cmap,&C->cmap));
2181   c->bs2 = a->bs2;
2182   c->mbs = a->mbs;
2183   c->nbs = a->nbs;
2184 
2185   if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2186     c->imax           = a->imax;
2187     c->ilen           = a->ilen;
2188     c->free_imax_ilen = PETSC_FALSE;
2189   } else {
2190     PetscCall(PetscMalloc2((mbs+1),&c->imax,(mbs+1),&c->ilen));
2191     PetscCall(PetscLogObjectMemory((PetscObject)C,2*(mbs+1)*sizeof(PetscInt)));
2192     for (i=0; i<mbs; i++) {
2193       c->imax[i] = a->imax[i];
2194       c->ilen[i] = a->ilen[i];
2195     }
2196     c->free_imax_ilen = PETSC_TRUE;
2197   }
2198 
2199   /* allocate the matrix space */
2200   if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2201     PetscCall(PetscMalloc1(bs2*nz,&c->a));
2202     PetscCall(PetscLogObjectMemory((PetscObject)C,nz*bs2*sizeof(MatScalar)));
2203     c->i            = a->i;
2204     c->j            = a->j;
2205     c->singlemalloc = PETSC_FALSE;
2206     c->free_a       = PETSC_TRUE;
2207     c->free_ij      = PETSC_FALSE;
2208     c->parent       = A;
2209     PetscCall(PetscObjectReference((PetscObject)A));
2210     PetscCall(MatSetOption(A,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE));
2211     PetscCall(MatSetOption(C,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE));
2212   } else {
2213     PetscCall(PetscMalloc3(bs2*nz,&c->a,nz,&c->j,mbs+1,&c->i));
2214     PetscCall(PetscArraycpy(c->i,a->i,mbs+1));
2215     PetscCall(PetscLogObjectMemory((PetscObject)C,(mbs+1)*sizeof(PetscInt) + nz*(bs2*sizeof(MatScalar) + sizeof(PetscInt))));
2216     c->singlemalloc = PETSC_TRUE;
2217     c->free_a       = PETSC_TRUE;
2218     c->free_ij      = PETSC_TRUE;
2219   }
2220   if (mbs > 0) {
2221     if (cpvalues != MAT_SHARE_NONZERO_PATTERN) {
2222       PetscCall(PetscArraycpy(c->j,a->j,nz));
2223     }
2224     if (cpvalues == MAT_COPY_VALUES) {
2225       PetscCall(PetscArraycpy(c->a,a->a,bs2*nz));
2226     } else {
2227       PetscCall(PetscArrayzero(c->a,bs2*nz));
2228     }
2229     if (a->jshort) {
2230       /* cannot share jshort, it is reallocated in MatAssemblyEnd_SeqSBAIJ() */
2231       /* if the parent matrix is reassembled, this child matrix will never notice */
2232       PetscCall(PetscMalloc1(nz,&c->jshort));
2233       PetscCall(PetscLogObjectMemory((PetscObject)C,nz*sizeof(unsigned short)));
2234       PetscCall(PetscArraycpy(c->jshort,a->jshort,nz));
2235 
2236       c->free_jshort = PETSC_TRUE;
2237     }
2238   }
2239 
2240   c->roworiented = a->roworiented;
2241   c->nonew       = a->nonew;
2242 
2243   if (a->diag) {
2244     if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2245       c->diag      = a->diag;
2246       c->free_diag = PETSC_FALSE;
2247     } else {
2248       PetscCall(PetscMalloc1(mbs,&c->diag));
2249       PetscCall(PetscLogObjectMemory((PetscObject)C,mbs*sizeof(PetscInt)));
2250       for (i=0; i<mbs; i++) c->diag[i] = a->diag[i];
2251       c->free_diag = PETSC_TRUE;
2252     }
2253   }
2254   c->nz         = a->nz;
2255   c->maxnz      = a->nz; /* Since we allocate exactly the right amount */
2256   c->solve_work = NULL;
2257   c->mult_work  = NULL;
2258 
2259   *B   = C;
2260   PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist,&((PetscObject)C)->qlist));
2261   PetscFunctionReturn(0);
2262 }
2263 
2264 /* Used for both SeqBAIJ and SeqSBAIJ matrices */
2265 #define MatLoad_SeqSBAIJ_Binary MatLoad_SeqBAIJ_Binary
2266 
2267 PetscErrorCode MatLoad_SeqSBAIJ(Mat mat,PetscViewer viewer)
2268 {
2269   PetscBool      isbinary;
2270 
2271   PetscFunctionBegin;
2272   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary));
2273   PetscCheck(isbinary,PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Viewer type %s not yet supported for reading %s matrices",((PetscObject)viewer)->type_name,((PetscObject)mat)->type_name);
2274   PetscCall(MatLoad_SeqSBAIJ_Binary(mat,viewer));
2275   PetscFunctionReturn(0);
2276 }
2277 
2278 /*@
2279      MatCreateSeqSBAIJWithArrays - Creates an sequential SBAIJ matrix using matrix elements
2280               (upper triangular entries in CSR format) provided by the user.
2281 
2282      Collective
2283 
2284    Input Parameters:
2285 +  comm - must be an MPI communicator of size 1
2286 .  bs - size of block
2287 .  m - number of rows
2288 .  n - number of columns
2289 .  i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of block elements in that row block row of the matrix
2290 .  j - column indices
2291 -  a - matrix values
2292 
2293    Output Parameter:
2294 .  mat - the matrix
2295 
2296    Level: advanced
2297 
2298    Notes:
2299        The i, j, and a arrays are not copied by this routine, the user must free these arrays
2300     once the matrix is destroyed
2301 
2302        You cannot set new nonzero locations into this matrix, that will generate an error.
2303 
2304        The i and j indices are 0 based
2305 
2306        When block size is greater than 1 the matrix values must be stored using the SBAIJ storage format (see the SBAIJ code to determine this). For block size of 1
2307        it is the regular CSR format excluding the lower triangular elements.
2308 
2309 .seealso: `MatCreate()`, `MatCreateSBAIJ()`, `MatCreateSeqSBAIJ()`
2310 
2311 @*/
2312 PetscErrorCode  MatCreateSeqSBAIJWithArrays(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt i[],PetscInt j[],PetscScalar a[],Mat *mat)
2313 {
2314   PetscInt       ii;
2315   Mat_SeqSBAIJ   *sbaij;
2316 
2317   PetscFunctionBegin;
2318   PetscCheck(bs == 1,PETSC_COMM_SELF,PETSC_ERR_SUP,"block size %" PetscInt_FMT " > 1 is not supported yet",bs);
2319   PetscCheck(m == 0 || i[0] == 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"i (row indices) must start with 0");
2320 
2321   PetscCall(MatCreate(comm,mat));
2322   PetscCall(MatSetSizes(*mat,m,n,m,n));
2323   PetscCall(MatSetType(*mat,MATSEQSBAIJ));
2324   PetscCall(MatSeqSBAIJSetPreallocation(*mat,bs,MAT_SKIP_ALLOCATION,NULL));
2325   sbaij = (Mat_SeqSBAIJ*)(*mat)->data;
2326   PetscCall(PetscMalloc2(m,&sbaij->imax,m,&sbaij->ilen));
2327   PetscCall(PetscLogObjectMemory((PetscObject)*mat,2*m*sizeof(PetscInt)));
2328 
2329   sbaij->i = i;
2330   sbaij->j = j;
2331   sbaij->a = a;
2332 
2333   sbaij->singlemalloc   = PETSC_FALSE;
2334   sbaij->nonew          = -1;             /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/
2335   sbaij->free_a         = PETSC_FALSE;
2336   sbaij->free_ij        = PETSC_FALSE;
2337   sbaij->free_imax_ilen = PETSC_TRUE;
2338 
2339   for (ii=0; ii<m; ii++) {
2340     sbaij->ilen[ii] = sbaij->imax[ii] = i[ii+1] - i[ii];
2341     PetscCheck(i[ii+1] >= i[ii],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative row length in i (row indices) row = %" PetscInt_FMT " length = %" PetscInt_FMT,ii,i[ii+1] - i[ii]);
2342   }
2343   if (PetscDefined(USE_DEBUG)) {
2344     for (ii=0; ii<sbaij->i[m]; ii++) {
2345       PetscCheck(j[ii] >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT,ii,j[ii]);
2346       PetscCheck(j[ii] < n,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Column index too large at location = %" PetscInt_FMT " index = %" PetscInt_FMT,ii,j[ii]);
2347     }
2348   }
2349 
2350   PetscCall(MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY));
2351   PetscCall(MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY));
2352   PetscFunctionReturn(0);
2353 }
2354 
2355 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqSBAIJ(MPI_Comm comm,Mat inmat,PetscInt n,MatReuse scall,Mat *outmat)
2356 {
2357   PetscMPIInt    size;
2358 
2359   PetscFunctionBegin;
2360   PetscCallMPI(MPI_Comm_size(comm,&size));
2361   if (size == 1 && scall == MAT_REUSE_MATRIX) {
2362     PetscCall(MatCopy(inmat,*outmat,SAME_NONZERO_PATTERN));
2363   } else {
2364     PetscCall(MatCreateMPIMatConcatenateSeqMat_MPISBAIJ(comm,inmat,n,scall,outmat));
2365   }
2366   PetscFunctionReturn(0);
2367 }
2368