xref: /petsc/src/mat/impls/shell/shell.c (revision fa54792ac089a1752bc35d94f1b655469e1f7f8e)
1 
2 /*
3    This provides a simple shell for Fortran (and C programmers) to
4   create a very simple matrix class for use with KSP without coding
5   much of anything.
6 */
7 
8 #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
9 #include <petsc/private/vecimpl.h>
10 
11 struct _MatShellOps {
12   /*  3 */ PetscErrorCode (*mult)(Mat,Vec,Vec);
13   /*  5 */ PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
14   /* 17 */ PetscErrorCode (*getdiagonal)(Mat,Vec);
15   /* 43 */ PetscErrorCode (*copy)(Mat,Mat,MatStructure);
16   /* 60 */ PetscErrorCode (*destroy)(Mat);
17 };
18 
19 typedef struct {
20   struct _MatShellOps ops[1];
21 
22   PetscScalar vscale,vshift;
23   Vec         dshift;
24   Vec         left,right;
25   Vec         left_work,right_work;
26   Vec         left_add_work,right_add_work;
27   Mat         axpy;
28   PetscScalar axpy_vscale;
29   PetscBool   managescalingshifts;                   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
30   /* support for ZeroRows/Columns operations */
31   IS          zrows;
32   IS          zcols;
33   Vec         zvals;
34   Vec         zvals_w;
35   VecScatter  zvals_sct_r;
36   VecScatter  zvals_sct_c;
37   void        *ctx;
38 } Mat_Shell;
39 
40 
41 /*
42      Store and scale values on zeroed rows
43      xx = [x_1, 0], 0 on zeroed columns
44 */
45 static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx)
46 {
47   Mat_Shell      *shell = (Mat_Shell*)A->data;
48   PetscErrorCode ierr;
49 
50   PetscFunctionBegin;
51   *xx = x;
52   if (shell->zrows) {
53     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
54     ierr = VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
55     ierr = VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
56     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
57   }
58   if (shell->zcols) {
59     if (!shell->right_work) {
60       ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);
61     }
62     ierr = VecCopy(x,shell->right_work);CHKERRQ(ierr);
63     ierr = VecISSet(shell->right_work,shell->zcols,0.0);CHKERRQ(ierr);
64     *xx  = shell->right_work;
65   }
66   PetscFunctionReturn(0);
67 }
68 
69 /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
70 static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x)
71 {
72   Mat_Shell      *shell = (Mat_Shell*)A->data;
73   PetscErrorCode ierr;
74 
75   PetscFunctionBegin;
76   if (shell->zrows) {
77     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
78     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
79   }
80   PetscFunctionReturn(0);
81 }
82 
83 /*
84      Store and scale values on zeroed rows
85      xx = [x_1, 0], 0 on zeroed rows
86 */
87 static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx)
88 {
89   Mat_Shell      *shell = (Mat_Shell*)A->data;
90   PetscErrorCode ierr;
91 
92   PetscFunctionBegin;
93   *xx = NULL;
94   if (!shell->zrows) {
95     *xx = x;
96   } else {
97     if (!shell->left_work) {
98       ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);
99     }
100     ierr = VecCopy(x,shell->left_work);CHKERRQ(ierr);
101     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
102     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
103     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
104     ierr = VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
105     ierr = VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
106     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
107     *xx  = shell->left_work;
108   }
109   PetscFunctionReturn(0);
110 }
111 
112 /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
113 static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x)
114 {
115   Mat_Shell      *shell = (Mat_Shell*)A->data;
116   PetscErrorCode ierr;
117 
118   PetscFunctionBegin;
119   if (shell->zcols) {
120     ierr = VecISSet(x,shell->zcols,0.0);CHKERRQ(ierr);
121   }
122   if (shell->zrows) {
123     ierr = VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
124     ierr = VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 /*
130       xx = diag(left)*x
131 */
132 static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
133 {
134   Mat_Shell      *shell = (Mat_Shell*)A->data;
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   *xx = NULL;
139   if (!shell->left) {
140     *xx = x;
141   } else {
142     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
143     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
144     *xx  = shell->left_work;
145   }
146   PetscFunctionReturn(0);
147 }
148 
149 /*
150      xx = diag(right)*x
151 */
152 static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
153 {
154   Mat_Shell      *shell = (Mat_Shell*)A->data;
155   PetscErrorCode ierr;
156 
157   PetscFunctionBegin;
158   *xx = NULL;
159   if (!shell->right) {
160     *xx = x;
161   } else {
162     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
163     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
164     *xx  = shell->right_work;
165   }
166   PetscFunctionReturn(0);
167 }
168 
169 /*
170     x = diag(left)*x
171 */
172 static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
173 {
174   Mat_Shell      *shell = (Mat_Shell*)A->data;
175   PetscErrorCode ierr;
176 
177   PetscFunctionBegin;
178   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
179   PetscFunctionReturn(0);
180 }
181 
182 /*
183     x = diag(right)*x
184 */
185 static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
186 {
187   Mat_Shell      *shell = (Mat_Shell*)A->data;
188   PetscErrorCode ierr;
189 
190   PetscFunctionBegin;
191   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
192   PetscFunctionReturn(0);
193 }
194 
195 /*
196          Y = vscale*Y + diag(dshift)*X + vshift*X
197 
198          On input Y already contains A*x
199 */
200 static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
201 {
202   Mat_Shell      *shell = (Mat_Shell*)A->data;
203   PetscErrorCode ierr;
204 
205   PetscFunctionBegin;
206   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
207     PetscInt          i,m;
208     const PetscScalar *x,*d;
209     PetscScalar       *y;
210     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
211     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
212     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
213     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
214     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
215     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
216     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
217     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
218   } else {
219     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
220   }
221   if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */
222   PetscFunctionReturn(0);
223 }
224 
225 /*@
226     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
227 
228     Not Collective
229 
230     Input Parameter:
231 .   mat - the matrix, should have been created with MatCreateShell()
232 
233     Output Parameter:
234 .   ctx - the user provided context
235 
236     Level: advanced
237 
238    Fortran Notes:
239     To use this from Fortran you must write a Fortran interface definition for this
240     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
241 
242 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
243 @*/
244 PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
245 {
246   PetscErrorCode ierr;
247   PetscBool      flg;
248 
249   PetscFunctionBegin;
250   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
251   PetscValidPointer(ctx,2);
252   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
253   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
254   else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
255   PetscFunctionReturn(0);
256 }
257 
258 static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)
259 {
260   PetscErrorCode ierr;
261   Mat_Shell      *shell = (Mat_Shell*)mat->data;
262   Vec            x = NULL,b = NULL;
263   IS             is1, is2;
264   const PetscInt *ridxs;
265   PetscInt       *idxs,*gidxs;
266   PetscInt       cum,rst,cst,i;
267 
268   PetscFunctionBegin;
269   if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation");
270   if (!shell->zvals) {
271     ierr = MatCreateVecs(mat,NULL,&shell->zvals);CHKERRQ(ierr);
272   }
273   if (!shell->zvals_w) {
274     ierr = VecDuplicate(shell->zvals,&shell->zvals_w);CHKERRQ(ierr);
275   }
276   ierr = MatGetOwnershipRange(mat,&rst,NULL);CHKERRQ(ierr);
277   ierr = MatGetOwnershipRangeColumn(mat,&cst,NULL);CHKERRQ(ierr);
278 
279   /* Expand/create index set of zeroed rows */
280   ierr = PetscMalloc1(nr,&idxs);CHKERRQ(ierr);
281   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
282   ierr = ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
283   ierr = ISSort(is1);CHKERRQ(ierr);
284   ierr = VecISSet(shell->zvals,is1,diag);CHKERRQ(ierr);
285   if (shell->zrows) {
286     ierr = ISSum(shell->zrows,is1,&is2);CHKERRQ(ierr);
287     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
288     ierr = ISDestroy(&is1);CHKERRQ(ierr);
289     shell->zrows = is2;
290   } else shell->zrows = is1;
291 
292   /* Create scatters for diagonal values communications */
293   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
294   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
295 
296   /* row scatter: from/to left vector */
297   ierr = MatCreateVecs(mat,&x,&b);CHKERRQ(ierr);
298   ierr = VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r);CHKERRQ(ierr);
299 
300   /* col scatter: from right vector to left vector */
301   ierr = ISGetIndices(shell->zrows,&ridxs);CHKERRQ(ierr);
302   ierr = ISGetLocalSize(shell->zrows,&nr);CHKERRQ(ierr);
303   ierr = PetscMalloc1(nr,&gidxs);CHKERRQ(ierr);
304   for (i = 0, cum  = 0; i < nr; i++) {
305     if (ridxs[i] >= mat->cmap->N) continue;
306     gidxs[cum] = ridxs[i];
307     cum++;
308   }
309   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
310   ierr = VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c);CHKERRQ(ierr);
311   ierr = ISDestroy(&is1);CHKERRQ(ierr);
312   ierr = VecDestroy(&x);CHKERRQ(ierr);
313   ierr = VecDestroy(&b);CHKERRQ(ierr);
314 
315   /* Expand/create index set of zeroed columns */
316   if (rc) {
317     ierr = PetscMalloc1(nc,&idxs);CHKERRQ(ierr);
318     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
319     ierr = ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
320     ierr = ISSort(is1);CHKERRQ(ierr);
321     if (shell->zcols) {
322       ierr = ISSum(shell->zcols,is1,&is2);CHKERRQ(ierr);
323       ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
324       ierr = ISDestroy(&is1);CHKERRQ(ierr);
325       shell->zcols = is2;
326     } else shell->zcols = is1;
327   }
328   PetscFunctionReturn(0);
329 }
330 
331 static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
332 {
333   PetscInt       nr, *lrows;
334   PetscErrorCode ierr;
335 
336   PetscFunctionBegin;
337   if (x && b) {
338     Vec          xt;
339     PetscScalar *vals;
340     PetscInt    *gcols,i,st,nl,nc;
341 
342     ierr = PetscMalloc1(n,&gcols);CHKERRQ(ierr);
343     for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
344 
345     ierr = MatCreateVecs(mat,&xt,NULL);CHKERRQ(ierr);
346     ierr = VecCopy(x,xt);CHKERRQ(ierr);
347     ierr = PetscCalloc1(nc,&vals);CHKERRQ(ierr);
348     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
349     ierr = PetscFree(vals);CHKERRQ(ierr);
350     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
351     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
352     ierr = VecAYPX(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, x2] */
353 
354     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
355     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
356     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
357     for (i = 0; i < nl; i++) {
358       PetscInt g = i + st;
359       if (g > mat->rmap->N) continue;
360       if (PetscAbsScalar(vals[i]) == 0.0) continue;
361       ierr = VecSetValue(b,g,diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
362     }
363     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
364     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
365     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1, x2 * diag] */
366     ierr = VecDestroy(&xt);CHKERRQ(ierr);
367     ierr = PetscFree(gcols);CHKERRQ(ierr);
368   }
369   ierr = PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL);CHKERRQ(ierr);
370   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE);CHKERRQ(ierr);
371   ierr = PetscFree(lrows);CHKERRQ(ierr);
372   PetscFunctionReturn(0);
373 }
374 
375 static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)
376 {
377   PetscInt       *lrows, *lcols;
378   PetscInt       nr, nc;
379   PetscBool      congruent;
380   PetscErrorCode ierr;
381 
382   PetscFunctionBegin;
383   if (x && b) {
384     Vec          xt, bt;
385     PetscScalar *vals;
386     PetscInt    *grows,*gcols,i,st,nl;
387 
388     ierr = PetscMalloc2(n,&grows,n,&gcols);CHKERRQ(ierr);
389     for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
390     for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
391     ierr = PetscCalloc1(n,&vals);CHKERRQ(ierr);
392 
393     ierr = MatCreateVecs(mat,&xt,&bt);CHKERRQ(ierr);
394     ierr = VecCopy(x,xt);CHKERRQ(ierr);
395     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
396     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
397     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
398     ierr = VecAXPY(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, -x2] */
399     ierr = MatMult(mat,xt,bt);CHKERRQ(ierr);                           /* bt = [-A12*x2,-A22*x2] */
400     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* bt = [-A12*x2,0] */
401     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
402     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
403     ierr = VecAXPY(b,1.0,bt);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, b2] */
404     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* b  = [b1 - A12*x2, 0] */
405     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
406     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
407     ierr = PetscFree(vals);CHKERRQ(ierr);
408 
409     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
410     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
411     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
412     for (i = 0; i < nl; i++) {
413       PetscInt g = i + st;
414       if (g > mat->rmap->N) continue;
415       if (PetscAbsScalar(vals[i]) == 0.0) continue;
416       ierr = VecSetValue(b,g,-diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
417     }
418     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
419     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
420     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, x2 * diag] */
421     ierr = VecDestroy(&xt);CHKERRQ(ierr);
422     ierr = VecDestroy(&bt);CHKERRQ(ierr);
423     ierr = PetscFree2(grows,gcols);CHKERRQ(ierr);
424   }
425   ierr = PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL);CHKERRQ(ierr);
426   ierr = MatHasCongruentLayouts(mat,&congruent);CHKERRQ(ierr);
427   if (congruent) {
428     nc    = nr;
429     lcols = lrows;
430   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
431     PetscInt i,nt,*t;
432 
433     ierr = PetscMalloc1(n,&t);CHKERRQ(ierr);
434     for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
435     ierr = PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL);CHKERRQ(ierr);
436     ierr = PetscFree(t);CHKERRQ(ierr);
437   }
438   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE);CHKERRQ(ierr);
439   if (!congruent) {
440     ierr = PetscFree(lcols);CHKERRQ(ierr);
441   }
442   ierr = PetscFree(lrows);CHKERRQ(ierr);
443   PetscFunctionReturn(0);
444 }
445 
446 PetscErrorCode MatDestroy_Shell(Mat mat)
447 {
448   PetscErrorCode ierr;
449   Mat_Shell      *shell = (Mat_Shell*)mat->data;
450 
451   PetscFunctionBegin;
452   if (shell->ops->destroy) {
453     ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr);
454   }
455   ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
456   ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
457   ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
458   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
459   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
460   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
461   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
462   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
463   ierr = VecDestroy(&shell->zvals_w);CHKERRQ(ierr);
464   ierr = VecDestroy(&shell->zvals);CHKERRQ(ierr);
465   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
466   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
467   ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
468   ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
469   ierr = PetscFree(mat->data);CHKERRQ(ierr);
470   PetscFunctionReturn(0);
471 }
472 
473 PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
474 {
475   Mat_Shell       *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
476   PetscErrorCode  ierr;
477   PetscBool       matflg;
478 
479   PetscFunctionBegin;
480   ierr = PetscObjectTypeCompare((PetscObject)B,MATSHELL,&matflg);CHKERRQ(ierr);
481   if (!matflg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_NOTSAMETYPE,"Output matrix must be a MATSHELL");
482 
483   ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
484   ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
485 
486   if (shellA->ops->copy) {
487     ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr);
488   }
489   shellB->vscale = shellA->vscale;
490   shellB->vshift = shellA->vshift;
491   if (shellA->dshift) {
492     if (!shellB->dshift) {
493       ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr);
494     }
495     ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr);
496   } else {
497     ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr);
498   }
499   if (shellA->left) {
500     if (!shellB->left) {
501       ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr);
502     }
503     ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr);
504   } else {
505     ierr = VecDestroy(&shellB->left);CHKERRQ(ierr);
506   }
507   if (shellA->right) {
508     if (!shellB->right) {
509       ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr);
510     }
511     ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr);
512   } else {
513     ierr = VecDestroy(&shellB->right);CHKERRQ(ierr);
514   }
515   ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr);
516   if (shellA->axpy) {
517     ierr                = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr);
518     shellB->axpy        = shellA->axpy;
519     shellB->axpy_vscale = shellA->axpy_vscale;
520   }
521   if (shellA->zrows) {
522     ierr = ISDuplicate(shellA->zrows,&shellB->zrows);CHKERRQ(ierr);
523     if (shellA->zcols) {
524       ierr = ISDuplicate(shellA->zcols,&shellB->zcols);CHKERRQ(ierr);
525     }
526     ierr = VecDuplicate(shellA->zvals,&shellB->zvals);CHKERRQ(ierr);
527     ierr = VecCopy(shellA->zvals,shellB->zvals);CHKERRQ(ierr);
528     ierr = VecDuplicate(shellA->zvals_w,&shellB->zvals_w);CHKERRQ(ierr);
529     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_r);CHKERRQ(ierr);
530     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_c);CHKERRQ(ierr);
531     shellB->zvals_sct_r = shellA->zvals_sct_r;
532     shellB->zvals_sct_c = shellA->zvals_sct_c;
533   }
534   PetscFunctionReturn(0);
535 }
536 
537 PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
538 {
539   PetscErrorCode ierr;
540   void           *ctx;
541 
542   PetscFunctionBegin;
543   ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr);
544   ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr);
545   if (op != MAT_DO_NOT_COPY_VALUES) {
546     ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
547   }
548   PetscFunctionReturn(0);
549 }
550 
551 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
552 {
553   Mat_Shell        *shell = (Mat_Shell*)A->data;
554   PetscErrorCode   ierr;
555   Vec              xx;
556   PetscObjectState instate,outstate;
557 
558   PetscFunctionBegin;
559   if (!shell->ops->mult) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
560   ierr = MatShellPreZeroRight(A,x,&xx);CHKERRQ(ierr);
561   ierr = MatShellPreScaleRight(A,xx,&xx);CHKERRQ(ierr);
562   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
563   ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr);
564   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
565   if (instate == outstate) {
566     /* increase the state of the output vector since the user did not update its state themself as should have been done */
567     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
568   }
569   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
570   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
571   ierr = MatShellPostZeroLeft(A,y);CHKERRQ(ierr);
572 
573   if (shell->axpy) {
574     if (!shell->left_work) {ierr = MatCreateVecs(A,&shell->left_work,NULL);CHKERRQ(ierr);}
575     ierr = MatMult(shell->axpy,x,shell->left_work);CHKERRQ(ierr);
576     ierr = VecAXPY(y,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr);
577   }
578   PetscFunctionReturn(0);
579 }
580 
581 PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
582 {
583   Mat_Shell      *shell = (Mat_Shell*)A->data;
584   PetscErrorCode ierr;
585 
586   PetscFunctionBegin;
587   if (y == z) {
588     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
589     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
590     ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr);
591   } else {
592     ierr = MatMult(A,x,z);CHKERRQ(ierr);
593     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
594   }
595   PetscFunctionReturn(0);
596 }
597 
598 PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
599 {
600   Mat_Shell        *shell = (Mat_Shell*)A->data;
601   PetscErrorCode   ierr;
602   Vec              xx;
603   PetscObjectState instate,outstate;
604 
605   PetscFunctionBegin;
606   ierr = MatShellPreZeroLeft(A,x,&xx);CHKERRQ(ierr);
607   ierr = MatShellPreScaleLeft(A,xx,&xx);CHKERRQ(ierr);
608   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
609   if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
610   ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr);
611   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
612   if (instate == outstate) {
613     /* increase the state of the output vector since the user did not update its state themself as should have been done */
614     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
615   }
616   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
617   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
618   ierr = MatShellPostZeroRight(A,y);CHKERRQ(ierr);
619 
620   if (shell->axpy) {
621     if (!shell->right_work) {ierr = MatCreateVecs(A,NULL,&shell->right_work);CHKERRQ(ierr);}
622     ierr = MatMultTranspose(shell->axpy,x,shell->right_work);CHKERRQ(ierr);
623     ierr = VecAXPY(y,shell->axpy_vscale,shell->right_work);CHKERRQ(ierr);
624   }
625   PetscFunctionReturn(0);
626 }
627 
628 PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
629 {
630   Mat_Shell      *shell = (Mat_Shell*)A->data;
631   PetscErrorCode ierr;
632 
633   PetscFunctionBegin;
634   if (y == z) {
635     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
636     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
637     ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr);
638   } else {
639     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
640     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
641   }
642   PetscFunctionReturn(0);
643 }
644 
645 /*
646           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
647 */
648 PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
649 {
650   Mat_Shell      *shell = (Mat_Shell*)A->data;
651   PetscErrorCode ierr;
652 
653   PetscFunctionBegin;
654   if (shell->ops->getdiagonal) {
655     ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr);
656   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)");
657   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
658   if (shell->dshift) {
659     ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr);
660   }
661   ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
662   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
663   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
664   if (shell->zrows) {
665     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
666     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
667   }
668   if (shell->axpy) {
669     if (!shell->left_work) {ierr = VecDuplicate(v,&shell->left_work);CHKERRQ(ierr);}
670     ierr = MatGetDiagonal(shell->axpy,shell->left_work);CHKERRQ(ierr);
671     ierr = VecAXPY(v,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr);
672   }
673   PetscFunctionReturn(0);
674 }
675 
676 PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
677 {
678   Mat_Shell      *shell = (Mat_Shell*)Y->data;
679   PetscErrorCode ierr;
680 
681   PetscFunctionBegin;
682   if (shell->left || shell->right) {
683     if (!shell->dshift) {
684       ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr);
685       ierr = VecSet(shell->dshift,a);CHKERRQ(ierr);
686     } else {
687       if (shell->left)  {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
688       if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
689       ierr = VecShift(shell->dshift,a);CHKERRQ(ierr);
690     }
691     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
692     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
693   } else shell->vshift += a;
694   if (shell->zrows) {
695     ierr = VecShift(shell->zvals,a);CHKERRQ(ierr);
696   }
697   PetscFunctionReturn(0);
698 }
699 
700 PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
701 {
702   Mat_Shell      *shell = (Mat_Shell*)A->data;
703   PetscErrorCode ierr;
704 
705   PetscFunctionBegin;
706   if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);}
707   if (shell->left || shell->right) {
708     if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);}
709     if (shell->left && shell->right)  {
710       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
711       ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
712     } else if (shell->left) {
713       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
714     } else {
715       ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr);
716     }
717     ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr);
718   } else {
719     ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr);
720   }
721   PetscFunctionReturn(0);
722 }
723 
724 PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
725 {
726   Mat_Shell      *shell = (Mat_Shell*)A->data;
727   Vec            d;
728   PetscErrorCode ierr;
729 
730   PetscFunctionBegin;
731   if (ins == INSERT_VALUES) {
732     if (!A->ops->getdiagonal) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
733     ierr = VecDuplicate(D,&d);CHKERRQ(ierr);
734     ierr = MatGetDiagonal(A,d);CHKERRQ(ierr);
735     ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr);
736     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
737     ierr = VecDestroy(&d);CHKERRQ(ierr);
738     if (shell->zrows) {
739       ierr = VecCopy(D,shell->zvals);CHKERRQ(ierr);
740     }
741   } else {
742     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
743     if (shell->zrows) {
744       ierr = VecAXPY(shell->zvals,1.0,D);CHKERRQ(ierr);
745     }
746   }
747   PetscFunctionReturn(0);
748 }
749 
750 PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
751 {
752   Mat_Shell      *shell = (Mat_Shell*)Y->data;
753   PetscErrorCode ierr;
754 
755   PetscFunctionBegin;
756   shell->vscale *= a;
757   shell->vshift *= a;
758   if (shell->dshift) {
759     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
760   }
761   shell->axpy_vscale *= a;
762   if (shell->zrows) {
763     ierr = VecScale(shell->zvals,a);CHKERRQ(ierr);
764   }
765   PetscFunctionReturn(0);
766 }
767 
768 static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
769 {
770   Mat_Shell      *shell = (Mat_Shell*)Y->data;
771   PetscErrorCode ierr;
772 
773   PetscFunctionBegin;
774   if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation");
775   if (left) {
776     if (!shell->left) {
777       ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr);
778       ierr = VecCopy(left,shell->left);CHKERRQ(ierr);
779     } else {
780       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
781     }
782     if (shell->zrows) {
783       ierr = VecPointwiseMult(shell->zvals,shell->zvals,left);CHKERRQ(ierr);
784     }
785   }
786   if (right) {
787     if (!shell->right) {
788       ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr);
789       ierr = VecCopy(right,shell->right);CHKERRQ(ierr);
790     } else {
791       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
792     }
793     if (shell->zrows) {
794       if (!shell->left_work) {
795         ierr = MatCreateVecs(Y,NULL,&shell->left_work);CHKERRQ(ierr);
796       }
797       ierr = VecSet(shell->zvals_w,1.0);CHKERRQ(ierr);
798       ierr = VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
799       ierr = VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
800       ierr = VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w);CHKERRQ(ierr);
801     }
802   }
803   PetscFunctionReturn(0);
804 }
805 
806 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
807 {
808   Mat_Shell      *shell = (Mat_Shell*)Y->data;
809   PetscErrorCode ierr;
810 
811   PetscFunctionBegin;
812   if (t == MAT_FINAL_ASSEMBLY) {
813     shell->vshift = 0.0;
814     shell->vscale = 1.0;
815     ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
816     ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
817     ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
818     ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
819     ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
820     ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
821     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
822     ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
823   }
824   PetscFunctionReturn(0);
825 }
826 
827 static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool  *missing,PetscInt *d)
828 {
829   PetscFunctionBegin;
830   *missing = PETSC_FALSE;
831   PetscFunctionReturn(0);
832 }
833 
834 PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
835 {
836   Mat_Shell      *shell = (Mat_Shell*)Y->data;
837   PetscErrorCode ierr;
838 
839   PetscFunctionBegin;
840   ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
841   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
842   shell->axpy        = X;
843   shell->axpy_vscale = a;
844   PetscFunctionReturn(0);
845 }
846 
847 static struct _MatOps MatOps_Values = {0,
848                                        0,
849                                        0,
850                                        0,
851                                 /* 4*/ MatMultAdd_Shell,
852                                        0,
853                                        MatMultTransposeAdd_Shell,
854                                        0,
855                                        0,
856                                        0,
857                                 /*10*/ 0,
858                                        0,
859                                        0,
860                                        0,
861                                        0,
862                                 /*15*/ 0,
863                                        0,
864                                        0,
865                                        MatDiagonalScale_Shell,
866                                        0,
867                                 /*20*/ 0,
868                                        MatAssemblyEnd_Shell,
869                                        0,
870                                        0,
871                                 /*24*/ MatZeroRows_Shell,
872                                        0,
873                                        0,
874                                        0,
875                                        0,
876                                 /*29*/ 0,
877                                        0,
878                                        0,
879                                        0,
880                                        0,
881                                 /*34*/ MatDuplicate_Shell,
882                                        0,
883                                        0,
884                                        0,
885                                        0,
886                                 /*39*/ MatAXPY_Shell,
887                                        0,
888                                        0,
889                                        0,
890                                        MatCopy_Shell,
891                                 /*44*/ 0,
892                                        MatScale_Shell,
893                                        MatShift_Shell,
894                                        MatDiagonalSet_Shell,
895                                        MatZeroRowsColumns_Shell,
896                                 /*49*/ 0,
897                                        0,
898                                        0,
899                                        0,
900                                        0,
901                                 /*54*/ 0,
902                                        0,
903                                        0,
904                                        0,
905                                        0,
906                                 /*59*/ 0,
907                                        MatDestroy_Shell,
908                                        0,
909                                        MatConvertFrom_Shell,
910                                        0,
911                                 /*64*/ 0,
912                                        0,
913                                        0,
914                                        0,
915                                        0,
916                                 /*69*/ 0,
917                                        0,
918                                        MatConvert_Shell,
919                                        0,
920                                        0,
921                                 /*74*/ 0,
922                                        0,
923                                        0,
924                                        0,
925                                        0,
926                                 /*79*/ 0,
927                                        0,
928                                        0,
929                                        0,
930                                        0,
931                                 /*84*/ 0,
932                                        0,
933                                        0,
934                                        0,
935                                        0,
936                                 /*89*/ 0,
937                                        0,
938                                        0,
939                                        0,
940                                        0,
941                                 /*94*/ 0,
942                                        0,
943                                        0,
944                                        0,
945                                        0,
946                                 /*99*/ 0,
947                                        0,
948                                        0,
949                                        0,
950                                        0,
951                                /*104*/ 0,
952                                        0,
953                                        0,
954                                        0,
955                                        0,
956                                /*109*/ 0,
957                                        0,
958                                        0,
959                                        0,
960                                        MatMissingDiagonal_Shell,
961                                /*114*/ 0,
962                                        0,
963                                        0,
964                                        0,
965                                        0,
966                                /*119*/ 0,
967                                        0,
968                                        0,
969                                        0,
970                                        0,
971                                /*124*/ 0,
972                                        0,
973                                        0,
974                                        0,
975                                        0,
976                                /*129*/ 0,
977                                        0,
978                                        0,
979                                        0,
980                                        0,
981                                /*134*/ 0,
982                                        0,
983                                        0,
984                                        0,
985                                        0,
986                                /*139*/ 0,
987                                        0,
988                                        0
989 };
990 
991 /*MC
992    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
993 
994   Level: advanced
995 
996 .seealso: MatCreateShell()
997 M*/
998 
999 PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1000 {
1001   Mat_Shell      *b;
1002   PetscErrorCode ierr;
1003 
1004   PetscFunctionBegin;
1005   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
1006 
1007   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
1008   A->data = (void*)b;
1009 
1010   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1011   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1012 
1013   b->ctx                 = 0;
1014   b->vshift              = 0.0;
1015   b->vscale              = 1.0;
1016   b->managescalingshifts = PETSC_TRUE;
1017   A->assembled           = PETSC_TRUE;
1018   A->preallocated        = PETSC_FALSE;
1019 
1020   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
1021   PetscFunctionReturn(0);
1022 }
1023 
1024 /*@C
1025    MatCreateShell - Creates a new matrix class for use with a user-defined
1026    private data storage format.
1027 
1028   Collective on MPI_Comm
1029 
1030    Input Parameters:
1031 +  comm - MPI communicator
1032 .  m - number of local rows (must be given)
1033 .  n - number of local columns (must be given)
1034 .  M - number of global rows (may be PETSC_DETERMINE)
1035 .  N - number of global columns (may be PETSC_DETERMINE)
1036 -  ctx - pointer to data needed by the shell matrix routines
1037 
1038    Output Parameter:
1039 .  A - the matrix
1040 
1041    Level: advanced
1042 
1043   Usage:
1044 $    extern int mult(Mat,Vec,Vec);
1045 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
1046 $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1047 $    [ Use matrix for operations that have been set ]
1048 $    MatDestroy(mat);
1049 
1050    Notes:
1051    The shell matrix type is intended to provide a simple class to use
1052    with KSP (such as, for use with matrix-free methods). You should not
1053    use the shell type if you plan to define a complete matrix class.
1054 
1055    Fortran Notes:
1056     To use this from Fortran with a ctx you must write an interface definition for this
1057     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
1058     in as the ctx argument.
1059 
1060    PETSc requires that matrices and vectors being used for certain
1061    operations are partitioned accordingly.  For example, when
1062    creating a shell matrix, A, that supports parallel matrix-vector
1063    products using MatMult(A,x,y) the user should set the number
1064    of local matrix rows to be the number of local elements of the
1065    corresponding result vector, y. Note that this is information is
1066    required for use of the matrix interface routines, even though
1067    the shell matrix may not actually be physically partitioned.
1068    For example,
1069 
1070 $
1071 $     Vec x, y
1072 $     extern int mult(Mat,Vec,Vec);
1073 $     Mat A
1074 $
1075 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1076 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1077 $     VecGetLocalSize(y,&m);
1078 $     VecGetLocalSize(x,&n);
1079 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
1080 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1081 $     MatMult(A,x,y);
1082 $     MatDestroy(&A);
1083 $     VecDestroy(&y);
1084 $     VecDestroy(&x);
1085 $
1086 
1087 
1088    MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these
1089    operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
1090 
1091 
1092     For rectangular matrices do all the scalings and shifts make sense?
1093 
1094     Developers Notes:
1095     Regarding shifting and scaling. The general form is
1096 
1097           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
1098 
1099       The order you apply the operations is important. For example if you have a dshift then
1100       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
1101       you get s*vscale*A + diag(shift)
1102 
1103           A is the user provided function.
1104 
1105    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
1106    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
1107    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
1108    each time the MATSHELL matrix has changed.
1109 
1110    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
1111    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
1112 
1113 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts()
1114 @*/
1115 PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
1116 {
1117   PetscErrorCode ierr;
1118 
1119   PetscFunctionBegin;
1120   ierr = MatCreate(comm,A);CHKERRQ(ierr);
1121   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
1122   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
1123   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
1124   ierr = MatSetUp(*A);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 /*@
1129     MatShellSetContext - sets the context for a shell matrix
1130 
1131    Logically Collective on Mat
1132 
1133     Input Parameters:
1134 +   mat - the shell matrix
1135 -   ctx - the context
1136 
1137    Level: advanced
1138 
1139    Fortran Notes:
1140     To use this from Fortran you must write a Fortran interface definition for this
1141     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1142 
1143 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
1144 @*/
1145 PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
1146 {
1147   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1148   PetscErrorCode ierr;
1149   PetscBool      flg;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1153   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1154   if (flg) {
1155     shell->ctx = ctx;
1156   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
1157   PetscFunctionReturn(0);
1158 }
1159 
1160 /*@
1161     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
1162           after MatCreateShell()
1163 
1164    Logically Collective on Mat
1165 
1166     Input Parameter:
1167 .   mat - the shell matrix
1168 
1169   Level: advanced
1170 
1171 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation()
1172 @*/
1173 PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1174 {
1175   PetscErrorCode ierr;
1176   Mat_Shell      *shell;
1177   PetscBool      flg;
1178 
1179   PetscFunctionBegin;
1180   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1181   ierr = PetscObjectTypeCompare((PetscObject)A,MATSHELL,&flg);CHKERRQ(ierr);
1182   if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
1183   shell = (Mat_Shell*)A->data;
1184   shell->managescalingshifts = PETSC_FALSE;
1185   A->ops->diagonalset   = NULL;
1186   A->ops->diagonalscale = NULL;
1187   A->ops->scale         = NULL;
1188   A->ops->shift         = NULL;
1189   A->ops->axpy          = NULL;
1190   PetscFunctionReturn(0);
1191 }
1192 
1193 /*@C
1194     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
1195 
1196    Logically Collective on Mat
1197 
1198     Input Parameters:
1199 +   mat - the shell matrix
1200 .   f - the function
1201 .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1202 -   ctx - an optional context for the function
1203 
1204    Output Parameter:
1205 .   flg - PETSC_TRUE if the multiply is likely correct
1206 
1207    Options Database:
1208 .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1209 
1210    Level: advanced
1211 
1212    Fortran Notes:
1213     Not supported from Fortran
1214 
1215 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose()
1216 @*/
1217 PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1218 {
1219   PetscErrorCode ierr;
1220   PetscInt       m,n;
1221   Mat            mf,Dmf,Dmat,Ddiff;
1222   PetscReal      Diffnorm,Dmfnorm;
1223   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1224 
1225   PetscFunctionBegin;
1226   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1227   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr);
1228   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
1229   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr);
1230   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
1231   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
1232 
1233   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
1234   ierr = MatComputeOperator(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
1235 
1236   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
1237   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1238   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
1239   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
1240   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1241     flag = PETSC_FALSE;
1242     if (v) {
1243       ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm));CHKERRQ(ierr);
1244       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1245       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1246       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1247     }
1248   } else if (v) {
1249     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
1250   }
1251   if (flg) *flg = flag;
1252   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
1253   ierr = MatDestroy(&mf);CHKERRQ(ierr);
1254   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
1255   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
1256   PetscFunctionReturn(0);
1257 }
1258 
1259 /*@C
1260     MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
1261 
1262    Logically Collective on Mat
1263 
1264     Input Parameters:
1265 +   mat - the shell matrix
1266 .   f - the function
1267 .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1268 -   ctx - an optional context for the function
1269 
1270    Output Parameter:
1271 .   flg - PETSC_TRUE if the multiply is likely correct
1272 
1273    Options Database:
1274 .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1275 
1276    Level: advanced
1277 
1278    Fortran Notes:
1279     Not supported from Fortran
1280 
1281 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult()
1282 @*/
1283 PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1284 {
1285   PetscErrorCode ierr;
1286   Vec            x,y,z;
1287   PetscInt       m,n,M,N;
1288   Mat            mf,Dmf,Dmat,Ddiff;
1289   PetscReal      Diffnorm,Dmfnorm;
1290   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1291 
1292   PetscFunctionBegin;
1293   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1294   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr);
1295   ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr);
1296   ierr = VecDuplicate(y,&z);CHKERRQ(ierr);
1297   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
1298   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
1299   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr);
1300   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
1301   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
1302   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
1303   ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr);
1304   ierr = MatComputeOperatorTranspose(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
1305 
1306   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
1307   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1308   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
1309   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
1310   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1311     flag = PETSC_FALSE;
1312     if (v) {
1313       ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm));CHKERRQ(ierr);
1314       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
1315       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
1316       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
1317     }
1318   } else if (v) {
1319     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
1320   }
1321   if (flg) *flg = flag;
1322   ierr = MatDestroy(&mf);CHKERRQ(ierr);
1323   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
1324   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
1325   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
1326   ierr = VecDestroy(&x);CHKERRQ(ierr);
1327   ierr = VecDestroy(&y);CHKERRQ(ierr);
1328   ierr = VecDestroy(&z);CHKERRQ(ierr);
1329   PetscFunctionReturn(0);
1330 }
1331 
1332 /*@C
1333     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
1334 
1335    Logically Collective on Mat
1336 
1337     Input Parameters:
1338 +   mat - the shell matrix
1339 .   op - the name of the operation
1340 -   f - the function that provides the operation.
1341 
1342    Level: advanced
1343 
1344     Usage:
1345 $      extern PetscErrorCode usermult(Mat,Vec,Vec);
1346 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
1347 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
1348 
1349     Notes:
1350     See the file include/petscmat.h for a complete list of matrix
1351     operations, which all have the form MATOP_<OPERATION>, where
1352     <OPERATION> is the name (in all capital letters) of the
1353     user interface routine (e.g., MatMult() -> MATOP_MULT).
1354 
1355     All user-provided functions (except for MATOP_DESTROY) should have the same calling
1356     sequence as the usual matrix interface routines, since they
1357     are intended to be accessed via the usual matrix interface
1358     routines, e.g.,
1359 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1360 
1361     In particular each function MUST return an error code of 0 on success and
1362     nonzero on failure.
1363 
1364     Within each user-defined routine, the user should call
1365     MatShellGetContext() to obtain the user-defined context that was
1366     set by MatCreateShell().
1367 
1368     Fortran Notes:
1369     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
1370        generate a matrix. See src/mat/examples/tests/ex120f.F
1371 
1372     Use MatSetOperation() to set an operation for any matrix type
1373 
1374 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts()
1375 @*/
1376 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
1377 {
1378   PetscBool      flg;
1379   Mat_Shell      *shell;
1380   PetscErrorCode ierr;
1381 
1382   PetscFunctionBegin;
1383   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1384   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1385   if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
1386   shell = (Mat_Shell*)mat->data;
1387 
1388   switch (op) {
1389   case MATOP_DESTROY:
1390     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1391     break;
1392   case MATOP_VIEW:
1393     if (!mat->ops->viewnative) {
1394       mat->ops->viewnative = mat->ops->view;
1395     }
1396     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1397     break;
1398   case MATOP_COPY:
1399     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1400     break;
1401   case MATOP_DIAGONAL_SET:
1402   case MATOP_DIAGONAL_SCALE:
1403   case MATOP_SHIFT:
1404   case MATOP_SCALE:
1405   case MATOP_AXPY:
1406   case MATOP_ZERO_ROWS:
1407   case MATOP_ZERO_ROWS_COLUMNS:
1408     if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1409     (((void(**)(void))mat->ops)[op]) = f;
1410     break;
1411   case MATOP_GET_DIAGONAL:
1412     if (shell->managescalingshifts) {
1413       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1414       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1415     } else {
1416       shell->ops->getdiagonal = NULL;
1417       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
1418     }
1419     break;
1420   case MATOP_MULT:
1421     if (shell->managescalingshifts) {
1422       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1423       mat->ops->mult   = MatMult_Shell;
1424     } else {
1425       shell->ops->mult = NULL;
1426       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1427     }
1428     break;
1429   case MATOP_MULT_TRANSPOSE:
1430     if (shell->managescalingshifts) {
1431       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1432       mat->ops->multtranspose   = MatMultTranspose_Shell;
1433     } else {
1434       shell->ops->multtranspose = NULL;
1435       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1436     }
1437     break;
1438   default:
1439     (((void(**)(void))mat->ops)[op]) = f;
1440     break;
1441   }
1442   PetscFunctionReturn(0);
1443 }
1444 
1445 /*@C
1446     MatShellGetOperation - Gets a matrix function for a shell matrix.
1447 
1448     Not Collective
1449 
1450     Input Parameters:
1451 +   mat - the shell matrix
1452 -   op - the name of the operation
1453 
1454     Output Parameter:
1455 .   f - the function that provides the operation.
1456 
1457     Level: advanced
1458 
1459     Notes:
1460     See the file include/petscmat.h for a complete list of matrix
1461     operations, which all have the form MATOP_<OPERATION>, where
1462     <OPERATION> is the name (in all capital letters) of the
1463     user interface routine (e.g., MatMult() -> MATOP_MULT).
1464 
1465     All user-provided functions have the same calling
1466     sequence as the usual matrix interface routines, since they
1467     are intended to be accessed via the usual matrix interface
1468     routines, e.g.,
1469 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1470 
1471     Within each user-defined routine, the user should call
1472     MatShellGetContext() to obtain the user-defined context that was
1473     set by MatCreateShell().
1474 
1475 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
1476 @*/
1477 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
1478 {
1479   PetscBool      flg;
1480   Mat_Shell      *shell;
1481   PetscErrorCode ierr;
1482 
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1485   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1486   if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
1487   shell = (Mat_Shell*)mat->data;
1488 
1489   switch (op) {
1490   case MATOP_DESTROY:
1491     *f = (void (*)(void))shell->ops->destroy;
1492     break;
1493   case MATOP_VIEW:
1494     *f = (void (*)(void))mat->ops->view;
1495     break;
1496   case MATOP_COPY:
1497     *f = (void (*)(void))shell->ops->copy;
1498     break;
1499   case MATOP_DIAGONAL_SET:
1500   case MATOP_DIAGONAL_SCALE:
1501   case MATOP_SHIFT:
1502   case MATOP_SCALE:
1503   case MATOP_AXPY:
1504   case MATOP_ZERO_ROWS:
1505   case MATOP_ZERO_ROWS_COLUMNS:
1506     *f = (((void (**)(void))mat->ops)[op]);
1507     break;
1508   case MATOP_GET_DIAGONAL:
1509     if (shell->ops->getdiagonal)
1510       *f = (void (*)(void))shell->ops->getdiagonal;
1511     else
1512       *f = (((void (**)(void))mat->ops)[op]);
1513     break;
1514   case MATOP_MULT:
1515     if (shell->ops->mult)
1516       *f = (void (*)(void))shell->ops->mult;
1517     else
1518       *f = (((void (**)(void))mat->ops)[op]);
1519     break;
1520   case MATOP_MULT_TRANSPOSE:
1521     if (shell->ops->multtranspose)
1522       *f = (void (*)(void))shell->ops->multtranspose;
1523     else
1524       *f = (((void (**)(void))mat->ops)[op]);
1525     break;
1526   default:
1527     *f = (((void (**)(void))mat->ops)[op]);
1528   }
1529   PetscFunctionReturn(0);
1530 }
1531