xref: /petsc/src/mat/impls/shell/shell.c (revision 2205254efee3a00a594e5e2a3a70f74dcb40bc03)
1be1d678aSKris Buschelman 
2e51e0e81SBarry Smith /*
320563c6bSBarry Smith    This provides a simple shell for Fortran (and C programmers) to
420563c6bSBarry Smith   create a very simple matrix class for use with KSP without coding
5ed3cc1f0SBarry Smith   much of anything.
6e51e0e81SBarry Smith */
7e51e0e81SBarry Smith 
8b45d2f2cSJed Brown #include <petsc-private/matimpl.h>        /*I "petscmat.h" I*/
9b45d2f2cSJed Brown #include <petsc-private/vecimpl.h>
10e51e0e81SBarry Smith 
1120563c6bSBarry Smith typedef struct {
126849ba73SBarry Smith   PetscErrorCode (*destroy)(Mat);
136849ba73SBarry Smith   PetscErrorCode (*mult)(Mat,Vec,Vec);
1418be62a5SSatish Balay   PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
1518be62a5SSatish Balay   PetscErrorCode (*getdiagonal)(Mat,Vec);
16*2205254eSKarl Rupp 
17ef66eb69SBarry Smith   PetscScalar vscale,vshift;
188fe8eb27SJed Brown   Vec         dshift;
198fe8eb27SJed Brown   Vec         left,right;
208fe8eb27SJed Brown   Vec         dshift_owned,left_owned,right_owned;
218fe8eb27SJed Brown   Vec         left_work,right_work;
225edf6516SJed Brown   Vec         left_add_work,right_add_work;
238fe8eb27SJed Brown   PetscBool   usingscaled;
2420563c6bSBarry Smith   void        *ctx;
2588cf3e7dSBarry Smith } Mat_Shell;
268fe8eb27SJed Brown /*
278fe8eb27SJed Brown  The most general expression for the matrix is
288fe8eb27SJed Brown 
298fe8eb27SJed Brown  S = L (a A + B) R
308fe8eb27SJed Brown 
318fe8eb27SJed Brown  where
328fe8eb27SJed Brown  A is the matrix defined by the user's function
338fe8eb27SJed Brown  a is a scalar multiple
348fe8eb27SJed Brown  L is left scaling
358fe8eb27SJed Brown  R is right scaling
368fe8eb27SJed Brown  B is a diagonal shift defined by
378fe8eb27SJed Brown    diag(dshift) if the vector dshift is non-NULL
388fe8eb27SJed Brown    vscale*identity otherwise
398fe8eb27SJed Brown 
408fe8eb27SJed Brown  The following identities apply:
418fe8eb27SJed Brown 
428fe8eb27SJed Brown  Scale by c:
438fe8eb27SJed Brown   c [L (a A + B) R] = L [(a c) A + c B] R
448fe8eb27SJed Brown 
458fe8eb27SJed Brown  Shift by c:
468fe8eb27SJed Brown   [L (a A + B) R] + c = L [a A + (B + c Linv Rinv)] R
478fe8eb27SJed Brown 
488fe8eb27SJed Brown  Diagonal scaling is achieved by simply multiplying with existing L and R vectors
498fe8eb27SJed Brown 
508fe8eb27SJed Brown  In the data structure:
518fe8eb27SJed Brown 
528fe8eb27SJed Brown  vscale=1.0  means no special scaling will be applied
538fe8eb27SJed Brown  dshift=NULL means a constant diagonal shift (fall back to vshift)
548fe8eb27SJed Brown  vshift=0.0  means no constant diagonal shift, note that vshift is only used if dshift is NULL
558fe8eb27SJed Brown */
568fe8eb27SJed Brown 
578fe8eb27SJed Brown static PetscErrorCode MatMult_Shell(Mat,Vec,Vec);
588fe8eb27SJed Brown static PetscErrorCode MatMultTranspose_Shell(Mat,Vec,Vec);
598fe8eb27SJed Brown static PetscErrorCode MatGetDiagonal_Shell(Mat,Vec);
608fe8eb27SJed Brown 
618fe8eb27SJed Brown #undef __FUNCT__
628fe8eb27SJed Brown #define __FUNCT__ "MatShellUseScaledMethods"
638fe8eb27SJed Brown static PetscErrorCode MatShellUseScaledMethods(Mat Y)
648fe8eb27SJed Brown {
658fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)Y->data;
668fe8eb27SJed Brown 
678fe8eb27SJed Brown   PetscFunctionBegin;
688fe8eb27SJed Brown   if (shell->usingscaled) PetscFunctionReturn(0);
698fe8eb27SJed Brown   shell->mult  = Y->ops->mult;
708fe8eb27SJed Brown   Y->ops->mult = MatMult_Shell;
718fe8eb27SJed Brown   if (Y->ops->multtranspose) {
728fe8eb27SJed Brown     shell->multtranspose  = Y->ops->multtranspose;
738fe8eb27SJed Brown     Y->ops->multtranspose = MatMultTranspose_Shell;
748fe8eb27SJed Brown   }
758fe8eb27SJed Brown   if (Y->ops->getdiagonal) {
768fe8eb27SJed Brown     shell->getdiagonal  = Y->ops->getdiagonal;
778fe8eb27SJed Brown     Y->ops->getdiagonal = MatGetDiagonal_Shell;
788fe8eb27SJed Brown   }
798fe8eb27SJed Brown   shell->usingscaled = PETSC_TRUE;
808fe8eb27SJed Brown   PetscFunctionReturn(0);
818fe8eb27SJed Brown }
828fe8eb27SJed Brown 
838fe8eb27SJed Brown #undef __FUNCT__
848fe8eb27SJed Brown #define __FUNCT__ "MatShellPreScaleLeft"
858fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
868fe8eb27SJed Brown {
878fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
888fe8eb27SJed Brown   PetscErrorCode ierr;
898fe8eb27SJed Brown 
908fe8eb27SJed Brown   PetscFunctionBegin;
91d63f877fSJed Brown   *xx = PETSC_NULL;
928fe8eb27SJed Brown   if (!shell->left) {
938fe8eb27SJed Brown     *xx = x;
948fe8eb27SJed Brown   } else {
958fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
968fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
978fe8eb27SJed Brown     *xx  = shell->left_work;
988fe8eb27SJed Brown   }
998fe8eb27SJed Brown   PetscFunctionReturn(0);
1008fe8eb27SJed Brown }
1018fe8eb27SJed Brown 
1028fe8eb27SJed Brown #undef __FUNCT__
1038fe8eb27SJed Brown #define __FUNCT__ "MatShellPreScaleRight"
1048fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1058fe8eb27SJed Brown {
1068fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1078fe8eb27SJed Brown   PetscErrorCode ierr;
1088fe8eb27SJed Brown 
1098fe8eb27SJed Brown   PetscFunctionBegin;
110d63f877fSJed Brown   *xx = PETSC_NULL;
1118fe8eb27SJed Brown   if (!shell->right) {
1128fe8eb27SJed Brown     *xx = x;
1138fe8eb27SJed Brown   } else {
1148fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
1158fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
1168fe8eb27SJed Brown     *xx  = shell->right_work;
1178fe8eb27SJed Brown   }
1188fe8eb27SJed Brown   PetscFunctionReturn(0);
1198fe8eb27SJed Brown }
1208fe8eb27SJed Brown 
1218fe8eb27SJed Brown #undef __FUNCT__
1228fe8eb27SJed Brown #define __FUNCT__ "MatShellPostScaleLeft"
1238fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1248fe8eb27SJed Brown {
1258fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1268fe8eb27SJed Brown   PetscErrorCode ierr;
1278fe8eb27SJed Brown 
1288fe8eb27SJed Brown   PetscFunctionBegin;
1298fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
1308fe8eb27SJed Brown   PetscFunctionReturn(0);
1318fe8eb27SJed Brown }
1328fe8eb27SJed Brown 
1338fe8eb27SJed Brown #undef __FUNCT__
1348fe8eb27SJed Brown #define __FUNCT__ "MatShellPostScaleRight"
1358fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
1368fe8eb27SJed Brown {
1378fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1388fe8eb27SJed Brown   PetscErrorCode ierr;
1398fe8eb27SJed Brown 
1408fe8eb27SJed Brown   PetscFunctionBegin;
1418fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
1428fe8eb27SJed Brown   PetscFunctionReturn(0);
1438fe8eb27SJed Brown }
1448fe8eb27SJed Brown 
1458fe8eb27SJed Brown #undef __FUNCT__
1468fe8eb27SJed Brown #define __FUNCT__ "MatShellShiftAndScale"
1478fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
1488fe8eb27SJed Brown {
1498fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1508fe8eb27SJed Brown   PetscErrorCode ierr;
1518fe8eb27SJed Brown 
1528fe8eb27SJed Brown   PetscFunctionBegin;
1538fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
1548fe8eb27SJed Brown     PetscInt          i,m;
1558fe8eb27SJed Brown     const PetscScalar *x,*d;
1568fe8eb27SJed Brown     PetscScalar       *y;
1578fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
1588fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1598fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1608fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
1618fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
1628fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1638fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1648fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
165880538faSHong Zhang   } else if (PetscAbsScalar(shell->vshift) != 0) {
1668fe8eb27SJed Brown     ierr = VecAXPBY(Y,shell->vshift,shell->vscale,X);CHKERRQ(ierr);
167027c5fb5SJed Brown   } else if (shell->vscale != 1.0) {
168027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
1698fe8eb27SJed Brown   }
1708fe8eb27SJed Brown   PetscFunctionReturn(0);
1718fe8eb27SJed Brown }
172e51e0e81SBarry Smith 
173711e205bSSatish Balay #undef __FUNCT__
174711e205bSSatish Balay #define __FUNCT__ "MatShellGetContext"
1759d225801SJed Brown /*@
176a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
177b4fd4287SBarry Smith 
178c7fcc2eaSBarry Smith     Not Collective
179c7fcc2eaSBarry Smith 
180b4fd4287SBarry Smith     Input Parameter:
181b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
182b4fd4287SBarry Smith 
183b4fd4287SBarry Smith     Output Parameter:
184b4fd4287SBarry Smith .   ctx - the user provided context
185b4fd4287SBarry Smith 
18615091d37SBarry Smith     Level: advanced
18715091d37SBarry Smith 
188a62d957aSLois Curfman McInnes     Notes:
189a62d957aSLois Curfman McInnes     This routine is intended for use within various shell matrix routines,
190a62d957aSLois Curfman McInnes     as set with MatShellSetOperation().
191a62d957aSLois Curfman McInnes 
192a62d957aSLois Curfman McInnes .keywords: matrix, shell, get, context
193a62d957aSLois Curfman McInnes 
194ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
1950bc0a719SBarry Smith @*/
1968fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
197b4fd4287SBarry Smith {
198dfbe8321SBarry Smith   PetscErrorCode ierr;
199ace3abfcSBarry Smith   PetscBool      flg;
200273d9f13SBarry Smith 
2013a40ed3dSBarry Smith   PetscFunctionBegin;
2020700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2034482741eSBarry Smith   PetscValidPointer(ctx,2);
204251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
205940183f3SBarry Smith   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
206940183f3SBarry Smith   else SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
2073a40ed3dSBarry Smith   PetscFunctionReturn(0);
208b4fd4287SBarry Smith }
209b4fd4287SBarry Smith 
210711e205bSSatish Balay #undef __FUNCT__
211711e205bSSatish Balay #define __FUNCT__ "MatDestroy_Shell"
212dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
213e51e0e81SBarry Smith {
214dfbe8321SBarry Smith   PetscErrorCode ierr;
215bf0cc555SLisandro Dalcin   Mat_Shell      *shell = (Mat_Shell*)mat->data;
216ed3cc1f0SBarry Smith 
2173a40ed3dSBarry Smith   PetscFunctionBegin;
218bf0cc555SLisandro Dalcin   if (shell->destroy) {
219bf0cc555SLisandro Dalcin     ierr = (*shell->destroy)(mat);CHKERRQ(ierr);
220bf0cc555SLisandro Dalcin   }
2218fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_owned);CHKERRQ(ierr);
2228fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_owned);CHKERRQ(ierr);
2238fe8eb27SJed Brown   ierr = VecDestroy(&shell->dshift_owned);CHKERRQ(ierr);
2248fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
2258fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
2265edf6516SJed Brown   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
2275edf6516SJed Brown   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
228bf0cc555SLisandro Dalcin   ierr = PetscFree(mat->data);CHKERRQ(ierr);
2293a40ed3dSBarry Smith   PetscFunctionReturn(0);
230e51e0e81SBarry Smith }
231e51e0e81SBarry Smith 
232711e205bSSatish Balay #undef __FUNCT__
233ef66eb69SBarry Smith #define __FUNCT__ "MatMult_Shell"
234dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
235ef66eb69SBarry Smith {
236ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
237dfbe8321SBarry Smith   PetscErrorCode ierr;
23825578ef6SJed Brown   Vec            xx;
239ef66eb69SBarry Smith 
240ef66eb69SBarry Smith   PetscFunctionBegin;
2418fe8eb27SJed Brown   ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr);
2428fe8eb27SJed Brown   ierr = (*shell->mult)(A,xx,y);CHKERRQ(ierr);
2438fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
2448fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
245ef66eb69SBarry Smith   PetscFunctionReturn(0);
246ef66eb69SBarry Smith }
247ef66eb69SBarry Smith 
248ef66eb69SBarry Smith #undef __FUNCT__
2495edf6516SJed Brown #define __FUNCT__ "MatMultAdd_Shell"
2505edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
2515edf6516SJed Brown {
2525edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2535edf6516SJed Brown   PetscErrorCode ierr;
2545edf6516SJed Brown 
2555edf6516SJed Brown   PetscFunctionBegin;
2565edf6516SJed Brown   if (y == z) {
2575edf6516SJed Brown     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
2585edf6516SJed Brown     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
2595edf6516SJed Brown     ierr = VecWAXPY(z,1.0,shell->right_add_work,y);CHKERRQ(ierr);
2605edf6516SJed Brown   } else {
2615edf6516SJed Brown     ierr = MatMult(A,x,z);CHKERRQ(ierr);
2625edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
2635edf6516SJed Brown   }
2645edf6516SJed Brown   PetscFunctionReturn(0);
2655edf6516SJed Brown }
2665edf6516SJed Brown 
2675edf6516SJed Brown #undef __FUNCT__
26818be62a5SSatish Balay #define __FUNCT__ "MatMultTranspose_Shell"
26918be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
27018be62a5SSatish Balay {
27118be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
27218be62a5SSatish Balay   PetscErrorCode ierr;
27325578ef6SJed Brown   Vec            xx;
27418be62a5SSatish Balay 
27518be62a5SSatish Balay   PetscFunctionBegin;
2768fe8eb27SJed Brown   ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr);
2778fe8eb27SJed Brown   ierr = (*shell->multtranspose)(A,xx,y);CHKERRQ(ierr);
2788fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
2798fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
28018be62a5SSatish Balay   PetscFunctionReturn(0);
28118be62a5SSatish Balay }
28218be62a5SSatish Balay 
28318be62a5SSatish Balay #undef __FUNCT__
2845edf6516SJed Brown #define __FUNCT__ "MatMultTransposeAdd_Shell"
2855edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
2865edf6516SJed Brown {
2875edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2885edf6516SJed Brown   PetscErrorCode ierr;
2895edf6516SJed Brown 
2905edf6516SJed Brown   PetscFunctionBegin;
2915edf6516SJed Brown   if (y == z) {
2925edf6516SJed Brown     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
2935edf6516SJed Brown     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
2945edf6516SJed Brown     ierr = VecWAXPY(z,1.0,shell->left_add_work,y);CHKERRQ(ierr);
2955edf6516SJed Brown   } else {
2965edf6516SJed Brown     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
2975edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
2985edf6516SJed Brown   }
2995edf6516SJed Brown   PetscFunctionReturn(0);
3005edf6516SJed Brown }
3015edf6516SJed Brown 
3025edf6516SJed Brown #undef __FUNCT__
30318be62a5SSatish Balay #define __FUNCT__ "MatGetDiagonal_Shell"
30418be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
30518be62a5SSatish Balay {
30618be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
30718be62a5SSatish Balay   PetscErrorCode ierr;
30818be62a5SSatish Balay 
30918be62a5SSatish Balay   PetscFunctionBegin;
31018be62a5SSatish Balay   ierr = (*shell->getdiagonal)(A,v);CHKERRQ(ierr);
31118be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
3128fe8eb27SJed Brown   if (shell->dshift) {
3138fe8eb27SJed Brown     ierr = VecPointwiseMult(v,v,shell->dshift);CHKERRQ(ierr);
3148fe8eb27SJed Brown   } else {
31518be62a5SSatish Balay     ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
31618be62a5SSatish Balay   }
3178fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
3188fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
31918be62a5SSatish Balay   PetscFunctionReturn(0);
32018be62a5SSatish Balay }
32118be62a5SSatish Balay 
32218be62a5SSatish Balay #undef __FUNCT__
323ef66eb69SBarry Smith #define __FUNCT__ "MatShift_Shell"
324f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
325ef66eb69SBarry Smith {
326ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
3278fe8eb27SJed Brown   PetscErrorCode ierr;
328b24ad042SBarry Smith 
329ef66eb69SBarry Smith   PetscFunctionBegin;
3308fe8eb27SJed Brown   if (shell->left || shell->right || shell->dshift) {
3318fe8eb27SJed Brown     if (!shell->dshift) {
3328fe8eb27SJed Brown       if (!shell->dshift_owned) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift_owned);CHKERRQ(ierr);}
3338fe8eb27SJed Brown       shell->dshift = shell->dshift_owned;
3348fe8eb27SJed Brown       ierr          = VecSet(shell->dshift,shell->vshift+a);CHKERRQ(ierr);
3358fe8eb27SJed Brown     } else {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);}
3368fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
3378fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
3388fe8eb27SJed Brown   } else shell->vshift += a;
3398fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
340ef66eb69SBarry Smith   PetscFunctionReturn(0);
341ef66eb69SBarry Smith }
342ef66eb69SBarry Smith 
343ef66eb69SBarry Smith #undef __FUNCT__
344ef66eb69SBarry Smith #define __FUNCT__ "MatScale_Shell"
345f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
346ef66eb69SBarry Smith {
347ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
3488fe8eb27SJed Brown   PetscErrorCode ierr;
349b24ad042SBarry Smith 
350ef66eb69SBarry Smith   PetscFunctionBegin;
351f4df32b1SMatthew Knepley   shell->vscale *= a;
352*2205254eSKarl Rupp   if (shell->dshift) {
353*2205254eSKarl Rupp     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
354*2205254eSKarl Rupp   } else shell->vshift *= a;
3558fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
3568fe8eb27SJed Brown   PetscFunctionReturn(0);
35718be62a5SSatish Balay }
3588fe8eb27SJed Brown 
3598fe8eb27SJed Brown #undef __FUNCT__
3608fe8eb27SJed Brown #define __FUNCT__ "MatDiagonalScale_Shell"
3618fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
3628fe8eb27SJed Brown {
3638fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
3648fe8eb27SJed Brown   PetscErrorCode ierr;
3658fe8eb27SJed Brown 
3668fe8eb27SJed Brown   PetscFunctionBegin;
3678fe8eb27SJed Brown   if (left) {
3688fe8eb27SJed Brown     if (!shell->left_owned) {ierr = VecDuplicate(left,&shell->left_owned);CHKERRQ(ierr);}
369*2205254eSKarl Rupp     if (shell->left) {
370*2205254eSKarl Rupp       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
371*2205254eSKarl Rupp     } else {
3728fe8eb27SJed Brown       shell->left = shell->left_owned;
3738fe8eb27SJed Brown       ierr        = VecCopy(left,shell->left);CHKERRQ(ierr);
37418be62a5SSatish Balay     }
375ef66eb69SBarry Smith   }
3768fe8eb27SJed Brown   if (right) {
3778fe8eb27SJed Brown     if (!shell->right_owned) {ierr = VecDuplicate(right,&shell->right_owned);CHKERRQ(ierr);}
378*2205254eSKarl Rupp     if (shell->right) {
379*2205254eSKarl Rupp       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
380*2205254eSKarl Rupp     } else {
3818fe8eb27SJed Brown       shell->right = shell->right_owned;
3828fe8eb27SJed Brown       ierr         = VecCopy(right,shell->right);CHKERRQ(ierr);
3838fe8eb27SJed Brown     }
3848fe8eb27SJed Brown   }
3858fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
386ef66eb69SBarry Smith   PetscFunctionReturn(0);
387ef66eb69SBarry Smith }
388ef66eb69SBarry Smith 
389ef66eb69SBarry Smith #undef __FUNCT__
390ef66eb69SBarry Smith #define __FUNCT__ "MatAssemblyEnd_Shell"
391dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
392ef66eb69SBarry Smith {
393ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell*)Y->data;
394ef66eb69SBarry Smith 
395ef66eb69SBarry Smith   PetscFunctionBegin;
3968fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
397ef66eb69SBarry Smith     shell->vshift = 0.0;
398ef66eb69SBarry Smith     shell->vscale = 1.0;
3998fe8eb27SJed Brown     shell->dshift = PETSC_NULL;
4008fe8eb27SJed Brown     shell->left   = PETSC_NULL;
4018fe8eb27SJed Brown     shell->right  = PETSC_NULL;
4027fb7d96aSJed Brown     if (shell->mult) {
403ef66eb69SBarry Smith       Y->ops->mult = shell->mult;
4047fb7d96aSJed Brown       shell->mult  = PETSC_NULL;
4057fb7d96aSJed Brown     }
4067fb7d96aSJed Brown     if (shell->multtranspose) {
40718be62a5SSatish Balay       Y->ops->multtranspose = shell->multtranspose;
4087fb7d96aSJed Brown       shell->multtranspose  = PETSC_NULL;
4097fb7d96aSJed Brown     }
4107fb7d96aSJed Brown     if (shell->getdiagonal) {
41118be62a5SSatish Balay       Y->ops->getdiagonal = shell->getdiagonal;
4127fb7d96aSJed Brown       shell->getdiagonal  = PETSC_NULL;
4137fb7d96aSJed Brown     }
4147fb7d96aSJed Brown     shell->usingscaled = PETSC_FALSE;
415ef66eb69SBarry Smith   }
416ef66eb69SBarry Smith   PetscFunctionReturn(0);
417ef66eb69SBarry Smith }
418ef66eb69SBarry Smith 
41919fd82e9SBarry Smith extern PetscErrorCode MatConvert_Shell(Mat, MatType,MatReuse,Mat*);
420b951964fSBarry Smith 
42109dc0095SBarry Smith static struct _MatOps MatOps_Values = {0,
42220563c6bSBarry Smith        0,
42320563c6bSBarry Smith        0,
42420563c6bSBarry Smith        0,
42597304618SKris Buschelman /* 4*/ 0,
42620563c6bSBarry Smith        0,
427b951964fSBarry Smith        0,
428b951964fSBarry Smith        0,
429b951964fSBarry Smith        0,
430b951964fSBarry Smith        0,
43197304618SKris Buschelman /*10*/ 0,
432b951964fSBarry Smith        0,
433b951964fSBarry Smith        0,
434b951964fSBarry Smith        0,
435b951964fSBarry Smith        0,
43697304618SKris Buschelman /*15*/ 0,
437b951964fSBarry Smith        0,
438b951964fSBarry Smith        0,
4398fe8eb27SJed Brown        MatDiagonalScale_Shell,
440b951964fSBarry Smith        0,
44197304618SKris Buschelman /*20*/ 0,
442ef66eb69SBarry Smith        MatAssemblyEnd_Shell,
443b951964fSBarry Smith        0,
444b951964fSBarry Smith        0,
445d519adbfSMatthew Knepley /*24*/ 0,
446b951964fSBarry Smith        0,
447b951964fSBarry Smith        0,
448b951964fSBarry Smith        0,
449b951964fSBarry Smith        0,
450d519adbfSMatthew Knepley /*29*/ 0,
451b951964fSBarry Smith        0,
452273d9f13SBarry Smith        0,
453b951964fSBarry Smith        0,
454b951964fSBarry Smith        0,
455d519adbfSMatthew Knepley /*34*/ 0,
456b951964fSBarry Smith        0,
457b951964fSBarry Smith        0,
45809dc0095SBarry Smith        0,
45909dc0095SBarry Smith        0,
460d519adbfSMatthew Knepley /*39*/ 0,
46109dc0095SBarry Smith        0,
46209dc0095SBarry Smith        0,
46309dc0095SBarry Smith        0,
46409dc0095SBarry Smith        0,
465d519adbfSMatthew Knepley /*44*/ 0,
466ef66eb69SBarry Smith        MatScale_Shell,
467ef66eb69SBarry Smith        MatShift_Shell,
46809dc0095SBarry Smith        0,
46909dc0095SBarry Smith        0,
470f73d5cc4SBarry Smith /*49*/ 0,
47109dc0095SBarry Smith        0,
47209dc0095SBarry Smith        0,
47309dc0095SBarry Smith        0,
47409dc0095SBarry Smith        0,
475d519adbfSMatthew Knepley /*54*/ 0,
47609dc0095SBarry Smith        0,
47709dc0095SBarry Smith        0,
47809dc0095SBarry Smith        0,
47909dc0095SBarry Smith        0,
480d519adbfSMatthew Knepley /*59*/ 0,
481b9b97703SBarry Smith        MatDestroy_Shell,
48209dc0095SBarry Smith        0,
483357abbc8SBarry Smith        0,
484273d9f13SBarry Smith        0,
485d519adbfSMatthew Knepley /*64*/ 0,
486273d9f13SBarry Smith        0,
487273d9f13SBarry Smith        0,
488273d9f13SBarry Smith        0,
489273d9f13SBarry Smith        0,
490d519adbfSMatthew Knepley /*69*/ 0,
491273d9f13SBarry Smith        0,
492c87e5d42SMatthew Knepley        MatConvert_Shell,
493273d9f13SBarry Smith        0,
49497304618SKris Buschelman        0,
495d519adbfSMatthew Knepley /*74*/ 0,
49697304618SKris Buschelman        0,
49797304618SKris Buschelman        0,
49897304618SKris Buschelman        0,
49997304618SKris Buschelman        0,
500d519adbfSMatthew Knepley /*79*/ 0,
50197304618SKris Buschelman        0,
50297304618SKris Buschelman        0,
50397304618SKris Buschelman        0,
504865e5f61SKris Buschelman        0,
505d519adbfSMatthew Knepley /*84*/ 0,
506865e5f61SKris Buschelman        0,
507865e5f61SKris Buschelman        0,
508865e5f61SKris Buschelman        0,
509865e5f61SKris Buschelman        0,
510d519adbfSMatthew Knepley /*89*/ 0,
511865e5f61SKris Buschelman        0,
512865e5f61SKris Buschelman        0,
513865e5f61SKris Buschelman        0,
514865e5f61SKris Buschelman        0,
515d519adbfSMatthew Knepley /*94*/ 0,
516865e5f61SKris Buschelman        0,
517865e5f61SKris Buschelman        0,
518865e5f61SKris Buschelman        0};
519273d9f13SBarry Smith 
5200bad9183SKris Buschelman /*MC
521fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
5220bad9183SKris Buschelman 
5230bad9183SKris Buschelman   Level: advanced
5240bad9183SKris Buschelman 
5250bad9183SKris Buschelman .seealso: MatCreateShell
5260bad9183SKris Buschelman M*/
5270bad9183SKris Buschelman 
528273d9f13SBarry Smith EXTERN_C_BEGIN
529711e205bSSatish Balay #undef __FUNCT__
530711e205bSSatish Balay #define __FUNCT__ "MatCreate_Shell"
5317087cfbeSBarry Smith PetscErrorCode  MatCreate_Shell(Mat A)
532273d9f13SBarry Smith {
533273d9f13SBarry Smith   Mat_Shell      *b;
534dfbe8321SBarry Smith   PetscErrorCode ierr;
535273d9f13SBarry Smith 
536273d9f13SBarry Smith   PetscFunctionBegin;
537273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
538273d9f13SBarry Smith 
53938f2d2fdSLisandro Dalcin   ierr    = PetscNewLog(A,Mat_Shell,&b);CHKERRQ(ierr);
540273d9f13SBarry Smith   A->data = (void*)b;
541273d9f13SBarry Smith 
54226283091SBarry Smith   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
54326283091SBarry Smith   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
544273d9f13SBarry Smith 
545273d9f13SBarry Smith   b->ctx           = 0;
546ef66eb69SBarry Smith   b->vshift        = 0.0;
547ef66eb69SBarry Smith   b->vscale        = 1.0;
548ef66eb69SBarry Smith   b->mult          = 0;
54918be62a5SSatish Balay   b->multtranspose = 0;
55018be62a5SSatish Balay   b->getdiagonal   = 0;
551273d9f13SBarry Smith   A->assembled     = PETSC_TRUE;
552210f0121SBarry Smith   A->preallocated  = PETSC_FALSE;
553*2205254eSKarl Rupp 
55417667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
555273d9f13SBarry Smith   PetscFunctionReturn(0);
556273d9f13SBarry Smith }
557273d9f13SBarry Smith EXTERN_C_END
558e51e0e81SBarry Smith 
559711e205bSSatish Balay #undef __FUNCT__
560711e205bSSatish Balay #define __FUNCT__ "MatCreateShell"
5614b828684SBarry Smith /*@C
562052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
563ff756334SLois Curfman McInnes    private data storage format.
564e51e0e81SBarry Smith 
565c7fcc2eaSBarry Smith   Collective on MPI_Comm
566c7fcc2eaSBarry Smith 
567e51e0e81SBarry Smith    Input Parameters:
568c7fcc2eaSBarry Smith +  comm - MPI communicator
569c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
570c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
571c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
572c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
573c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
574e51e0e81SBarry Smith 
575ff756334SLois Curfman McInnes    Output Parameter:
57644cd7ae7SLois Curfman McInnes .  A - the matrix
577e51e0e81SBarry Smith 
578ff2fd236SBarry Smith    Level: advanced
579ff2fd236SBarry Smith 
580f39d1f56SLois Curfman McInnes   Usage:
5817b2a1423SBarry Smith $    extern int mult(Mat,Vec,Vec);
582f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
583c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
584f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
585f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
586f39d1f56SLois Curfman McInnes 
587ff756334SLois Curfman McInnes    Notes:
588ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
589ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
590ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
591e51e0e81SBarry Smith 
592f38a8d56SBarry Smith    Fortran Notes: The context can only be an integer or a PetscObject
593f38a8d56SBarry Smith       unfortunately it cannot be a Fortran array or derived type.
594f38a8d56SBarry Smith 
595f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
596f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
597645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
598645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
599645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
600645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
601645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
602645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
603645985a0SLois Curfman McInnes    For example,
604f39d1f56SLois Curfman McInnes 
605f39d1f56SLois Curfman McInnes $
606f39d1f56SLois Curfman McInnes $     Vec x, y
6077b2a1423SBarry Smith $     extern int mult(Mat,Vec,Vec);
608645985a0SLois Curfman McInnes $     Mat A
609f39d1f56SLois Curfman McInnes $
610c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
611c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
612f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
613c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
614c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
615c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
616645985a0SLois Curfman McInnes $     MatMult(A,x,y);
617645985a0SLois Curfman McInnes $     MatDestroy(A);
618f39d1f56SLois Curfman McInnes $     VecDestroy(y); VecDestroy(x);
619645985a0SLois Curfman McInnes $
620e51e0e81SBarry Smith 
6210b627109SLois Curfman McInnes .keywords: matrix, shell, create
6220b627109SLois Curfman McInnes 
623ab50ec6bSBarry Smith .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
624e51e0e81SBarry Smith @*/
6257087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
626e51e0e81SBarry Smith {
627dfbe8321SBarry Smith   PetscErrorCode ierr;
628ed3cc1f0SBarry Smith 
6293a40ed3dSBarry Smith   PetscFunctionBegin;
630f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
631f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
632273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
633273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
6340fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
635273d9f13SBarry Smith   PetscFunctionReturn(0);
636c7fcc2eaSBarry Smith }
637c7fcc2eaSBarry Smith 
638711e205bSSatish Balay #undef __FUNCT__
639711e205bSSatish Balay #define __FUNCT__ "MatShellSetContext"
640c6866cfdSSatish Balay /*@
641273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
642c7fcc2eaSBarry Smith 
6433f9fe445SBarry Smith    Logically Collective on Mat
644c7fcc2eaSBarry Smith 
645273d9f13SBarry Smith     Input Parameters:
646273d9f13SBarry Smith +   mat - the shell matrix
647273d9f13SBarry Smith -   ctx - the context
648273d9f13SBarry Smith 
649273d9f13SBarry Smith    Level: advanced
650273d9f13SBarry Smith 
651f38a8d56SBarry Smith    Fortran Notes: The context can only be an integer or a PetscObject
652f38a8d56SBarry Smith       unfortunately it cannot be a Fortran array or derived type.
653273d9f13SBarry Smith 
654273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
6550bc0a719SBarry Smith @*/
6567087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
657273d9f13SBarry Smith {
658273d9f13SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
659dfbe8321SBarry Smith   PetscErrorCode ierr;
660ace3abfcSBarry Smith   PetscBool      flg;
661273d9f13SBarry Smith 
662273d9f13SBarry Smith   PetscFunctionBegin;
6630700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
664251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
665273d9f13SBarry Smith   if (flg) {
666273d9f13SBarry Smith     shell->ctx = ctx;
667940183f3SBarry Smith   } else SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
6683a40ed3dSBarry Smith   PetscFunctionReturn(0);
669e51e0e81SBarry Smith }
670e51e0e81SBarry Smith 
671711e205bSSatish Balay #undef __FUNCT__
672711e205bSSatish Balay #define __FUNCT__ "MatShellSetOperation"
673c16cb8f2SBarry Smith /*@C
6743a3eedf2SBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for
6753a3eedf2SBarry Smith                            a shell matrix.
676e51e0e81SBarry Smith 
6773f9fe445SBarry Smith    Logically Collective on Mat
678fee21e36SBarry Smith 
679c7fcc2eaSBarry Smith     Input Parameters:
680c7fcc2eaSBarry Smith +   mat - the shell matrix
681c7fcc2eaSBarry Smith .   op - the name of the operation
682c7fcc2eaSBarry Smith -   f - the function that provides the operation.
683c7fcc2eaSBarry Smith 
68415091d37SBarry Smith    Level: advanced
68515091d37SBarry Smith 
686fae171e0SBarry Smith     Usage:
687e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
688f39d1f56SLois Curfman McInnes $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
689c134de8dSSatish Balay $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
6900b627109SLois Curfman McInnes 
691a62d957aSLois Curfman McInnes     Notes:
692e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
6931c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
694a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
6951c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
696a62d957aSLois Curfman McInnes 
69725296bd5SBarry Smith     All user-provided functions (execept for MATOP_DESTROY) should have the same calling
698deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
699deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
700deebb3c3SLois Curfman McInnes     routines, e.g.,
701a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
702a62d957aSLois Curfman McInnes 
7034aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
7044aa34b0aSBarry Smith     nonzero on failure.
7054aa34b0aSBarry Smith 
706a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
707a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
708a62d957aSLois Curfman McInnes     set by MatCreateShell().
709a62d957aSLois Curfman McInnes 
710501d9185SBarry Smith     Fortran Notes: For MatGetVecs() the user code should check if the input left or right matrix is -1 and in that case not
711501d9185SBarry Smith        generate a matrix. See src/mat/examples/tests/ex120f.F
712501d9185SBarry Smith 
713a62d957aSLois Curfman McInnes .keywords: matrix, shell, set, operation
714a62d957aSLois Curfman McInnes 
715ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
716e51e0e81SBarry Smith @*/
7177087cfbeSBarry Smith PetscErrorCode  MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
718e51e0e81SBarry Smith {
719dfbe8321SBarry Smith   PetscErrorCode ierr;
720ace3abfcSBarry Smith   PetscBool      flg;
721273d9f13SBarry Smith 
7223a40ed3dSBarry Smith   PetscFunctionBegin;
7230700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
7245edf6516SJed Brown   switch (op) {
7255edf6516SJed Brown   case MATOP_DESTROY:
726251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
727273d9f13SBarry Smith     if (flg) {
728a62d957aSLois Curfman McInnes       Mat_Shell *shell = (Mat_Shell*)mat->data;
7296849ba73SBarry Smith       shell->destroy   = (PetscErrorCode (*)(Mat))f;
7306849ba73SBarry Smith     } else mat->ops->destroy = (PetscErrorCode (*)(Mat))f;
7315edf6516SJed Brown     break;
7325edf6516SJed Brown   case MATOP_VIEW:
7335edf6516SJed Brown     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
7345edf6516SJed Brown     break;
7355edf6516SJed Brown   case MATOP_MULT:
7365edf6516SJed Brown     mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
7375edf6516SJed Brown     if (!mat->ops->multadd) mat->ops->multadd = MatMultAdd_Shell;
7385edf6516SJed Brown     break;
7395edf6516SJed Brown   case MATOP_MULT_TRANSPOSE:
7405edf6516SJed Brown     mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
7415edf6516SJed Brown     if (!mat->ops->multtransposeadd) mat->ops->multtransposeadd = MatMultTransposeAdd_Shell;
7425edf6516SJed Brown     break;
7435edf6516SJed Brown   default:
7445edf6516SJed Brown     (((void(**)(void))mat->ops)[op]) = f;
745a62d957aSLois Curfman McInnes   }
7463a40ed3dSBarry Smith   PetscFunctionReturn(0);
747e51e0e81SBarry Smith }
748f0479e8cSBarry Smith 
749711e205bSSatish Balay #undef __FUNCT__
750711e205bSSatish Balay #define __FUNCT__ "MatShellGetOperation"
751d4bb536fSBarry Smith /*@C
752d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
753d4bb536fSBarry Smith 
754c7fcc2eaSBarry Smith     Not Collective
755c7fcc2eaSBarry Smith 
756d4bb536fSBarry Smith     Input Parameters:
757c7fcc2eaSBarry Smith +   mat - the shell matrix
758c7fcc2eaSBarry Smith -   op - the name of the operation
759d4bb536fSBarry Smith 
760d4bb536fSBarry Smith     Output Parameter:
761d4bb536fSBarry Smith .   f - the function that provides the operation.
762d4bb536fSBarry Smith 
76315091d37SBarry Smith     Level: advanced
76415091d37SBarry Smith 
765d4bb536fSBarry Smith     Notes:
766e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
767d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
768d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
769d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
770d4bb536fSBarry Smith 
771d4bb536fSBarry Smith     All user-provided functions have the same calling
772d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
773d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
774d4bb536fSBarry Smith     routines, e.g.,
775d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
776d4bb536fSBarry Smith 
777d4bb536fSBarry Smith     Within each user-defined routine, the user should call
778d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
779d4bb536fSBarry Smith     set by MatCreateShell().
780d4bb536fSBarry Smith 
781d4bb536fSBarry Smith .keywords: matrix, shell, set, operation
782d4bb536fSBarry Smith 
783ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
784d4bb536fSBarry Smith @*/
7857087cfbeSBarry Smith PetscErrorCode  MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
786d4bb536fSBarry Smith {
787dfbe8321SBarry Smith   PetscErrorCode ierr;
788ace3abfcSBarry Smith   PetscBool      flg;
789273d9f13SBarry Smith 
7903a40ed3dSBarry Smith   PetscFunctionBegin;
7910700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
792d4bb536fSBarry Smith   if (op == MATOP_DESTROY) {
793251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
794273d9f13SBarry Smith     if (flg) {
795d4bb536fSBarry Smith       Mat_Shell *shell = (Mat_Shell*)mat->data;
796c134de8dSSatish Balay       *f = (void (*)(void))shell->destroy;
797c7fcc2eaSBarry Smith     } else {
798c134de8dSSatish Balay       *f = (void (*)(void))mat->ops->destroy;
799d4bb536fSBarry Smith     }
800c7fcc2eaSBarry Smith   } else if (op == MATOP_VIEW) {
801c134de8dSSatish Balay     *f = (void (*)(void))mat->ops->view;
802c7fcc2eaSBarry Smith   } else {
803c134de8dSSatish Balay     *f = (((void (**)(void))mat->ops)[op]);
804d4bb536fSBarry Smith   }
8053a40ed3dSBarry Smith   PetscFunctionReturn(0);
806d4bb536fSBarry Smith }
807d4bb536fSBarry Smith 
808