xref: /petsc/src/mat/impls/kaij/kaij.c (revision d21efd2e5d911db017a545648c4fa4838359bb2d)
1 
2 /*
3   Defines the basic matrix operations for the KAIJ  matrix storage format.
4   This format is used to evaluate matrices of the form:
5 
6     [I \otimes S + A \otimes T]
7 
8   where
9     S is a dense (p \times q) matrix
10     T is a dense (p \times q) matrix
11     A is an AIJ  (n \times n) matrix
12     I is the identity matrix
13 
14   The resulting matrix is (np \times nq)
15 
16   We provide:
17      MatMult()
18      MatMultAdd()
19      MatInvertBlockDiagonal()
20   and
21      MatCreateKAIJ(Mat,PetscInt,PetscInt,const PetscScalar[],const PetscScalar[],Mat*)
22 
23   This single directory handles both the sequential and parallel codes
24 */
25 
26 #include <../src/mat/impls/kaij/kaij.h> /*I "petscmat.h" I*/
27 #include <../src/mat/utils/freespace.h>
28 #include <petsc/private/vecimpl.h>
29 
30 /*@C
31    MatKAIJGetAIJ - Get the AIJ matrix describing the blockwise action of the KAIJ matrix
32 
33    Not Collective, but if the KAIJ matrix is parallel, the AIJ matrix is also parallel
34 
35    Input Parameter:
36 .  A - the KAIJ matrix
37 
38    Output Parameter:
39 .  B - the AIJ matrix
40 
41    Level: advanced
42 
43    Notes: The reference count on the AIJ matrix is not increased so you should not destroy it.
44 
45 .seealso: MatCreateKAIJ()
46 @*/
47 PetscErrorCode  MatKAIJGetAIJ(Mat A,Mat *B)
48 {
49   PetscErrorCode ierr;
50   PetscBool      ismpikaij,isseqkaij;
51 
52   PetscFunctionBegin;
53   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIKAIJ,&ismpikaij);CHKERRQ(ierr);
54   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQKAIJ,&isseqkaij);CHKERRQ(ierr);
55   if (ismpikaij) {
56     Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data;
57 
58     *B = b->A;
59   } else if (isseqkaij) {
60     Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data;
61 
62     *B = b->AIJ;
63   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix passed in is not of type KAIJ");
64   PetscFunctionReturn(0);
65 }
66 
67 /*@C
68    MatKAIJGetS - Get the S matrix describing the shift action of the KAIJ matrix
69 
70    Not Collective; the entire S is stored and returned independently on all processes.
71 
72    Input Parameter:
73 .  A - the KAIJ matrix
74 
75    Output Parameters:
76 +  m - the number of rows in S
77 .  n - the number of columns in S
78 -  S - the S matrix, in form of a scalar array in column-major format
79 
80    Note: All output parameters are optional (pass NULL or PETSC_IGNORE if not desired)
81 
82    Level: advanced
83 
84 .seealso: MatCreateKAIJ(), MatGetBlockSizes()
85 @*/
86 PetscErrorCode MatKAIJGetS(Mat A,PetscInt *m,PetscInt *n,PetscScalar **S)
87 {
88   Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data;
89   PetscFunctionBegin;
90   if (m) *m = b->p;
91   if (n) *n = b->q;
92   if (S) *S = b->S;
93   PetscFunctionReturn(0);
94 }
95 
96 /*@C
97    MatKAIJGetSRead - Get a read-only pointer to the S matrix describing the shift action of the KAIJ matrix
98 
99    Not Collective; the entire S is stored and returned independently on all processes.
100 
101    Input Parameter:
102 .  A - the KAIJ matrix
103 
104    Output Parameters:
105 +  m - the number of rows in S
106 .  n - the number of columns in S
107 -  S - the S matrix, in form of a scalar array in column-major format
108 
109    Note: All output parameters are optional (pass NULL or PETSC_IGNORE if not desired)
110 
111    Level: advanced
112 
113 .seealso: MatCreateKAIJ(), MatGetBlockSizes()
114 @*/
115 PetscErrorCode MatKAIJGetSRead(Mat A,PetscInt *m,PetscInt *n,const PetscScalar **S)
116 {
117   Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data;
118   PetscFunctionBegin;
119   if (m) *m = b->p;
120   if (n) *n = b->q;
121   if (S) *S = b->S;
122   PetscFunctionReturn(0);
123 }
124 
125 /*@C
126   MatKAIJRestoreS - Restore array obtained with MatKAIJGetS()
127 
128   Not collective
129 
130   Input Parameter:
131 . A - the KAIJ matrix
132 
133   Output Parameter:
134 . S - location of pointer to array obtained with MatKAIJGetS()
135 
136   Note: This routine zeros the array pointer to prevent accidental reuse after it has been restored.
137   If NULL is passed, it will not attempt to zero the array pointer.
138 
139   Level: advanced
140 .seealso: MatKAIJGetS(), MatKAIJGetSRead(), MatKAIJRestoreSRead()
141 @*/
142 PetscErrorCode MatKAIJRestoreS(Mat A,PetscScalar **S)
143 {
144   PetscErrorCode ierr;
145 
146   PetscFunctionBegin;
147   if (S) *S = NULL;
148   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 /*@C
153   MatKAIJRestoreSRead - Restore array obtained with MatKAIJGetSRead()
154 
155   Not collective
156 
157   Input Parameter:
158 . A - the KAIJ matrix
159 
160   Output Parameter:
161 . S - location of pointer to array obtained with MatKAIJGetS()
162 
163   Note: This routine zeros the array pointer to prevent accidental reuse after it has been restored.
164   If NULL is passed, it will not attempt to zero the array pointer.
165 
166   Level: advanced
167 .seealso: MatKAIJGetS(), MatKAIJGetSRead(), MatKAIJRestoreSRead()
168 @*/
169 PetscErrorCode MatKAIJRestoreSRead(Mat A,const PetscScalar **S)
170 {
171   PetscFunctionBegin;
172   if (S) *S = NULL;
173   PetscFunctionReturn(0);
174 }
175 
176 /*@C
177    MatKAIJGetT - Get the transformation matrix T associated with the KAIJ matrix
178 
179    Not Collective; the entire T is stored and returned independently on all processes
180 
181    Input Parameter:
182 .  A - the KAIJ matrix
183 
184    Output Parameters:
185 +  m - the number of rows in T
186 .  n - the number of columns in T
187 -  T - the T matrix, in form of a scalar array in column-major format
188 
189    Note: All output parameters are optional (pass NULL or PETSC_IGNORE if not desired)
190 
191    Level: advanced
192 
193 .seealso: MatCreateKAIJ(), MatGetBlockSizes()
194 @*/
195 PetscErrorCode MatKAIJGetT(Mat A,PetscInt *m,PetscInt *n,PetscScalar **T)
196 {
197   Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data;
198   PetscFunctionBegin;
199   if (m) *m = b->p;
200   if (n) *n = b->q;
201   if (T) *T = b->T;
202   PetscFunctionReturn(0);
203 }
204 
205 /*@C
206    MatKAIJGetTRead - Get a read-only pointer to the transformation matrix T associated with the KAIJ matrix
207 
208    Not Collective; the entire T is stored and returned independently on all processes
209 
210    Input Parameter:
211 .  A - the KAIJ matrix
212 
213    Output Parameters:
214 +  m - the number of rows in T
215 .  n - the number of columns in T
216 -  T - the T matrix, in form of a scalar array in column-major format
217 
218    Note: All output parameters are optional (pass NULL or PETSC_IGNORE if not desired)
219 
220    Level: advanced
221 
222 .seealso: MatCreateKAIJ(), MatGetBlockSizes()
223 @*/
224 PetscErrorCode MatKAIJGetTRead(Mat A,PetscInt *m,PetscInt *n,const PetscScalar **T)
225 {
226   Mat_SeqKAIJ *b = (Mat_SeqKAIJ*)A->data;
227   PetscFunctionBegin;
228   if (m) *m = b->p;
229   if (n) *n = b->q;
230   if (T) *T = b->T;
231   PetscFunctionReturn(0);
232 }
233 
234 /*@C
235   MatKAIJRestoreT - Restore array obtained with MatKAIJGetT()
236 
237   Not collective
238 
239   Input Parameter:
240 . A - the KAIJ matrix
241 
242   Output Parameter:
243 . T - location of pointer to array obtained with MatKAIJGetS()
244 
245   Note: This routine zeros the array pointer to prevent accidental reuse after it has been restored.
246   If NULL is passed, it will not attempt to zero the array pointer.
247 
248   Level: advanced
249 .seealso: MatKAIJGetT(), MatKAIJGetTRead(), MatKAIJRestoreTRead()
250 @*/
251 PetscErrorCode MatKAIJRestoreT(Mat A,PetscScalar **T)
252 {
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   if (T) *T = NULL;
257   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
258   PetscFunctionReturn(0);
259 }
260 
261 /*@C
262   MatKAIJRestoreTRead - Restore array obtained with MatKAIJGetTRead()
263 
264   Not collective
265 
266   Input Parameter:
267 . A - the KAIJ matrix
268 
269   Output Parameter:
270 . T - location of pointer to array obtained with MatKAIJGetS()
271 
272   Note: This routine zeros the array pointer to prevent accidental reuse after it has been restored.
273   If NULL is passed, it will not attempt to zero the array pointer.
274 
275   Level: advanced
276 .seealso: MatKAIJGetT(), MatKAIJGetTRead(), MatKAIJRestoreTRead()
277 @*/
278 PetscErrorCode MatKAIJRestoreTRead(Mat A,const PetscScalar **T)
279 {
280   PetscFunctionBegin;
281   if (T) *T = NULL;
282   PetscFunctionReturn(0);
283 }
284 
285 /*@
286    MatKAIJSetAIJ - Set the AIJ matrix describing the blockwise action of the KAIJ matrix
287 
288    Logically Collective; if the AIJ matrix is parallel, the KAIJ matrix is also parallel
289 
290    Input Parameters:
291 +  A - the KAIJ matrix
292 -  B - the AIJ matrix
293 
294    Notes:
295    This function increases the reference count on the AIJ matrix, so the user is free to destroy the matrix if it is not needed.
296    Changes to the entries of the AIJ matrix will immediately affect the KAIJ matrix.
297 
298    Level: advanced
299 
300 .seealso: MatKAIJGetAIJ(), MatKAIJSetS(), MatKAIJSetT()
301 @*/
302 PetscErrorCode MatKAIJSetAIJ(Mat A,Mat B)
303 {
304   PetscErrorCode ierr;
305   PetscMPIInt    size;
306   PetscBool      flg;
307 
308   PetscFunctionBegin;
309   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRMPI(ierr);
310   if (size == 1) {
311     ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&flg);CHKERRQ(ierr);
312     PetscCheckFalse(!flg,PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"MatKAIJSetAIJ() with MATSEQKAIJ does not support %s as the AIJ mat",((PetscObject)B)->type_name);
313     Mat_SeqKAIJ *a = (Mat_SeqKAIJ*)A->data;
314     a->AIJ = B;
315   } else {
316     Mat_MPIKAIJ *a = (Mat_MPIKAIJ*)A->data;
317     a->A = B;
318   }
319   ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
320   PetscFunctionReturn(0);
321 }
322 
323 /*@C
324    MatKAIJSetS - Set the S matrix describing the shift action of the KAIJ matrix
325 
326    Logically Collective; the entire S is stored independently on all processes.
327 
328    Input Parameters:
329 +  A - the KAIJ matrix
330 .  p - the number of rows in S
331 .  q - the number of columns in S
332 -  S - the S matrix, in form of a scalar array in column-major format
333 
334    Notes: The dimensions p and q must match those of the transformation matrix T associated with the KAIJ matrix.
335    The S matrix is copied, so the user can destroy this array.
336 
337    Level: Advanced
338 
339 .seealso: MatKAIJGetS(), MatKAIJSetT(), MatKAIJSetAIJ()
340 @*/
341 PetscErrorCode MatKAIJSetS(Mat A,PetscInt p,PetscInt q,const PetscScalar S[])
342 {
343   PetscErrorCode ierr;
344   Mat_SeqKAIJ    *a = (Mat_SeqKAIJ*)A->data;
345 
346   PetscFunctionBegin;
347   ierr = PetscFree(a->S);CHKERRQ(ierr);
348   if (S) {
349     ierr = PetscMalloc1(p*q,&a->S);CHKERRQ(ierr);
350     ierr = PetscMemcpy(a->S,S,p*q*sizeof(PetscScalar));CHKERRQ(ierr);
351   } else  a->S = NULL;
352 
353   a->p = p;
354   a->q = q;
355   PetscFunctionReturn(0);
356 }
357 
358 /*@C
359    MatKAIJGetScaledIdentity - Check if both S and T are scaled identities.
360 
361    Logically Collective.
362 
363    Input Parameter:
364 .  A - the KAIJ matrix
365 
366   Output Parameter:
367 .  identity - the Boolean value
368 
369    Level: Advanced
370 
371 .seealso: MatKAIJGetS(), MatKAIJGetT()
372 @*/
373 PetscErrorCode MatKAIJGetScaledIdentity(Mat A,PetscBool* identity)
374 {
375   Mat_SeqKAIJ *a = (Mat_SeqKAIJ*)A->data;
376   PetscInt    i,j;
377 
378   PetscFunctionBegin;
379   if (a->p != a->q) {
380     *identity = PETSC_FALSE;
381     PetscFunctionReturn(0);
382   } else *identity = PETSC_TRUE;
383   if (!a->isTI || a->S) {
384     for (i=0; i<a->p && *identity; i++) {
385       for (j=0; j<a->p && *identity; j++) {
386         if (i != j) {
387           if (a->S && PetscAbsScalar(a->S[i+j*a->p]) > PETSC_SMALL) *identity = PETSC_FALSE;
388           if (a->T && PetscAbsScalar(a->T[i+j*a->p]) > PETSC_SMALL) *identity = PETSC_FALSE;
389         } else {
390           if (a->S && PetscAbsScalar(a->S[i*(a->p+1)]-a->S[0]) > PETSC_SMALL) *identity = PETSC_FALSE;
391           if (a->T && PetscAbsScalar(a->T[i*(a->p+1)]-a->T[0]) > PETSC_SMALL) *identity = PETSC_FALSE;
392         }
393       }
394     }
395   }
396   PetscFunctionReturn(0);
397 }
398 
399 /*@C
400    MatKAIJSetT - Set the transformation matrix T associated with the KAIJ matrix
401 
402    Logically Collective; the entire T is stored independently on all processes.
403 
404    Input Parameters:
405 +  A - the KAIJ matrix
406 .  p - the number of rows in S
407 .  q - the number of columns in S
408 -  T - the T matrix, in form of a scalar array in column-major format
409 
410    Notes: The dimensions p and q must match those of the shift matrix S associated with the KAIJ matrix.
411    The T matrix is copied, so the user can destroy this array.
412 
413    Level: Advanced
414 
415 .seealso: MatKAIJGetT(), MatKAIJSetS(), MatKAIJSetAIJ()
416 @*/
417 PetscErrorCode MatKAIJSetT(Mat A,PetscInt p,PetscInt q,const PetscScalar T[])
418 {
419   PetscErrorCode ierr;
420   PetscInt       i,j;
421   Mat_SeqKAIJ    *a = (Mat_SeqKAIJ*)A->data;
422   PetscBool      isTI = PETSC_FALSE;
423 
424   PetscFunctionBegin;
425   /* check if T is an identity matrix */
426   if (T && (p == q)) {
427     isTI = PETSC_TRUE;
428     for (i=0; i<p; i++) {
429       for (j=0; j<q; j++) {
430         if (i == j) {
431           /* diagonal term must be 1 */
432           if (T[i+j*p] != 1.0) isTI = PETSC_FALSE;
433         } else {
434           /* off-diagonal term must be 0 */
435           if (T[i+j*p] != 0.0) isTI = PETSC_FALSE;
436         }
437       }
438     }
439   }
440   a->isTI = isTI;
441 
442   ierr = PetscFree(a->T);CHKERRQ(ierr);
443   if (T && (!isTI)) {
444     ierr = PetscMalloc1(p*q,&a->T);CHKERRQ(ierr);
445     ierr = PetscMemcpy(a->T,T,p*q*sizeof(PetscScalar));CHKERRQ(ierr);
446   } else a->T = NULL;
447 
448   a->p = p;
449   a->q = q;
450   PetscFunctionReturn(0);
451 }
452 
453 PetscErrorCode MatDestroy_SeqKAIJ(Mat A)
454 {
455   PetscErrorCode ierr;
456   Mat_SeqKAIJ    *b = (Mat_SeqKAIJ*)A->data;
457 
458   PetscFunctionBegin;
459   ierr = MatDestroy(&b->AIJ);CHKERRQ(ierr);
460   ierr = PetscFree(b->S);CHKERRQ(ierr);
461   ierr = PetscFree(b->T);CHKERRQ(ierr);
462   ierr = PetscFree(b->ibdiag);CHKERRQ(ierr);
463   ierr = PetscFree5(b->sor.w,b->sor.y,b->sor.work,b->sor.t,b->sor.arr);CHKERRQ(ierr);
464   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqkaij_seqaij_C",NULL);CHKERRQ(ierr);
465   ierr = PetscFree(A->data);CHKERRQ(ierr);
466   PetscFunctionReturn(0);
467 }
468 
469 PETSC_INTERN PetscErrorCode MatKAIJ_build_AIJ_OAIJ(Mat A)
470 {
471   PetscErrorCode   ierr;
472   Mat_MPIKAIJ      *a;
473   Mat_MPIAIJ       *mpiaij;
474   PetscScalar      *T;
475   PetscInt         i,j;
476   PetscObjectState state;
477 
478   PetscFunctionBegin;
479   a = (Mat_MPIKAIJ*)A->data;
480   mpiaij = (Mat_MPIAIJ*)a->A->data;
481 
482   ierr = PetscObjectStateGet((PetscObject)a->A,&state);CHKERRQ(ierr);
483   if (state == a->state) {
484     /* The existing AIJ and KAIJ members are up-to-date, so simply exit. */
485     PetscFunctionReturn(0);
486   } else {
487     ierr = MatDestroy(&a->AIJ);CHKERRQ(ierr);
488     ierr = MatDestroy(&a->OAIJ);CHKERRQ(ierr);
489     if (a->isTI) {
490       /* If the transformation matrix associated with the parallel matrix A is the identity matrix, then a->T will be NULL.
491        * In this case, if we pass a->T directly to the MatCreateKAIJ() calls to create the sequential submatrices, the routine will
492        * not be able to tell that transformation matrix should be set to the identity; thus we create a temporary identity matrix
493        * to pass in. */
494       ierr = PetscMalloc1(a->p*a->q,&T);CHKERRQ(ierr);
495       for (i=0; i<a->p; i++) {
496         for (j=0; j<a->q; j++) {
497           if (i==j) T[i+j*a->p] = 1.0;
498           else      T[i+j*a->p] = 0.0;
499         }
500       }
501     } else T = a->T;
502     ierr = MatCreateKAIJ(mpiaij->A,a->p,a->q,a->S,T,&a->AIJ);CHKERRQ(ierr);
503     ierr = MatCreateKAIJ(mpiaij->B,a->p,a->q,NULL,T,&a->OAIJ);CHKERRQ(ierr);
504     if (a->isTI) {
505       ierr = PetscFree(T);CHKERRQ(ierr);
506     }
507     a->state = state;
508   }
509 
510   PetscFunctionReturn(0);
511 }
512 
513 PetscErrorCode MatSetUp_KAIJ(Mat A)
514 {
515   PetscErrorCode ierr;
516   PetscInt       n;
517   PetscMPIInt    size;
518   Mat_SeqKAIJ    *seqkaij = (Mat_SeqKAIJ*)A->data;
519 
520   PetscFunctionBegin;
521   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRMPI(ierr);
522   if (size == 1) {
523     ierr = MatSetSizes(A,seqkaij->p*seqkaij->AIJ->rmap->n,seqkaij->q*seqkaij->AIJ->cmap->n,seqkaij->p*seqkaij->AIJ->rmap->N,seqkaij->q*seqkaij->AIJ->cmap->N);CHKERRQ(ierr);
524     ierr = PetscLayoutSetBlockSize(A->rmap,seqkaij->p);CHKERRQ(ierr);
525     ierr = PetscLayoutSetBlockSize(A->cmap,seqkaij->q);CHKERRQ(ierr);
526     ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
527     ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
528   } else {
529     Mat_MPIKAIJ *a;
530     Mat_MPIAIJ  *mpiaij;
531     IS          from,to;
532     Vec         gvec;
533 
534     a = (Mat_MPIKAIJ*)A->data;
535     mpiaij = (Mat_MPIAIJ*)a->A->data;
536     ierr = MatSetSizes(A,a->p*a->A->rmap->n,a->q*a->A->cmap->n,a->p*a->A->rmap->N,a->q*a->A->cmap->N);CHKERRQ(ierr);
537     ierr = PetscLayoutSetBlockSize(A->rmap,seqkaij->p);CHKERRQ(ierr);
538     ierr = PetscLayoutSetBlockSize(A->cmap,seqkaij->q);CHKERRQ(ierr);
539     ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
540     ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
541 
542     ierr = MatKAIJ_build_AIJ_OAIJ(A);CHKERRQ(ierr);
543 
544     ierr = VecGetSize(mpiaij->lvec,&n);CHKERRQ(ierr);
545     ierr = VecCreate(PETSC_COMM_SELF,&a->w);CHKERRQ(ierr);
546     ierr = VecSetSizes(a->w,n*a->q,n*a->q);CHKERRQ(ierr);
547     ierr = VecSetBlockSize(a->w,a->q);CHKERRQ(ierr);
548     ierr = VecSetType(a->w,VECSEQ);CHKERRQ(ierr);
549 
550     /* create two temporary Index sets for build scatter gather */
551     ierr = ISCreateBlock(PetscObjectComm((PetscObject)a->A),a->q,n,mpiaij->garray,PETSC_COPY_VALUES,&from);CHKERRQ(ierr);
552     ierr = ISCreateStride(PETSC_COMM_SELF,n*a->q,0,1,&to);CHKERRQ(ierr);
553 
554     /* create temporary global vector to generate scatter context */
555     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)a->A),a->q,a->q*a->A->cmap->n,a->q*a->A->cmap->N,NULL,&gvec);CHKERRQ(ierr);
556 
557     /* generate the scatter context */
558     ierr = VecScatterCreate(gvec,from,a->w,to,&a->ctx);CHKERRQ(ierr);
559 
560     ierr = ISDestroy(&from);CHKERRQ(ierr);
561     ierr = ISDestroy(&to);CHKERRQ(ierr);
562     ierr = VecDestroy(&gvec);CHKERRQ(ierr);
563   }
564 
565   A->assembled = PETSC_TRUE;
566   PetscFunctionReturn(0);
567 }
568 
569 PetscErrorCode MatView_KAIJ(Mat A,PetscViewer viewer)
570 {
571   PetscViewerFormat format;
572   Mat_SeqKAIJ       *a = (Mat_SeqKAIJ*)A->data;
573   Mat               B;
574   PetscInt          i;
575   PetscErrorCode    ierr;
576   PetscBool         ismpikaij;
577 
578   PetscFunctionBegin;
579   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIKAIJ,&ismpikaij);CHKERRQ(ierr);
580   ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
581   if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_IMPL) {
582     ierr = PetscViewerASCIIPrintf(viewer,"S and T have %" PetscInt_FMT " rows and %" PetscInt_FMT " columns\n",a->p,a->q);CHKERRQ(ierr);
583 
584     /* Print appropriate details for S. */
585     if (!a->S) {
586       ierr = PetscViewerASCIIPrintf(viewer,"S is NULL\n");CHKERRQ(ierr);
587     } else if (format == PETSC_VIEWER_ASCII_IMPL) {
588       ierr = PetscViewerASCIIPrintf(viewer,"Entries of S are ");CHKERRQ(ierr);
589       for (i=0; i<(a->p * a->q); i++) {
590 #if defined(PETSC_USE_COMPLEX)
591         ierr = PetscViewerASCIIPrintf(viewer,"%18.16e %18.16e ",(double)PetscRealPart(a->S[i]),(double)PetscImaginaryPart(a->S[i]));CHKERRQ(ierr);
592 #else
593         ierr = PetscViewerASCIIPrintf(viewer,"%18.16e ",(double)PetscRealPart(a->S[i]));CHKERRQ(ierr);
594 #endif
595       }
596       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
597     }
598 
599     /* Print appropriate details for T. */
600     if (a->isTI) {
601       ierr = PetscViewerASCIIPrintf(viewer,"T is the identity matrix\n");CHKERRQ(ierr);
602     } else if (!a->T) {
603       ierr = PetscViewerASCIIPrintf(viewer,"T is NULL\n");CHKERRQ(ierr);
604     } else if (format == PETSC_VIEWER_ASCII_IMPL) {
605       ierr = PetscViewerASCIIPrintf(viewer,"Entries of T are ");CHKERRQ(ierr);
606       for (i=0; i<(a->p * a->q); i++) {
607 #if defined(PETSC_USE_COMPLEX)
608         ierr = PetscViewerASCIIPrintf(viewer,"%18.16e %18.16e ",(double)PetscRealPart(a->T[i]),(double)PetscImaginaryPart(a->T[i]));CHKERRQ(ierr);
609 #else
610         ierr = PetscViewerASCIIPrintf(viewer,"%18.16e ",(double)PetscRealPart(a->T[i]));CHKERRQ(ierr);
611 #endif
612       }
613       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
614     }
615 
616     /* Now print details for the AIJ matrix, using the AIJ viewer. */
617     ierr = PetscViewerASCIIPrintf(viewer,"Now viewing the associated AIJ matrix:\n");CHKERRQ(ierr);
618     if (ismpikaij) {
619       Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data;
620       ierr = MatView(b->A,viewer);CHKERRQ(ierr);
621     } else {
622       ierr = MatView(a->AIJ,viewer);CHKERRQ(ierr);
623     }
624 
625   } else {
626     /* For all other matrix viewer output formats, simply convert to an AIJ matrix and call MatView() on that. */
627     ierr = MatConvert(A,MATAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
628     ierr = MatView(B,viewer);CHKERRQ(ierr);
629     ierr = MatDestroy(&B);CHKERRQ(ierr);
630   }
631   PetscFunctionReturn(0);
632 }
633 
634 PetscErrorCode MatDestroy_MPIKAIJ(Mat A)
635 {
636   PetscErrorCode ierr;
637   Mat_MPIKAIJ    *b = (Mat_MPIKAIJ*)A->data;
638 
639   PetscFunctionBegin;
640   ierr = MatDestroy(&b->AIJ);CHKERRQ(ierr);
641   ierr = MatDestroy(&b->OAIJ);CHKERRQ(ierr);
642   ierr = MatDestroy(&b->A);CHKERRQ(ierr);
643   ierr = VecScatterDestroy(&b->ctx);CHKERRQ(ierr);
644   ierr = VecDestroy(&b->w);CHKERRQ(ierr);
645   ierr = PetscFree(b->S);CHKERRQ(ierr);
646   ierr = PetscFree(b->T);CHKERRQ(ierr);
647   ierr = PetscFree(b->ibdiag);CHKERRQ(ierr);
648   ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetDiagonalBlock_C",NULL);CHKERRQ(ierr);
649   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_mpikaij_mpiaij_C",NULL);CHKERRQ(ierr);
650   ierr = PetscFree(A->data);CHKERRQ(ierr);
651   PetscFunctionReturn(0);
652 }
653 
654 /* --------------------------------------------------------------------------------------*/
655 
656 /* zz = yy + Axx */
657 PetscErrorCode MatMultAdd_SeqKAIJ(Mat A,Vec xx,Vec yy,Vec zz)
658 {
659   Mat_SeqKAIJ       *b = (Mat_SeqKAIJ*)A->data;
660   Mat_SeqAIJ        *a = (Mat_SeqAIJ*)b->AIJ->data;
661   const PetscScalar *s = b->S, *t = b->T;
662   const PetscScalar *x,*v,*bx;
663   PetscScalar       *y,*sums;
664   PetscErrorCode    ierr;
665   const PetscInt    m = b->AIJ->rmap->n,*idx,*ii;
666   PetscInt          n,i,jrow,j,l,p=b->p,q=b->q,k;
667 
668   PetscFunctionBegin;
669   if (!yy) {
670     ierr = VecSet(zz,0.0);CHKERRQ(ierr);
671   } else {
672     ierr = VecCopy(yy,zz);CHKERRQ(ierr);
673   }
674   if ((!s) && (!t) && (!b->isTI)) PetscFunctionReturn(0);
675 
676   ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr);
677   ierr = VecGetArray(zz,&y);CHKERRQ(ierr);
678   idx  = a->j;
679   v    = a->a;
680   ii   = a->i;
681 
682   if (b->isTI) {
683     for (i=0; i<m; i++) {
684       jrow = ii[i];
685       n    = ii[i+1] - jrow;
686       sums = y + p*i;
687       for (j=0; j<n; j++) {
688         for (k=0; k<p; k++) {
689           sums[k] += v[jrow+j]*x[q*idx[jrow+j]+k];
690         }
691       }
692     }
693     ierr = PetscLogFlops(3.0*(a->nz)*p);CHKERRQ(ierr);
694   } else if (t) {
695     for (i=0; i<m; i++) {
696       jrow = ii[i];
697       n    = ii[i+1] - jrow;
698       sums = y + p*i;
699       for (j=0; j<n; j++) {
700         for (k=0; k<p; k++) {
701           for (l=0; l<q; l++) {
702             sums[k] += v[jrow+j]*t[k+l*p]*x[q*idx[jrow+j]+l];
703           }
704         }
705       }
706     }
707     /* The flop count below assumes that v[jrow+j] is hoisted out (which an optimizing compiler is likely to do),
708      * and also that T part is hoisted outside this loop (in exchange for temporary storage) as (A \otimes I) (I \otimes T),
709      * so that this multiply doesn't have to be redone for each matrix entry, but just once per column. The latter
710      * transformation is much less likely to be applied, but we nonetheless count the minimum flops required. */
711     ierr = PetscLogFlops((2.0*p*q-p)*m+2.0*p*a->nz);CHKERRQ(ierr);
712   }
713   if (s) {
714     for (i=0; i<m; i++) {
715       sums = y + p*i;
716       bx   = x + q*i;
717       if (i < b->AIJ->cmap->n) {
718         for (j=0; j<q; j++) {
719           for (k=0; k<p; k++) {
720             sums[k] += s[k+j*p]*bx[j];
721           }
722         }
723       }
724     }
725     ierr = PetscLogFlops(2.0*m*p*q);CHKERRQ(ierr);
726   }
727 
728   ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr);
729   ierr = VecRestoreArray(zz,&y);CHKERRQ(ierr);
730   PetscFunctionReturn(0);
731 }
732 
733 PetscErrorCode MatMult_SeqKAIJ(Mat A,Vec xx,Vec yy)
734 {
735   PetscErrorCode ierr;
736   PetscFunctionBegin;
737   ierr = MatMultAdd_SeqKAIJ(A,xx,PETSC_NULL,yy);CHKERRQ(ierr);
738   PetscFunctionReturn(0);
739 }
740 
741 #include <petsc/private/kernels/blockinvert.h>
742 
743 PetscErrorCode MatInvertBlockDiagonal_SeqKAIJ(Mat A,const PetscScalar **values)
744 {
745   Mat_SeqKAIJ       *b  = (Mat_SeqKAIJ*)A->data;
746   Mat_SeqAIJ        *a  = (Mat_SeqAIJ*)b->AIJ->data;
747   const PetscScalar *S  = b->S;
748   const PetscScalar *T  = b->T;
749   const PetscScalar *v  = a->a;
750   const PetscInt     p  = b->p, q = b->q, m = b->AIJ->rmap->n, *idx = a->j, *ii = a->i;
751   PetscErrorCode    ierr;
752   PetscInt          i,j,*v_pivots,dof,dof2;
753   PetscScalar       *diag,aval,*v_work;
754 
755   PetscFunctionBegin;
756   PetscCheckFalse(p != q,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MATKAIJ: Block size must be square to calculate inverse.");
757   PetscCheckFalse((!S) && (!T) && (!b->isTI),PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MATKAIJ: Cannot invert a zero matrix.");
758 
759   dof  = p;
760   dof2 = dof*dof;
761 
762   if (b->ibdiagvalid) {
763     if (values) *values = b->ibdiag;
764     PetscFunctionReturn(0);
765   }
766   if (!b->ibdiag) {
767     ierr = PetscMalloc1(dof2*m,&b->ibdiag);CHKERRQ(ierr);
768     ierr = PetscLogObjectMemory((PetscObject)A,dof2*m*sizeof(PetscScalar));CHKERRQ(ierr);
769   }
770   if (values) *values = b->ibdiag;
771   diag = b->ibdiag;
772 
773   ierr = PetscMalloc2(dof,&v_work,dof,&v_pivots);CHKERRQ(ierr);
774   for (i=0; i<m; i++) {
775     if (S) {
776       ierr = PetscMemcpy(diag,S,dof2*sizeof(PetscScalar));CHKERRQ(ierr);
777     } else {
778       ierr = PetscMemzero(diag,dof2*sizeof(PetscScalar));CHKERRQ(ierr);
779     }
780     if (b->isTI) {
781       aval = 0;
782       for (j=ii[i]; j<ii[i+1]; j++) if (idx[j] == i) aval = v[j];
783       for (j=0; j<dof; j++) diag[j+dof*j] += aval;
784     } else if (T) {
785       aval = 0;
786       for (j=ii[i]; j<ii[i+1]; j++) if (idx[j] == i) aval = v[j];
787       for (j=0; j<dof2; j++) diag[j] += aval*T[j];
788     }
789     ierr = PetscKernel_A_gets_inverse_A(dof,diag,v_pivots,v_work,PETSC_FALSE,NULL);CHKERRQ(ierr);
790     diag += dof2;
791   }
792   ierr = PetscFree2(v_work,v_pivots);CHKERRQ(ierr);
793 
794   b->ibdiagvalid = PETSC_TRUE;
795   PetscFunctionReturn(0);
796 }
797 
798 static PetscErrorCode MatGetDiagonalBlock_MPIKAIJ(Mat A,Mat *B)
799 {
800   Mat_MPIKAIJ *kaij = (Mat_MPIKAIJ*) A->data;
801 
802   PetscFunctionBegin;
803   *B = kaij->AIJ;
804   PetscFunctionReturn(0);
805 }
806 
807 static PetscErrorCode MatConvert_KAIJ_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
808 {
809   Mat_SeqKAIJ    *a = (Mat_SeqKAIJ*)A->data;
810   Mat            AIJ,OAIJ,B;
811   PetscInt       *d_nnz,*o_nnz = NULL,nz,i,j,m,d;
812   const PetscInt p = a->p,q = a->q;
813   PetscBool      ismpikaij,missing;
814   PetscErrorCode ierr;
815 
816   PetscFunctionBegin;
817   if (reuse != MAT_REUSE_MATRIX) {
818     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIKAIJ,&ismpikaij);CHKERRQ(ierr);
819     if (ismpikaij) {
820       Mat_MPIKAIJ *b = (Mat_MPIKAIJ*)A->data;
821       AIJ = ((Mat_SeqKAIJ*)b->AIJ->data)->AIJ;
822       OAIJ = ((Mat_SeqKAIJ*)b->OAIJ->data)->AIJ;
823     } else {
824       AIJ = a->AIJ;
825       OAIJ = NULL;
826     }
827     ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
828     ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
829     ierr = MatSetType(B,MATAIJ);CHKERRQ(ierr);
830     ierr = MatGetSize(AIJ,&m,NULL);CHKERRQ(ierr);
831     ierr = MatMissingDiagonal(AIJ,&missing,&d);CHKERRQ(ierr); /* assumption that all successive rows will have a missing diagonal */
832     if (!missing || !a->S) d = m;
833     ierr = PetscMalloc1(m*p,&d_nnz);CHKERRQ(ierr);
834     for (i = 0; i < m; ++i) {
835       ierr = MatGetRow_SeqAIJ(AIJ,i,&nz,NULL,NULL);CHKERRQ(ierr);
836       for (j = 0; j < p; ++j) d_nnz[i*p + j] = nz*q + (i >= d)*q;
837       ierr = MatRestoreRow_SeqAIJ(AIJ,i,&nz,NULL,NULL);CHKERRQ(ierr);
838     }
839     if (OAIJ) {
840       ierr = PetscMalloc1(m*p,&o_nnz);CHKERRQ(ierr);
841       for (i = 0; i < m; ++i) {
842         ierr = MatGetRow_SeqAIJ(OAIJ,i,&nz,NULL,NULL);CHKERRQ(ierr);
843         for (j = 0; j < p; ++j) o_nnz[i*p + j] = nz*q;
844         ierr = MatRestoreRow_SeqAIJ(OAIJ,i,&nz,NULL,NULL);CHKERRQ(ierr);
845       }
846       ierr = MatMPIAIJSetPreallocation(B,0,d_nnz,0,o_nnz);CHKERRQ(ierr);
847     } else {
848       ierr = MatSeqAIJSetPreallocation(B,0,d_nnz);CHKERRQ(ierr);
849     }
850     ierr = PetscFree(d_nnz);CHKERRQ(ierr);
851     ierr = PetscFree(o_nnz);CHKERRQ(ierr);
852   } else B = *newmat;
853   ierr = MatConvert_Basic(A,newtype,MAT_REUSE_MATRIX,&B);CHKERRQ(ierr);
854   if (reuse == MAT_INPLACE_MATRIX) {
855     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
856   } else *newmat = B;
857   PetscFunctionReturn(0);
858 }
859 
860 PetscErrorCode MatSOR_SeqKAIJ(Mat A,Vec bb,PetscReal omega,MatSORType flag,PetscReal fshift,PetscInt its,PetscInt lits,Vec xx)
861 {
862   PetscErrorCode    ierr;
863   Mat_SeqKAIJ       *kaij = (Mat_SeqKAIJ*) A->data;
864   Mat_SeqAIJ        *a = (Mat_SeqAIJ*)kaij->AIJ->data;
865   const PetscScalar *aa = a->a, *T = kaij->T, *v;
866   const PetscInt    m  = kaij->AIJ->rmap->n, *ai=a->i, *aj=a->j, p = kaij->p, q = kaij->q, *diag, *vi;
867   const PetscScalar *b, *xb, *idiag;
868   PetscScalar       *x, *work, *workt, *w, *y, *arr, *t, *arrt;
869   PetscInt          i, j, k, i2, bs, bs2, nz;
870 
871   PetscFunctionBegin;
872   its = its*lits;
873   PetscCheckFalse(flag & SOR_EISENSTAT,PETSC_COMM_SELF,PETSC_ERR_SUP,"No support yet for Eisenstat");
874   PetscCheckFalse(its <= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Relaxation requires global its %" PetscInt_FMT " and local its %" PetscInt_FMT " both positive",its,lits);
875   PetscCheckFalse(fshift,PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for diagonal shift");
876   PetscCheckFalse((flag & SOR_APPLY_UPPER) || (flag & SOR_APPLY_LOWER),PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for applying upper or lower triangular parts");
877   PetscCheckFalse(p != q,PETSC_COMM_SELF,PETSC_ERR_SUP,"MatSOR for KAIJ: No support for non-square dense blocks");
878   else        {bs = p; bs2 = bs*bs; }
879 
880   if (!m) PetscFunctionReturn(0);
881 
882   if (!kaij->ibdiagvalid) { ierr = MatInvertBlockDiagonal_SeqKAIJ(A,NULL);CHKERRQ(ierr); }
883   idiag = kaij->ibdiag;
884   diag  = a->diag;
885 
886   if (!kaij->sor.setup) {
887     ierr = PetscMalloc5(bs,&kaij->sor.w,bs,&kaij->sor.y,m*bs,&kaij->sor.work,m*bs,&kaij->sor.t,m*bs2,&kaij->sor.arr);CHKERRQ(ierr);
888     kaij->sor.setup = PETSC_TRUE;
889   }
890   y     = kaij->sor.y;
891   w     = kaij->sor.w;
892   work  = kaij->sor.work;
893   t     = kaij->sor.t;
894   arr   = kaij->sor.arr;
895 
896   ierr = VecGetArray(xx,&x);    CHKERRQ(ierr);
897   ierr = VecGetArrayRead(bb,&b);CHKERRQ(ierr);
898 
899   if (flag & SOR_ZERO_INITIAL_GUESS) {
900     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
901       PetscKernel_w_gets_Ar_times_v(bs,bs,b,idiag,x);                            /* x[0:bs] <- D^{-1} b[0:bs] */
902       ierr   =  PetscMemcpy(t,b,bs*sizeof(PetscScalar));CHKERRQ(ierr);
903       i2     =  bs;
904       idiag  += bs2;
905       for (i=1; i<m; i++) {
906         v  = aa + ai[i];
907         vi = aj + ai[i];
908         nz = diag[i] - ai[i];
909 
910         if (T) {                /* b - T (Arow * x) */
911           ierr = PetscMemzero(w,bs*sizeof(PetscScalar));CHKERRQ(ierr);
912           for (j=0; j<nz; j++) {
913             for (k=0; k<bs; k++) w[k] -= v[j] * x[vi[j]*bs+k];
914           }
915           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs,w,T,&t[i2]);
916           for (k=0; k<bs; k++) t[i2+k] += b[i2+k];
917         } else if (kaij->isTI) {
918           ierr = PetscMemcpy(t+i2,b+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
919           for (j=0; j<nz; j++) {
920             for (k=0; k<bs; k++) t[i2+k] -= v[j] * x[vi[j]*bs+k];
921           }
922         } else {
923           ierr = PetscMemcpy(t+i2,b+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
924         }
925 
926         PetscKernel_w_gets_Ar_times_v(bs,bs,t+i2,idiag,y);
927         for (j=0; j<bs; j++) x[i2+j] = omega * y[j];
928 
929         idiag += bs2;
930         i2    += bs;
931       }
932       /* for logging purposes assume number of nonzero in lower half is 1/2 of total */
933       ierr = PetscLogFlops(1.0*bs2*a->nz);CHKERRQ(ierr);
934       xb = t;
935     } else xb = b;
936     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
937       idiag = kaij->ibdiag+bs2*(m-1);
938       i2    = bs * (m-1);
939       ierr  = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
940       PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,x+i2);
941       i2    -= bs;
942       idiag -= bs2;
943       for (i=m-2; i>=0; i--) {
944         v  = aa + diag[i] + 1 ;
945         vi = aj + diag[i] + 1;
946         nz = ai[i+1] - diag[i] - 1;
947 
948         if (T) {                /* FIXME: This branch untested */
949           ierr = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
950           /* copy all rows of x that are needed into contiguous space */
951           workt = work;
952           for (j=0; j<nz; j++) {
953             ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
954             workt += bs;
955           }
956           arrt = arr;
957           for (j=0; j<nz; j++) {
958             ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
959             for (k=0; k<bs2; k++) arrt[k] *= v[j];
960             arrt += bs2;
961           }
962           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
963         } else if (kaij->isTI) {
964           ierr = PetscMemcpy(w,t+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
965           for (j=0; j<nz; j++) {
966             for (k=0; k<bs; k++) w[k] -= v[j] * x[vi[j]*bs+k];
967           }
968         }
969 
970         PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,y); /* RHS incorrect for omega != 1.0 */
971         for (j=0; j<bs; j++) x[i2+j] = (1.0-omega) * x[i2+j] + omega * y[j];
972 
973         idiag -= bs2;
974         i2    -= bs;
975       }
976       ierr = PetscLogFlops(1.0*bs2*(a->nz));CHKERRQ(ierr);
977     }
978     its--;
979   }
980   while (its--) {               /* FIXME: This branch not updated */
981     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
982       i2     =  0;
983       idiag  = kaij->ibdiag;
984       for (i=0; i<m; i++) {
985         ierr = PetscMemcpy(w,b+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
986 
987         v  = aa + ai[i];
988         vi = aj + ai[i];
989         nz = diag[i] - ai[i];
990         workt = work;
991         for (j=0; j<nz; j++) {
992           ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
993           workt += bs;
994         }
995         arrt = arr;
996         if (T) {
997           for (j=0; j<nz; j++) {
998             ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
999             for (k=0; k<bs2; k++) arrt[k] *= v[j];
1000             arrt += bs2;
1001           }
1002           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1003         } else if (kaij->isTI) {
1004           for (j=0; j<nz; j++) {
1005             ierr = PetscMemzero(arrt,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1006             for (k=0; k<bs; k++) arrt[k+bs*k] = v[j];
1007             arrt += bs2;
1008           }
1009           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1010         }
1011         ierr = PetscMemcpy(t+i2,w,bs*sizeof(PetscScalar));CHKERRQ(ierr);
1012 
1013         v  = aa + diag[i] + 1;
1014         vi = aj + diag[i] + 1;
1015         nz = ai[i+1] - diag[i] - 1;
1016         workt = work;
1017         for (j=0; j<nz; j++) {
1018           ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
1019           workt += bs;
1020         }
1021         arrt = arr;
1022         if (T) {
1023           for (j=0; j<nz; j++) {
1024             ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1025             for (k=0; k<bs2; k++) arrt[k] *= v[j];
1026             arrt += bs2;
1027           }
1028           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1029         } else if (kaij->isTI) {
1030           for (j=0; j<nz; j++) {
1031             ierr = PetscMemzero(arrt,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1032             for (k=0; k<bs; k++) arrt[k+bs*k] = v[j];
1033             arrt += bs2;
1034           }
1035           PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1036         }
1037 
1038         PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,y);
1039         for (j=0; j<bs; j++) *(x+i2+j) = (1.0-omega) * *(x+i2+j) + omega * *(y+j);
1040 
1041         idiag += bs2;
1042         i2    += bs;
1043       }
1044       xb = t;
1045     }
1046     else xb = b;
1047     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
1048       idiag = kaij->ibdiag+bs2*(m-1);
1049       i2    = bs * (m-1);
1050       if (xb == b) {
1051         for (i=m-1; i>=0; i--) {
1052           ierr = PetscMemcpy(w,b+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
1053 
1054           v  = aa + ai[i];
1055           vi = aj + ai[i];
1056           nz = diag[i] - ai[i];
1057           workt = work;
1058           for (j=0; j<nz; j++) {
1059             ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
1060             workt += bs;
1061           }
1062           arrt = arr;
1063           if (T) {
1064             for (j=0; j<nz; j++) {
1065               ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1066               for (k=0; k<bs2; k++) arrt[k] *= v[j];
1067               arrt += bs2;
1068             }
1069             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1070           } else if (kaij->isTI) {
1071             for (j=0; j<nz; j++) {
1072               ierr = PetscMemzero(arrt,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1073               for (k=0; k<bs; k++) arrt[k+bs*k] = v[j];
1074               arrt += bs2;
1075             }
1076             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1077           }
1078 
1079           v  = aa + diag[i] + 1;
1080           vi = aj + diag[i] + 1;
1081           nz = ai[i+1] - diag[i] - 1;
1082           workt = work;
1083           for (j=0; j<nz; j++) {
1084             ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
1085             workt += bs;
1086           }
1087           arrt = arr;
1088           if (T) {
1089             for (j=0; j<nz; j++) {
1090               ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1091               for (k=0; k<bs2; k++) arrt[k] *= v[j];
1092               arrt += bs2;
1093             }
1094             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1095           } else if (kaij->isTI) {
1096             for (j=0; j<nz; j++) {
1097               ierr = PetscMemzero(arrt,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1098               for (k=0; k<bs; k++) arrt[k+bs*k] = v[j];
1099               arrt += bs2;
1100             }
1101             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1102           }
1103 
1104           PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,y);
1105           for (j=0; j<bs; j++) *(x+i2+j) = (1.0-omega) * *(x+i2+j) + omega * *(y+j);
1106         }
1107       } else {
1108         for (i=m-1; i>=0; i--) {
1109           ierr = PetscMemcpy(w,xb+i2,bs*sizeof(PetscScalar));CHKERRQ(ierr);
1110           v  = aa + diag[i] + 1;
1111           vi = aj + diag[i] + 1;
1112           nz = ai[i+1] - diag[i] - 1;
1113           workt = work;
1114           for (j=0; j<nz; j++) {
1115             ierr   = PetscMemcpy(workt,x + bs*(*vi++),bs*sizeof(PetscScalar));CHKERRQ(ierr);
1116             workt += bs;
1117           }
1118           arrt = arr;
1119           if (T) {
1120             for (j=0; j<nz; j++) {
1121               ierr  = PetscMemcpy(arrt,T,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1122               for (k=0; k<bs2; k++) arrt[k] *= v[j];
1123               arrt += bs2;
1124             }
1125             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1126           } else if (kaij->isTI) {
1127             for (j=0; j<nz; j++) {
1128               ierr = PetscMemzero(arrt,bs2*sizeof(PetscScalar));CHKERRQ(ierr);
1129               for (k=0; k<bs; k++) arrt[k+bs*k] = v[j];
1130               arrt += bs2;
1131             }
1132             PetscKernel_w_gets_w_minus_Ar_times_v(bs,bs*nz,w,arr,work);
1133           }
1134           PetscKernel_w_gets_Ar_times_v(bs,bs,w,idiag,y);
1135           for (j=0; j<bs; j++) *(x+i2+j) = (1.0-omega) * *(x+i2+j) + omega * *(y+j);
1136         }
1137       }
1138       ierr = PetscLogFlops(1.0*bs2*(a->nz));CHKERRQ(ierr);
1139     }
1140   }
1141 
1142   ierr = VecRestoreArray(xx,&x);    CHKERRQ(ierr);
1143   ierr = VecRestoreArrayRead(bb,&b);CHKERRQ(ierr);
1144   PetscFunctionReturn(0);
1145 }
1146 
1147 /*===================================================================================*/
1148 
1149 PetscErrorCode MatMultAdd_MPIKAIJ(Mat A,Vec xx,Vec yy,Vec zz)
1150 {
1151   Mat_MPIKAIJ    *b = (Mat_MPIKAIJ*)A->data;
1152   PetscErrorCode ierr;
1153 
1154   PetscFunctionBegin;
1155   if (!yy) {
1156     ierr = VecSet(zz,0.0);CHKERRQ(ierr);
1157   } else {
1158     ierr = VecCopy(yy,zz);CHKERRQ(ierr);
1159   }
1160   ierr = MatKAIJ_build_AIJ_OAIJ(A);CHKERRQ(ierr); /* Ensure b->AIJ and b->OAIJ are up to date. */
1161   /* start the scatter */
1162   ierr = VecScatterBegin(b->ctx,xx,b->w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1163   ierr = (*b->AIJ->ops->multadd)(b->AIJ,xx,zz,zz);CHKERRQ(ierr);
1164   ierr = VecScatterEnd(b->ctx,xx,b->w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1165   ierr = (*b->OAIJ->ops->multadd)(b->OAIJ,b->w,zz,zz);CHKERRQ(ierr);
1166   PetscFunctionReturn(0);
1167 }
1168 
1169 PetscErrorCode MatMult_MPIKAIJ(Mat A,Vec xx,Vec yy)
1170 {
1171   PetscErrorCode ierr;
1172   PetscFunctionBegin;
1173   ierr = MatMultAdd_MPIKAIJ(A,xx,PETSC_NULL,yy);CHKERRQ(ierr);
1174   PetscFunctionReturn(0);
1175 }
1176 
1177 PetscErrorCode MatInvertBlockDiagonal_MPIKAIJ(Mat A,const PetscScalar **values)
1178 {
1179   Mat_MPIKAIJ     *b = (Mat_MPIKAIJ*)A->data;
1180   PetscErrorCode  ierr;
1181 
1182   PetscFunctionBegin;
1183   ierr = MatKAIJ_build_AIJ_OAIJ(A);CHKERRQ(ierr); /* Ensure b->AIJ is up to date. */
1184   ierr = (*b->AIJ->ops->invertblockdiagonal)(b->AIJ,values);CHKERRQ(ierr);
1185   PetscFunctionReturn(0);
1186 }
1187 
1188 /* ----------------------------------------------------------------*/
1189 
1190 PetscErrorCode MatGetRow_SeqKAIJ(Mat A,PetscInt row,PetscInt *ncols,PetscInt **cols,PetscScalar **values)
1191 {
1192   Mat_SeqKAIJ     *b   = (Mat_SeqKAIJ*) A->data;
1193   PetscErrorCode  diag = PETSC_FALSE;
1194   PetscErrorCode  ierr;
1195   PetscInt        nzaij,nz,*colsaij,*idx,i,j,p=b->p,q=b->q,r=row/p,s=row%p,c;
1196   PetscScalar     *vaij,*v,*S=b->S,*T=b->T;
1197 
1198   PetscFunctionBegin;
1199   PetscCheckFalse(b->getrowactive,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Already active");
1200   b->getrowactive = PETSC_TRUE;
1201   PetscCheckFalse(row < 0 || row >= A->rmap->n,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Row %" PetscInt_FMT " out of range",row);
1202 
1203   if ((!S) && (!T) && (!b->isTI)) {
1204     if (ncols)    *ncols  = 0;
1205     if (cols)     *cols   = NULL;
1206     if (values)   *values = NULL;
1207     PetscFunctionReturn(0);
1208   }
1209 
1210   if (T || b->isTI) {
1211     ierr  = MatGetRow_SeqAIJ(b->AIJ,r,&nzaij,&colsaij,&vaij);CHKERRQ(ierr);
1212     c     = nzaij;
1213     for (i=0; i<nzaij; i++) {
1214       /* check if this row contains a diagonal entry */
1215       if (colsaij[i] == r) {
1216         diag = PETSC_TRUE;
1217         c = i;
1218       }
1219     }
1220   } else nzaij = c = 0;
1221 
1222   /* calculate size of row */
1223   nz = 0;
1224   if (S)            nz += q;
1225   if (T || b->isTI) nz += (diag && S ? (nzaij-1)*q : nzaij*q);
1226 
1227   if (cols || values) {
1228     ierr = PetscMalloc2(nz,&idx,nz,&v);CHKERRQ(ierr);
1229     for (i=0; i<q; i++) {
1230       /* We need to initialize the v[i] to zero to handle the case in which T is NULL (not the identity matrix). */
1231       v[i] = 0.0;
1232     }
1233     if (b->isTI) {
1234       for (i=0; i<nzaij; i++) {
1235         for (j=0; j<q; j++) {
1236           idx[i*q+j] = colsaij[i]*q+j;
1237           v[i*q+j]   = (j==s ? vaij[i] : 0);
1238         }
1239       }
1240     } else if (T) {
1241       for (i=0; i<nzaij; i++) {
1242         for (j=0; j<q; j++) {
1243           idx[i*q+j] = colsaij[i]*q+j;
1244           v[i*q+j]   = vaij[i]*T[s+j*p];
1245         }
1246       }
1247     }
1248     if (S) {
1249       for (j=0; j<q; j++) {
1250         idx[c*q+j] = r*q+j;
1251         v[c*q+j]  += S[s+j*p];
1252       }
1253     }
1254   }
1255 
1256   if (ncols)    *ncols  = nz;
1257   if (cols)     *cols   = idx;
1258   if (values)   *values = v;
1259   PetscFunctionReturn(0);
1260 }
1261 
1262 PetscErrorCode MatRestoreRow_SeqKAIJ(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
1263 {
1264   PetscErrorCode ierr;
1265 
1266   PetscFunctionBegin;
1267   if (nz) *nz = 0;
1268   ierr = PetscFree2(*idx,*v);CHKERRQ(ierr);
1269   ((Mat_SeqKAIJ*)A->data)->getrowactive = PETSC_FALSE;
1270   PetscFunctionReturn(0);
1271 }
1272 
1273 PetscErrorCode MatGetRow_MPIKAIJ(Mat A,PetscInt row,PetscInt *ncols,PetscInt **cols,PetscScalar **values)
1274 {
1275   Mat_MPIKAIJ     *b      = (Mat_MPIKAIJ*) A->data;
1276   Mat             AIJ     = b->A;
1277   PetscBool       diag    = PETSC_FALSE;
1278   Mat             MatAIJ,MatOAIJ;
1279   PetscErrorCode  ierr;
1280   const PetscInt  rstart=A->rmap->rstart,rend=A->rmap->rend,p=b->p,q=b->q,*garray;
1281   PetscInt        nz,*idx,ncolsaij = 0,ncolsoaij = 0,*colsaij,*colsoaij,r,s,c,i,j,lrow;
1282   PetscScalar     *v,*vals,*ovals,*S=b->S,*T=b->T;
1283 
1284   PetscFunctionBegin;
1285   ierr = MatKAIJ_build_AIJ_OAIJ(A);CHKERRQ(ierr); /* Ensure b->AIJ and b->OAIJ are up to date. */
1286   MatAIJ  = ((Mat_SeqKAIJ*)b->AIJ->data)->AIJ;
1287   MatOAIJ = ((Mat_SeqKAIJ*)b->OAIJ->data)->AIJ;
1288   PetscCheckFalse(b->getrowactive,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Already active");
1289   b->getrowactive = PETSC_TRUE;
1290   PetscCheckFalse(row < rstart || row >= rend,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Only local rows");
1291   lrow = row - rstart;
1292 
1293   if ((!S) && (!T) && (!b->isTI)) {
1294     if (ncols)    *ncols  = 0;
1295     if (cols)     *cols   = NULL;
1296     if (values)   *values = NULL;
1297     PetscFunctionReturn(0);
1298   }
1299 
1300   r = lrow/p;
1301   s = lrow%p;
1302 
1303   if (T || b->isTI) {
1304     ierr = MatMPIAIJGetSeqAIJ(AIJ,NULL,NULL,&garray);CHKERRQ(ierr);
1305     ierr = MatGetRow_SeqAIJ(MatAIJ,lrow/p,&ncolsaij,&colsaij,&vals);CHKERRQ(ierr);
1306     ierr = MatGetRow_SeqAIJ(MatOAIJ,lrow/p,&ncolsoaij,&colsoaij,&ovals);CHKERRQ(ierr);
1307 
1308     c     = ncolsaij + ncolsoaij;
1309     for (i=0; i<ncolsaij; i++) {
1310       /* check if this row contains a diagonal entry */
1311       if (colsaij[i] == r) {
1312         diag = PETSC_TRUE;
1313         c = i;
1314       }
1315     }
1316   } else c = 0;
1317 
1318   /* calculate size of row */
1319   nz = 0;
1320   if (S)            nz += q;
1321   if (T || b->isTI) nz += (diag && S ? (ncolsaij+ncolsoaij-1)*q : (ncolsaij+ncolsoaij)*q);
1322 
1323   if (cols || values) {
1324     ierr = PetscMalloc2(nz,&idx,nz,&v);CHKERRQ(ierr);
1325     for (i=0; i<q; i++) {
1326       /* We need to initialize the v[i] to zero to handle the case in which T is NULL (not the identity matrix). */
1327       v[i] = 0.0;
1328     }
1329     if (b->isTI) {
1330       for (i=0; i<ncolsaij; i++) {
1331         for (j=0; j<q; j++) {
1332           idx[i*q+j] = (colsaij[i]+rstart/p)*q+j;
1333           v[i*q+j]   = (j==s ? vals[i] : 0.0);
1334         }
1335       }
1336       for (i=0; i<ncolsoaij; i++) {
1337         for (j=0; j<q; j++) {
1338           idx[(i+ncolsaij)*q+j] = garray[colsoaij[i]]*q+j;
1339           v[(i+ncolsaij)*q+j]   = (j==s ? ovals[i]: 0.0);
1340         }
1341       }
1342     } else if (T) {
1343       for (i=0; i<ncolsaij; i++) {
1344         for (j=0; j<q; j++) {
1345           idx[i*q+j] = (colsaij[i]+rstart/p)*q+j;
1346           v[i*q+j]   = vals[i]*T[s+j*p];
1347         }
1348       }
1349       for (i=0; i<ncolsoaij; i++) {
1350         for (j=0; j<q; j++) {
1351           idx[(i+ncolsaij)*q+j] = garray[colsoaij[i]]*q+j;
1352           v[(i+ncolsaij)*q+j]   = ovals[i]*T[s+j*p];
1353         }
1354       }
1355     }
1356     if (S) {
1357       for (j=0; j<q; j++) {
1358         idx[c*q+j] = (r+rstart/p)*q+j;
1359         v[c*q+j]  += S[s+j*p];
1360       }
1361     }
1362   }
1363 
1364   if (ncols)  *ncols  = nz;
1365   if (cols)   *cols   = idx;
1366   if (values) *values = v;
1367   PetscFunctionReturn(0);
1368 }
1369 
1370 PetscErrorCode MatRestoreRow_MPIKAIJ(Mat A,PetscInt row,PetscInt *nz,PetscInt **idx,PetscScalar **v)
1371 {
1372   PetscErrorCode ierr;
1373   PetscFunctionBegin;
1374   ierr = PetscFree2(*idx,*v);CHKERRQ(ierr);
1375   ((Mat_SeqKAIJ*)A->data)->getrowactive = PETSC_FALSE;
1376   PetscFunctionReturn(0);
1377 }
1378 
1379 PetscErrorCode  MatCreateSubMatrix_KAIJ(Mat mat,IS isrow,IS iscol,MatReuse cll,Mat *newmat)
1380 {
1381   PetscErrorCode ierr;
1382   Mat            A;
1383 
1384   PetscFunctionBegin;
1385   ierr = MatConvert(mat,MATAIJ,MAT_INITIAL_MATRIX,&A);CHKERRQ(ierr);
1386   ierr = MatCreateSubMatrix(A,isrow,iscol,cll,newmat);CHKERRQ(ierr);
1387   ierr = MatDestroy(&A);CHKERRQ(ierr);
1388   PetscFunctionReturn(0);
1389 }
1390 
1391 /* ---------------------------------------------------------------------------------- */
1392 /*@C
1393   MatCreateKAIJ - Creates a matrix type to be used for matrices of the following form:
1394 
1395     [I \otimes S + A \otimes T]
1396 
1397   where
1398     S is a dense (p \times q) matrix
1399     T is a dense (p \times q) matrix
1400     A is an AIJ  (n \times n) matrix
1401     I is the identity matrix
1402   The resulting matrix is (np \times nq)
1403 
1404   S and T are always stored independently on all processes as PetscScalar arrays in column-major format.
1405 
1406   Collective
1407 
1408   Input Parameters:
1409 + A - the AIJ matrix
1410 . p - number of rows in S and T
1411 . q - number of columns in S and T
1412 . S - the S matrix (can be PETSC_NULL), stored as a PetscScalar array (column-major)
1413 - T - the T matrix (can be PETSC_NULL), stored as a PetscScalar array (column-major)
1414 
1415   Output Parameter:
1416 . kaij - the new KAIJ matrix
1417 
1418   Notes:
1419   This function increases the reference count on the AIJ matrix, so the user is free to destroy the matrix if it is not needed.
1420   Changes to the entries of the AIJ matrix will immediately affect the KAIJ matrix.
1421 
1422   Developer Notes:
1423   In the MATMPIKAIJ case, the internal 'AIJ' and 'OAIJ' sequential KAIJ matrices are kept up to date by tracking the object state
1424   of the AIJ matrix 'A' that describes the blockwise action of the MATMPIKAIJ matrix and, if the object state has changed, lazily
1425   rebuilding 'AIJ' and 'OAIJ' just before executing operations with the MATMPIKAIJ matrix. If new types of operations are added,
1426   routines implementing those must also ensure these are rebuilt when needed (by calling the internal MatKAIJ_build_AIJ_OAIJ() routine).
1427 
1428   Level: advanced
1429 
1430 .seealso: MatKAIJSetAIJ(), MatKAIJSetS(), MatKAIJSetT(), MatKAIJGetAIJ(), MatKAIJGetS(), MatKAIJGetT(), MATKAIJ
1431 @*/
1432 PetscErrorCode  MatCreateKAIJ(Mat A,PetscInt p,PetscInt q,const PetscScalar S[],const PetscScalar T[],Mat *kaij)
1433 {
1434   PetscErrorCode ierr;
1435 
1436   PetscFunctionBegin;
1437   ierr = MatCreate(PetscObjectComm((PetscObject)A),kaij);CHKERRQ(ierr);
1438   ierr = MatSetType(*kaij,MATKAIJ);CHKERRQ(ierr);
1439   ierr = MatKAIJSetAIJ(*kaij,A);CHKERRQ(ierr);
1440   ierr = MatKAIJSetS(*kaij,p,q,S);CHKERRQ(ierr);
1441   ierr = MatKAIJSetT(*kaij,p,q,T);CHKERRQ(ierr);
1442   ierr = MatSetUp(*kaij);CHKERRQ(ierr);
1443   PetscFunctionReturn(0);
1444 }
1445 
1446 /*MC
1447   MATKAIJ - MATKAIJ = "kaij" - A matrix type to be used to evaluate matrices of form
1448     [I \otimes S + A \otimes T],
1449   where
1450     S is a dense (p \times q) matrix,
1451     T is a dense (p \times q) matrix,
1452     A is an AIJ  (n \times n) matrix,
1453     and I is the identity matrix.
1454   The resulting matrix is (np \times nq).
1455 
1456   S and T are always stored independently on all processes as PetscScalar arrays in column-major format.
1457 
1458   Notes:
1459   A linear system with multiple right-hand sides, AX = B, can be expressed in the KAIJ-friendly form of (A \otimes I) x = b,
1460   where x and b are column vectors containing the row-major representations of X and B.
1461 
1462   Level: advanced
1463 
1464 .seealso: MatKAIJSetAIJ(), MatKAIJSetS(), MatKAIJSetT(), MatKAIJGetAIJ(), MatKAIJGetS(), MatKAIJGetT(), MatCreateKAIJ()
1465 M*/
1466 
1467 PETSC_EXTERN PetscErrorCode MatCreate_KAIJ(Mat A)
1468 {
1469   PetscErrorCode ierr;
1470   Mat_MPIKAIJ    *b;
1471   PetscMPIInt    size;
1472 
1473   PetscFunctionBegin;
1474   ierr     = PetscNewLog(A,&b);CHKERRQ(ierr);
1475   A->data  = (void*)b;
1476 
1477   ierr = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
1478 
1479   b->w    = NULL;
1480   ierr    = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRMPI(ierr);
1481   if (size == 1) {
1482     ierr = PetscObjectChangeTypeName((PetscObject)A,MATSEQKAIJ);CHKERRQ(ierr);
1483     A->ops->destroy             = MatDestroy_SeqKAIJ;
1484     A->ops->mult                = MatMult_SeqKAIJ;
1485     A->ops->multadd             = MatMultAdd_SeqKAIJ;
1486     A->ops->invertblockdiagonal = MatInvertBlockDiagonal_SeqKAIJ;
1487     A->ops->getrow              = MatGetRow_SeqKAIJ;
1488     A->ops->restorerow          = MatRestoreRow_SeqKAIJ;
1489     A->ops->sor                 = MatSOR_SeqKAIJ;
1490     ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_seqkaij_seqaij_C",MatConvert_KAIJ_AIJ);CHKERRQ(ierr);
1491   } else {
1492     ierr = PetscObjectChangeTypeName((PetscObject)A,MATMPIKAIJ);CHKERRQ(ierr);
1493     A->ops->destroy             = MatDestroy_MPIKAIJ;
1494     A->ops->mult                = MatMult_MPIKAIJ;
1495     A->ops->multadd             = MatMultAdd_MPIKAIJ;
1496     A->ops->invertblockdiagonal = MatInvertBlockDiagonal_MPIKAIJ;
1497     A->ops->getrow              = MatGetRow_MPIKAIJ;
1498     A->ops->restorerow          = MatRestoreRow_MPIKAIJ;
1499     ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetDiagonalBlock_C",MatGetDiagonalBlock_MPIKAIJ);CHKERRQ(ierr);
1500     ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_mpikaij_mpiaij_C",MatConvert_KAIJ_AIJ);CHKERRQ(ierr);
1501   }
1502   A->ops->setup           = MatSetUp_KAIJ;
1503   A->ops->view            = MatView_KAIJ;
1504   A->ops->createsubmatrix = MatCreateSubMatrix_KAIJ;
1505   PetscFunctionReturn(0);
1506 }
1507