xref: /petsc/src/mat/impls/is/matis.c (revision 70cf5478945a9d09b9da66ef3d9730962f546e98)
1 
2 /*
3     Creates a matrix class for using the Neumann-Neumann type preconditioners.
4    This stores the matrices in globally unassembled form. Each processor
5    assembles only its local Neumann problem and the parallel matrix vector
6    product is handled "implicitly".
7 
8      We provide:
9          MatMult()
10 
11     Currently this allows for only one subdomain per processor.
12 
13 */
14 
15 #include <../src/mat/impls/is/matis.h>      /*I "petscmat.h" I*/
16 
17 #undef __FUNCT__
18 #define __FUNCT__ "MatIsHermitian_IS"
19 PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool  *flg)
20 {
21   PetscErrorCode ierr;
22   Mat_IS         *matis = (Mat_IS*)A->data;
23   PetscBool      local_sym;
24 
25   PetscFunctionBegin;
26   ierr = MatIsHermitian(matis->A,tol,&local_sym);CHKERRQ(ierr);
27   ierr = MPI_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
28   PetscFunctionReturn(0);
29 }
30 
31 #undef __FUNCT__
32 #define __FUNCT__ "MatIsSymmetric_IS"
33 PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool  *flg)
34 {
35   PetscErrorCode ierr;
36   Mat_IS         *matis = (Mat_IS*)A->data;
37   PetscBool      local_sym;
38 
39   PetscFunctionBegin;
40   ierr = MatIsSymmetric(matis->A,tol,&local_sym);CHKERRQ(ierr);
41   ierr = MPI_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
42   PetscFunctionReturn(0);
43 }
44 
45 #undef __FUNCT__
46 #define __FUNCT__ "MatDestroy_IS"
47 PetscErrorCode MatDestroy_IS(Mat A)
48 {
49   PetscErrorCode ierr;
50   Mat_IS         *b = (Mat_IS*)A->data;
51 
52   PetscFunctionBegin;
53   ierr = MatDestroy(&b->A);CHKERRQ(ierr);
54   ierr = VecScatterDestroy(&b->ctx);CHKERRQ(ierr);
55   ierr = VecDestroy(&b->x);CHKERRQ(ierr);
56   ierr = VecDestroy(&b->y);CHKERRQ(ierr);
57   ierr = ISLocalToGlobalMappingDestroy(&b->mapping);CHKERRQ(ierr);
58   ierr = PetscFree(A->data);CHKERRQ(ierr);
59   ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr);
60   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);CHKERRQ(ierr);
61   PetscFunctionReturn(0);
62 }
63 
64 #undef __FUNCT__
65 #define __FUNCT__ "MatMult_IS"
66 PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
67 {
68   PetscErrorCode ierr;
69   Mat_IS         *is  = (Mat_IS*)A->data;
70   PetscScalar    zero = 0.0;
71 
72   PetscFunctionBegin;
73   /*  scatter the global vector x into the local work vector */
74   ierr = VecScatterBegin(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
75   ierr = VecScatterEnd(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
76 
77   /* multiply the local matrix */
78   ierr = MatMult(is->A,is->x,is->y);CHKERRQ(ierr);
79 
80   /* scatter product back into global memory */
81   ierr = VecSet(y,zero);CHKERRQ(ierr);
82   ierr = VecScatterBegin(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
83   ierr = VecScatterEnd(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
84   PetscFunctionReturn(0);
85 }
86 
87 #undef __FUNCT__
88 #define __FUNCT__ "MatMultAdd_IS"
89 static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
90 {
91   Vec            temp_vec;
92   PetscErrorCode ierr;
93 
94   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
95   if (v3 != v2) {
96     ierr = MatMult(A,v1,v3);CHKERRQ(ierr);
97     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
98   } else {
99     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
100     ierr = MatMult(A,v1,temp_vec);CHKERRQ(ierr);
101     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
102     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
103     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
104   }
105   PetscFunctionReturn(0);
106 }
107 
108 #undef __FUNCT__
109 #define __FUNCT__ "MatMultTranspose_IS"
110 PetscErrorCode MatMultTranspose_IS(Mat A,Vec x,Vec y)
111 {
112   Mat_IS         *is = (Mat_IS*)A->data;
113   PetscErrorCode ierr;
114 
115   PetscFunctionBegin; /*  y = A' * x */
116   /*  scatter the global vector x into the local work vector */
117   ierr = VecScatterBegin(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
118   ierr = VecScatterEnd(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
119 
120   /* multiply the local matrix */
121   ierr = MatMultTranspose(is->A,is->x,is->y);CHKERRQ(ierr);
122 
123   /* scatter product back into global vector */
124   ierr = VecSet(y,0);CHKERRQ(ierr);
125   ierr = VecScatterBegin(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
126   ierr = VecScatterEnd(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
127   PetscFunctionReturn(0);
128 }
129 
130 #undef __FUNCT__
131 #define __FUNCT__ "MatMultTransposeAdd_IS"
132 PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
133 {
134   Vec            temp_vec;
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
138   if (v3 != v2) {
139     ierr = MatMultTranspose(A,v1,v3);CHKERRQ(ierr);
140     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
141   } else {
142     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
143     ierr = MatMultTranspose(A,v1,temp_vec);CHKERRQ(ierr);
144     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
145     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
146     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
147   }
148   PetscFunctionReturn(0);
149 }
150 
151 #undef __FUNCT__
152 #define __FUNCT__ "MatView_IS"
153 PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
154 {
155   Mat_IS         *a = (Mat_IS*)A->data;
156   PetscErrorCode ierr;
157   PetscViewer    sviewer;
158 
159   PetscFunctionBegin;
160   ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
161   ierr = MatView(a->A,sviewer);CHKERRQ(ierr);
162   ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "MatSetLocalToGlobalMapping_IS"
168 PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
169 {
170   PetscErrorCode ierr;
171   PetscInt       n,bs;
172   Mat_IS         *is = (Mat_IS*)A->data;
173   IS             from,to;
174   Vec            global;
175 
176   PetscFunctionBegin;
177   PetscCheckSameComm(A,1,rmapping,2);
178   if (rmapping != cmapping) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"MATIS requires the row and column mappings to be identical");
179   if (is->mapping) { /* Currenly destroys the objects that will be created by this routine. Is there anything else that should be checked? */
180     ierr = ISLocalToGlobalMappingDestroy(&is->mapping);CHKERRQ(ierr);
181     ierr = VecDestroy(&is->x);CHKERRQ(ierr);
182     ierr = VecDestroy(&is->y);CHKERRQ(ierr);
183     ierr = VecScatterDestroy(&is->ctx);CHKERRQ(ierr);
184   }
185   ierr = PetscObjectReference((PetscObject)rmapping);CHKERRQ(ierr);
186   ierr = ISLocalToGlobalMappingDestroy(&is->mapping);CHKERRQ(ierr);
187   is->mapping = rmapping;
188 /*
189   ierr = PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);CHKERRQ(ierr);
190   ierr = PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);CHKERRQ(ierr);
191 */
192 
193   /* Create the local matrix A */
194   ierr = ISLocalToGlobalMappingGetSize(rmapping,&n);CHKERRQ(ierr);
195   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
196   ierr = MatCreate(PETSC_COMM_SELF,&is->A);CHKERRQ(ierr);
197   ierr = MatSetSizes(is->A,n,n,n,n);CHKERRQ(ierr);
198   ierr = MatSetBlockSize(is->A,bs);CHKERRQ(ierr);
199   ierr = MatSetOptionsPrefix(is->A,((PetscObject)A)->prefix);CHKERRQ(ierr);
200   ierr = MatAppendOptionsPrefix(is->A,"is_");CHKERRQ(ierr);
201   ierr = MatSetFromOptions(is->A);CHKERRQ(ierr);
202 
203   /* Create the local work vectors */
204   ierr = VecCreate(PETSC_COMM_SELF,&is->x);CHKERRQ(ierr);
205   ierr = VecSetBlockSize(is->x,bs);CHKERRQ(ierr);
206   ierr = VecSetSizes(is->x,n,n);CHKERRQ(ierr);
207   ierr = VecSetOptionsPrefix(is->x,((PetscObject)A)->prefix);CHKERRQ(ierr);
208   ierr = VecAppendOptionsPrefix(is->x,"is_");CHKERRQ(ierr);
209   ierr = VecSetFromOptions(is->x);CHKERRQ(ierr);
210   ierr = VecDuplicate(is->x,&is->y);CHKERRQ(ierr);
211 
212   /* setup the global to local scatter */
213   ierr = ISCreateStride(PETSC_COMM_SELF,n,0,1,&to);CHKERRQ(ierr);
214   ierr = ISLocalToGlobalMappingApplyIS(rmapping,to,&from);CHKERRQ(ierr);
215   ierr = MatGetVecs(A,&global,NULL);CHKERRQ(ierr);
216   ierr = VecScatterCreate(global,from,is->x,to,&is->ctx);CHKERRQ(ierr);
217   ierr = VecDestroy(&global);CHKERRQ(ierr);
218   ierr = ISDestroy(&to);CHKERRQ(ierr);
219   ierr = ISDestroy(&from);CHKERRQ(ierr);
220   PetscFunctionReturn(0);
221 }
222 
223 #undef __FUNCT__
224 #define __FUNCT__ "MatSetValues_IS"
225 PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
226 {
227   Mat_IS         *is = (Mat_IS*)mat->data;
228   PetscInt       rows_l[2048],cols_l[2048];
229   PetscErrorCode ierr;
230 
231   PetscFunctionBegin;
232 #if defined(PETSC_USE_DEBUG)
233   if (m > 2048 || n > 2048) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= 2048: they are %D %D",m,n);
234 #endif
235   ierr = ISG2LMapApply(is->mapping,m,rows,rows_l);CHKERRQ(ierr);
236   ierr = ISG2LMapApply(is->mapping,n,cols,cols_l);CHKERRQ(ierr);
237   ierr = MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
238   PetscFunctionReturn(0);
239 }
240 
241 #undef ISG2LMapSetUp
242 #undef ISG2LMapApply
243 
244 #undef __FUNCT__
245 #define __FUNCT__ "MatSetValuesLocal_IS"
246 PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
247 {
248   PetscErrorCode ierr;
249   Mat_IS         *is = (Mat_IS*)A->data;
250 
251   PetscFunctionBegin;
252   ierr = MatSetValues(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
253   PetscFunctionReturn(0);
254 }
255 
256 #undef __FUNCT__
257 #define __FUNCT__ "MatSetValuesBlockedLocal_IS"
258 PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
259 {
260   PetscErrorCode ierr;
261   Mat_IS         *is = (Mat_IS*)A->data;
262 
263   PetscFunctionBegin;
264   ierr = MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
265   PetscFunctionReturn(0);
266 }
267 
268 #undef __FUNCT__
269 #define __FUNCT__ "MatZeroRows_IS"
270 PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
271 {
272   Mat_IS         *is = (Mat_IS*)A->data;
273   PetscInt       n_l = 0, *rows_l = NULL;
274   PetscErrorCode ierr;
275 
276   PetscFunctionBegin;
277   if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support");
278   if (n) {
279     ierr = PetscMalloc(n*sizeof(PetscInt),&rows_l);CHKERRQ(ierr);
280     ierr = ISGlobalToLocalMappingApply(is->mapping,IS_GTOLM_DROP,n,rows,&n_l,rows_l);CHKERRQ(ierr);
281   }
282   ierr = MatZeroRowsLocal(A,n_l,rows_l,diag,x,b);CHKERRQ(ierr);
283   ierr = PetscFree(rows_l);CHKERRQ(ierr);
284   PetscFunctionReturn(0);
285 }
286 
287 #undef __FUNCT__
288 #define __FUNCT__ "MatZeroRowsLocal_IS"
289 PetscErrorCode MatZeroRowsLocal_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
290 {
291   Mat_IS         *is = (Mat_IS*)A->data;
292   PetscErrorCode ierr;
293   PetscInt       i;
294   PetscScalar    *array;
295 
296   PetscFunctionBegin;
297   if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support");
298   {
299     /*
300        Set up is->x as a "counting vector". This is in order to MatMult_IS
301        work properly in the interface nodes.
302     */
303     Vec         counter;
304     PetscScalar one=1.0, zero=0.0;
305     ierr = MatGetVecs(A,&counter,NULL);CHKERRQ(ierr);
306     ierr = VecSet(counter,zero);CHKERRQ(ierr);
307     ierr = VecSet(is->x,one);CHKERRQ(ierr);
308     ierr = VecScatterBegin(is->ctx,is->x,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
309     ierr = VecScatterEnd  (is->ctx,is->x,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
310     ierr = VecScatterBegin(is->ctx,counter,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
311     ierr = VecScatterEnd  (is->ctx,counter,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
312     ierr = VecDestroy(&counter);CHKERRQ(ierr);
313   }
314   if (!n) {
315     is->pure_neumann = PETSC_TRUE;
316   } else {
317     is->pure_neumann = PETSC_FALSE;
318 
319     ierr = VecGetArray(is->x,&array);CHKERRQ(ierr);
320     ierr = MatZeroRows(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
321     for (i=0; i<n; i++) {
322       ierr = MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);CHKERRQ(ierr);
323     }
324     ierr = MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
325     ierr = MatAssemblyEnd  (is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
326     ierr = VecRestoreArray(is->x,&array);CHKERRQ(ierr);
327   }
328   PetscFunctionReturn(0);
329 }
330 
331 #undef __FUNCT__
332 #define __FUNCT__ "MatAssemblyBegin_IS"
333 PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
334 {
335   Mat_IS         *is = (Mat_IS*)A->data;
336   PetscErrorCode ierr;
337 
338   PetscFunctionBegin;
339   ierr = MatAssemblyBegin(is->A,type);CHKERRQ(ierr);
340   PetscFunctionReturn(0);
341 }
342 
343 #undef __FUNCT__
344 #define __FUNCT__ "MatAssemblyEnd_IS"
345 PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
346 {
347   Mat_IS         *is = (Mat_IS*)A->data;
348   PetscErrorCode ierr;
349 
350   PetscFunctionBegin;
351   ierr = MatAssemblyEnd(is->A,type);CHKERRQ(ierr);
352   PetscFunctionReturn(0);
353 }
354 
355 #undef __FUNCT__
356 #define __FUNCT__ "MatISGetLocalMat_IS"
357 PetscErrorCode  MatISGetLocalMat_IS(Mat mat,Mat *local)
358 {
359   Mat_IS *is = (Mat_IS*)mat->data;
360 
361   PetscFunctionBegin;
362   *local = is->A;
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "MatISGetLocalMat"
368 /*@
369     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
370 
371   Input Parameter:
372 .  mat - the matrix
373 
374   Output Parameter:
375 .  local - the local matrix usually MATSEQAIJ
376 
377   Level: advanced
378 
379   Notes:
380     This can be called if you have precomputed the nonzero structure of the
381   matrix and want to provide it to the inner matrix object to improve the performance
382   of the MatSetValues() operation.
383 
384 .seealso: MATIS
385 @*/
386 PetscErrorCode  MatISGetLocalMat(Mat mat,Mat *local)
387 {
388   PetscErrorCode ierr;
389 
390   PetscFunctionBegin;
391   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
392   PetscValidPointer(local,2);
393   ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "MatISSetLocalMat_IS"
399 PetscErrorCode  MatISSetLocalMat_IS(Mat mat,Mat local)
400 {
401   Mat_IS         *is = (Mat_IS*)mat->data;
402   PetscInt       nrows,ncols,orows,ocols;
403   PetscErrorCode ierr;
404 
405   PetscFunctionBegin;
406   if (is->A) {
407     ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr);
408     ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr);
409     if (orows != nrows || ocols != ncols) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local MATIS matrix should be of size %dx%d (you passed a %dx%d matrix)\n",orows,ocols,nrows,ncols);
410   }
411   ierr  = PetscObjectReference((PetscObject)local);CHKERRQ(ierr);
412   ierr  = MatDestroy(&is->A);CHKERRQ(ierr);
413   is->A = local;
414   PetscFunctionReturn(0);
415 }
416 
417 #undef __FUNCT__
418 #define __FUNCT__ "MatISSetLocalMat"
419 /*@
420     MatISSetLocalMat - Set the local matrix stored inside a MATIS matrix.
421 
422   Input Parameter:
423 .  mat - the matrix
424 .  local - the local matrix usually MATSEQAIJ
425 
426   Output Parameter:
427 
428   Level: advanced
429 
430   Notes:
431     This can be called if you have precomputed the local matrix and
432   want to provide it to the matrix object MATIS.
433 
434 .seealso: MATIS
435 @*/
436 PetscErrorCode  MatISSetLocalMat(Mat mat,Mat local)
437 {
438   PetscErrorCode ierr;
439 
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
442   ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr);
443   PetscFunctionReturn(0);
444 }
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "MatZeroEntries_IS"
448 PetscErrorCode MatZeroEntries_IS(Mat A)
449 {
450   Mat_IS         *a = (Mat_IS*)A->data;
451   PetscErrorCode ierr;
452 
453   PetscFunctionBegin;
454   ierr = MatZeroEntries(a->A);CHKERRQ(ierr);
455   PetscFunctionReturn(0);
456 }
457 
458 #undef __FUNCT__
459 #define __FUNCT__ "MatScale_IS"
460 PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
461 {
462   Mat_IS         *is = (Mat_IS*)A->data;
463   PetscErrorCode ierr;
464 
465   PetscFunctionBegin;
466   ierr = MatScale(is->A,a);CHKERRQ(ierr);
467   PetscFunctionReturn(0);
468 }
469 
470 #undef __FUNCT__
471 #define __FUNCT__ "MatGetDiagonal_IS"
472 PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
473 {
474   Mat_IS         *is = (Mat_IS*)A->data;
475   PetscErrorCode ierr;
476 
477   PetscFunctionBegin;
478   /* get diagonal of the local matrix */
479   ierr = MatGetDiagonal(is->A,is->x);CHKERRQ(ierr);
480 
481   /* scatter diagonal back into global vector */
482   ierr = VecSet(v,0);CHKERRQ(ierr);
483   ierr = VecScatterBegin(is->ctx,is->x,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
484   ierr = VecScatterEnd  (is->ctx,is->x,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
485   PetscFunctionReturn(0);
486 }
487 
488 #undef __FUNCT__
489 #define __FUNCT__ "MatSetOption_IS"
490 PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
491 {
492   Mat_IS         *a = (Mat_IS*)A->data;
493   PetscErrorCode ierr;
494 
495   PetscFunctionBegin;
496   ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr);
497   PetscFunctionReturn(0);
498 }
499 
500 #undef __FUNCT__
501 #define __FUNCT__ "MatCreateIS"
502 /*@
503     MatCreateIS - Creates a "process" unassmembled matrix, it is assembled on each
504        process but not across processes.
505 
506    Input Parameters:
507 +     comm - MPI communicator that will share the matrix
508 .     bs - local and global block size of the matrix
509 .     m,n,M,N - local and/or global sizes of the the left and right vector used in matrix vector products
510 -     map - mapping that defines the global number for each local number
511 
512    Output Parameter:
513 .    A - the resulting matrix
514 
515    Level: advanced
516 
517    Notes: See MATIS for more details
518           m and n are NOT related to the size of the map, they are the size of the part of the vector owned
519           by that process. m + nghosts (or n + nghosts) is the length of map since map maps all local points
520           plus the ghost points to global indices.
521 
522 .seealso: MATIS, MatSetLocalToGlobalMapping()
523 @*/
524 PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping map,Mat *A)
525 {
526   PetscErrorCode ierr;
527 
528   PetscFunctionBegin;
529   ierr = MatCreate(comm,A);CHKERRQ(ierr);
530   ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr);
531   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
532   ierr = MatSetType(*A,MATIS);CHKERRQ(ierr);
533   ierr = MatSetUp(*A);CHKERRQ(ierr);
534   ierr = MatSetLocalToGlobalMapping(*A,map,map);CHKERRQ(ierr);
535   PetscFunctionReturn(0);
536 }
537 
538 /*MC
539    MATIS - MATIS = "is" - A matrix type to be used for using the Neumann-Neumann type preconditioners.
540    This stores the matrices in globally unassembled form. Each processor
541    assembles only its local Neumann problem and the parallel matrix vector
542    product is handled "implicitly".
543 
544    Operations Provided:
545 +  MatMult()
546 .  MatMultAdd()
547 .  MatMultTranspose()
548 .  MatMultTransposeAdd()
549 .  MatZeroEntries()
550 .  MatSetOption()
551 .  MatZeroRows()
552 .  MatZeroRowsLocal()
553 .  MatSetValues()
554 .  MatSetValuesLocal()
555 .  MatScale()
556 .  MatGetDiagonal()
557 -  MatSetLocalToGlobalMapping()
558 
559    Options Database Keys:
560 . -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
561 
562    Notes: Options prefix for the inner matrix are given by -is_mat_xxx
563 
564           You must call MatSetLocalToGlobalMapping() before using this matrix type.
565 
566           You can do matrix preallocation on the local matrix after you obtain it with
567           MatISGetLocalMat()
568 
569   Level: advanced
570 
571 .seealso: PC, MatISGetLocalMat(), MatSetLocalToGlobalMapping()
572 
573 M*/
574 
575 #undef __FUNCT__
576 #define __FUNCT__ "MatCreate_IS"
577 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
578 {
579   PetscErrorCode ierr;
580   Mat_IS         *b;
581 
582   PetscFunctionBegin;
583   ierr    = PetscNewLog(A,Mat_IS,&b);CHKERRQ(ierr);
584   A->data = (void*)b;
585   ierr    = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
586 
587   A->ops->mult                    = MatMult_IS;
588   A->ops->multadd                 = MatMultAdd_IS;
589   A->ops->multtranspose           = MatMultTranspose_IS;
590   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
591   A->ops->destroy                 = MatDestroy_IS;
592   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
593   A->ops->setvalues               = MatSetValues_IS;
594   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
595   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
596   A->ops->zerorows                = MatZeroRows_IS;
597   A->ops->zerorowslocal           = MatZeroRowsLocal_IS;
598   A->ops->assemblybegin           = MatAssemblyBegin_IS;
599   A->ops->assemblyend             = MatAssemblyEnd_IS;
600   A->ops->view                    = MatView_IS;
601   A->ops->zeroentries             = MatZeroEntries_IS;
602   A->ops->scale                   = MatScale_IS;
603   A->ops->getdiagonal             = MatGetDiagonal_IS;
604   A->ops->setoption               = MatSetOption_IS;
605   A->ops->ishermitian             = MatIsHermitian_IS;
606   A->ops->issymmetric             = MatIsSymmetric_IS;
607 
608   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
609   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
610 
611   b->A   = 0;
612   b->ctx = 0;
613   b->x   = 0;
614   b->y   = 0;
615   ierr   = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr);
616   ierr   = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr);
617   ierr   = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr);
618   PetscFunctionReturn(0);
619 }
620