xref: /petsc/src/mat/impls/shell/shell.c (revision 74e5cdcad0e6db4a4968e1ae7f59a8e89e35509b)
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 
8af0996ceSBarry Smith #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
9e51e0e81SBarry Smith 
1028f357e3SAlex Fikl struct _MatShellOps {
1128f357e3SAlex Fikl   /*   0 */
126849ba73SBarry Smith   PetscErrorCode (*mult)(Mat,Vec,Vec);
1328f357e3SAlex Fikl   /*   5 */
1418be62a5SSatish Balay   PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
1528f357e3SAlex Fikl   /*  10 */
1628f357e3SAlex Fikl   /*  15 */
1718be62a5SSatish Balay   PetscErrorCode (*getdiagonal)(Mat,Vec);
1828f357e3SAlex Fikl   /*  20 */
1928f357e3SAlex Fikl   /*  24 */
2028f357e3SAlex Fikl   /*  29 */
2128f357e3SAlex Fikl   /*  34 */
2228f357e3SAlex Fikl   /*  39 */
2328f357e3SAlex Fikl   PetscErrorCode (*copy)(Mat,Mat,MatStructure);
2428f357e3SAlex Fikl   /*  44 */
256464bf51SAlex Fikl   PetscErrorCode (*diagonalset)(Mat,Vec,InsertMode);
2628f357e3SAlex Fikl   /*  49 */
2728f357e3SAlex Fikl   /*  54 */
2828f357e3SAlex Fikl   /*  59 */
2928f357e3SAlex Fikl   PetscErrorCode (*destroy)(Mat);
3028f357e3SAlex Fikl   /*  64 */
3128f357e3SAlex Fikl   /*  69 */
3228f357e3SAlex Fikl   /*  74 */
3328f357e3SAlex Fikl   /*  79 */
3428f357e3SAlex Fikl   /*  84 */
3528f357e3SAlex Fikl   /*  89 */
3628f357e3SAlex Fikl   /*  94 */
3728f357e3SAlex Fikl   /*  99 */
3828f357e3SAlex Fikl   /* 104 */
3928f357e3SAlex Fikl   /* 109 */
4028f357e3SAlex Fikl   /* 114 */
4128f357e3SAlex Fikl   /* 119 */
4228f357e3SAlex Fikl   /* 124 */
4328f357e3SAlex Fikl   /* 129 */
4428f357e3SAlex Fikl   /* 134 */
4528f357e3SAlex Fikl   /* 139 */
4628f357e3SAlex Fikl   /* 144 */
4728f357e3SAlex Fikl };
4828f357e3SAlex Fikl 
4928f357e3SAlex Fikl typedef struct {
5028f357e3SAlex Fikl   struct _MatShellOps ops[1];
512205254eSKarl Rupp 
52ef66eb69SBarry Smith   PetscScalar vscale,vshift;
538fe8eb27SJed Brown   Vec         dshift;
548fe8eb27SJed Brown   Vec         left,right;
558fe8eb27SJed Brown   Vec         dshift_owned,left_owned,right_owned;
568fe8eb27SJed Brown   Vec         left_work,right_work;
575edf6516SJed Brown   Vec         left_add_work,right_add_work;
588fe8eb27SJed Brown   PetscBool   usingscaled;
5920563c6bSBarry Smith   void        *ctx;
6088cf3e7dSBarry Smith } Mat_Shell;
618fe8eb27SJed Brown /*
628fe8eb27SJed Brown  The most general expression for the matrix is
638fe8eb27SJed Brown 
648fe8eb27SJed Brown  S = L (a A + B) R
658fe8eb27SJed Brown 
668fe8eb27SJed Brown  where
678fe8eb27SJed Brown  A is the matrix defined by the user's function
688fe8eb27SJed Brown  a is a scalar multiple
698fe8eb27SJed Brown  L is left scaling
708fe8eb27SJed Brown  R is right scaling
718fe8eb27SJed Brown  B is a diagonal shift defined by
728fe8eb27SJed Brown    diag(dshift) if the vector dshift is non-NULL
738fe8eb27SJed Brown    vscale*identity otherwise
748fe8eb27SJed Brown 
758fe8eb27SJed Brown  The following identities apply:
768fe8eb27SJed Brown 
778fe8eb27SJed Brown  Scale by c:
788fe8eb27SJed Brown   c [L (a A + B) R] = L [(a c) A + c B] R
798fe8eb27SJed Brown 
808fe8eb27SJed Brown  Shift by c:
818fe8eb27SJed Brown   [L (a A + B) R] + c = L [a A + (B + c Linv Rinv)] R
828fe8eb27SJed Brown 
838fe8eb27SJed Brown  Diagonal scaling is achieved by simply multiplying with existing L and R vectors
848fe8eb27SJed Brown 
858fe8eb27SJed Brown  In the data structure:
868fe8eb27SJed Brown 
878fe8eb27SJed Brown  vscale=1.0  means no special scaling will be applied
888fe8eb27SJed Brown  dshift=NULL means a constant diagonal shift (fall back to vshift)
898fe8eb27SJed Brown  vshift=0.0  means no constant diagonal shift, note that vshift is only used if dshift is NULL
908fe8eb27SJed Brown */
918fe8eb27SJed Brown 
928fe8eb27SJed Brown static PetscErrorCode MatMult_Shell(Mat,Vec,Vec);
938fe8eb27SJed Brown static PetscErrorCode MatMultTranspose_Shell(Mat,Vec,Vec);
948fe8eb27SJed Brown static PetscErrorCode MatGetDiagonal_Shell(Mat,Vec);
9528f357e3SAlex Fikl static PetscErrorCode MatCopy_Shell(Mat,Mat,MatStructure);
968fe8eb27SJed Brown 
978fe8eb27SJed Brown static PetscErrorCode MatShellUseScaledMethods(Mat Y)
988fe8eb27SJed Brown {
998fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)Y->data;
1008fe8eb27SJed Brown 
1018fe8eb27SJed Brown   PetscFunctionBegin;
1028fe8eb27SJed Brown   if (shell->usingscaled) PetscFunctionReturn(0);
10328f357e3SAlex Fikl   shell->ops->mult  = Y->ops->mult;
1048fe8eb27SJed Brown   Y->ops->mult = MatMult_Shell;
1058fe8eb27SJed Brown   if (Y->ops->multtranspose) {
10628f357e3SAlex Fikl     shell->ops->multtranspose  = Y->ops->multtranspose;
1078fe8eb27SJed Brown     Y->ops->multtranspose = MatMultTranspose_Shell;
1088fe8eb27SJed Brown   }
1098fe8eb27SJed Brown   if (Y->ops->getdiagonal) {
11028f357e3SAlex Fikl     shell->ops->getdiagonal  = Y->ops->getdiagonal;
1118fe8eb27SJed Brown     Y->ops->getdiagonal = MatGetDiagonal_Shell;
1128fe8eb27SJed Brown   }
11328f357e3SAlex Fikl   if (Y->ops->copy) {
11428f357e3SAlex Fikl     shell->ops->copy  = Y->ops->copy;
11528f357e3SAlex Fikl     Y->ops->copy = MatCopy_Shell;
11628f357e3SAlex Fikl   }
1178fe8eb27SJed Brown   shell->usingscaled = PETSC_TRUE;
1188fe8eb27SJed Brown   PetscFunctionReturn(0);
1198fe8eb27SJed Brown }
1208fe8eb27SJed Brown 
1218fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
1228fe8eb27SJed Brown {
1238fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1248fe8eb27SJed Brown   PetscErrorCode ierr;
1258fe8eb27SJed Brown 
1268fe8eb27SJed Brown   PetscFunctionBegin;
1270298fd71SBarry Smith   *xx = NULL;
1288fe8eb27SJed Brown   if (!shell->left) {
1298fe8eb27SJed Brown     *xx = x;
1308fe8eb27SJed Brown   } else {
1318fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
1328fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
1338fe8eb27SJed Brown     *xx  = shell->left_work;
1348fe8eb27SJed Brown   }
1358fe8eb27SJed Brown   PetscFunctionReturn(0);
1368fe8eb27SJed Brown }
1378fe8eb27SJed Brown 
1388fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1398fe8eb27SJed Brown {
1408fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1418fe8eb27SJed Brown   PetscErrorCode ierr;
1428fe8eb27SJed Brown 
1438fe8eb27SJed Brown   PetscFunctionBegin;
1440298fd71SBarry Smith   *xx = NULL;
1458fe8eb27SJed Brown   if (!shell->right) {
1468fe8eb27SJed Brown     *xx = x;
1478fe8eb27SJed Brown   } else {
1488fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
1498fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
1508fe8eb27SJed Brown     *xx  = shell->right_work;
1518fe8eb27SJed Brown   }
1528fe8eb27SJed Brown   PetscFunctionReturn(0);
1538fe8eb27SJed Brown }
1548fe8eb27SJed Brown 
1558fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1568fe8eb27SJed Brown {
1578fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1588fe8eb27SJed Brown   PetscErrorCode ierr;
1598fe8eb27SJed Brown 
1608fe8eb27SJed Brown   PetscFunctionBegin;
1618fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
1628fe8eb27SJed Brown   PetscFunctionReturn(0);
1638fe8eb27SJed Brown }
1648fe8eb27SJed Brown 
1658fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
1668fe8eb27SJed Brown {
1678fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1688fe8eb27SJed Brown   PetscErrorCode ierr;
1698fe8eb27SJed Brown 
1708fe8eb27SJed Brown   PetscFunctionBegin;
1718fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
1728fe8eb27SJed Brown   PetscFunctionReturn(0);
1738fe8eb27SJed Brown }
1748fe8eb27SJed Brown 
1758fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
1768fe8eb27SJed Brown {
1778fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1788fe8eb27SJed Brown   PetscErrorCode ierr;
1798fe8eb27SJed Brown 
1808fe8eb27SJed Brown   PetscFunctionBegin;
1818fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
1828fe8eb27SJed Brown     PetscInt          i,m;
1838fe8eb27SJed Brown     const PetscScalar *x,*d;
1848fe8eb27SJed Brown     PetscScalar       *y;
1858fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
1868fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1878fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1888fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
1898fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
1908fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1918fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1928fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
193880538faSHong Zhang   } else if (PetscAbsScalar(shell->vshift) != 0) {
1948fe8eb27SJed Brown     ierr = VecAXPBY(Y,shell->vshift,shell->vscale,X);CHKERRQ(ierr);
195027c5fb5SJed Brown   } else if (shell->vscale != 1.0) {
196027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
1978fe8eb27SJed Brown   }
1988fe8eb27SJed Brown   PetscFunctionReturn(0);
1998fe8eb27SJed Brown }
200e51e0e81SBarry Smith 
2019d225801SJed Brown /*@
202a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
203b4fd4287SBarry Smith 
204c7fcc2eaSBarry Smith     Not Collective
205c7fcc2eaSBarry Smith 
206b4fd4287SBarry Smith     Input Parameter:
207b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
208b4fd4287SBarry Smith 
209b4fd4287SBarry Smith     Output Parameter:
210b4fd4287SBarry Smith .   ctx - the user provided context
211b4fd4287SBarry Smith 
21215091d37SBarry Smith     Level: advanced
21315091d37SBarry Smith 
214daf670e6SBarry Smith    Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this
215daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
216a62d957aSLois Curfman McInnes 
217a62d957aSLois Curfman McInnes .keywords: matrix, shell, get, context
218a62d957aSLois Curfman McInnes 
219ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
2200bc0a719SBarry Smith @*/
2218fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
222b4fd4287SBarry Smith {
223dfbe8321SBarry Smith   PetscErrorCode ierr;
224ace3abfcSBarry Smith   PetscBool      flg;
225273d9f13SBarry Smith 
2263a40ed3dSBarry Smith   PetscFunctionBegin;
2270700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2284482741eSBarry Smith   PetscValidPointer(ctx,2);
229251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
230940183f3SBarry Smith   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
231ce94432eSBarry Smith   else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
2323a40ed3dSBarry Smith   PetscFunctionReturn(0);
233b4fd4287SBarry Smith }
234b4fd4287SBarry Smith 
235dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
236e51e0e81SBarry Smith {
237dfbe8321SBarry Smith   PetscErrorCode ierr;
238bf0cc555SLisandro Dalcin   Mat_Shell      *shell = (Mat_Shell*)mat->data;
239ed3cc1f0SBarry Smith 
2403a40ed3dSBarry Smith   PetscFunctionBegin;
24128f357e3SAlex Fikl   if (shell->ops->destroy) {
24228f357e3SAlex Fikl     ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr);
243bf0cc555SLisandro Dalcin   }
2448fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_owned);CHKERRQ(ierr);
2458fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_owned);CHKERRQ(ierr);
2468fe8eb27SJed Brown   ierr = VecDestroy(&shell->dshift_owned);CHKERRQ(ierr);
2478fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
2488fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
2495edf6516SJed Brown   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
2505edf6516SJed Brown   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
251bf0cc555SLisandro Dalcin   ierr = PetscFree(mat->data);CHKERRQ(ierr);
2523a40ed3dSBarry Smith   PetscFunctionReturn(0);
253e51e0e81SBarry Smith }
254e51e0e81SBarry Smith 
2557fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
2567fabda3fSAlex Fikl {
25728f357e3SAlex Fikl   Mat_Shell       *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
2587fabda3fSAlex Fikl   PetscErrorCode  ierr;
259cb8c8a77SBarry Smith   PetscBool       matflg;
2607fabda3fSAlex Fikl 
2617fabda3fSAlex Fikl   PetscFunctionBegin;
26228f357e3SAlex Fikl   ierr = PetscObjectTypeCompare((PetscObject)B,MATSHELL,&matflg);CHKERRQ(ierr);
263cb8c8a77SBarry Smith   if (!matflg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_NOTSAMETYPE,"Output matrix must be a MATSHELL");
2647fabda3fSAlex Fikl 
2657fabda3fSAlex Fikl   ierr = MatShellUseScaledMethods(B);CHKERRQ(ierr);
266cb8c8a77SBarry Smith   ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
267cb8c8a77SBarry Smith   ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
2687fabda3fSAlex Fikl 
269cb8c8a77SBarry Smith   if (shellA->ops->copy) {
27028f357e3SAlex Fikl     ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr);
271cb8c8a77SBarry Smith   }
2727fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
2737fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
2747fabda3fSAlex Fikl   if (shellA->dshift_owned) {
2757fabda3fSAlex Fikl     if (!shellB->dshift_owned) {
2767fabda3fSAlex Fikl       ierr = VecDuplicate(shellA->dshift_owned,&shellB->dshift_owned);CHKERRQ(ierr);
2777fabda3fSAlex Fikl     }
2787fabda3fSAlex Fikl     ierr = VecCopy(shellA->dshift_owned,shellB->dshift_owned);CHKERRQ(ierr);
2797fabda3fSAlex Fikl     shellB->dshift = shellB->dshift_owned;
2807fabda3fSAlex Fikl   } else {
2817fabda3fSAlex Fikl     shellB->dshift = NULL;
2827fabda3fSAlex Fikl   }
2837fabda3fSAlex Fikl   if (shellA->left_owned) {
2847fabda3fSAlex Fikl     if (!shellB->left_owned) {
2857fabda3fSAlex Fikl       ierr = VecDuplicate(shellA->left_owned,&shellB->left_owned);CHKERRQ(ierr);
2867fabda3fSAlex Fikl     }
2877fabda3fSAlex Fikl     ierr = VecCopy(shellA->left_owned,shellB->left_owned);CHKERRQ(ierr);
2887fabda3fSAlex Fikl     shellB->left = shellB->left_owned;
2897fabda3fSAlex Fikl   } else {
2907fabda3fSAlex Fikl     shellB->left = NULL;
2917fabda3fSAlex Fikl   }
2927fabda3fSAlex Fikl   if (shellA->right_owned) {
2937fabda3fSAlex Fikl     if (!shellB->right_owned) {
2947fabda3fSAlex Fikl       ierr = VecDuplicate(shellA->right_owned,&shellB->right_owned);CHKERRQ(ierr);
2957fabda3fSAlex Fikl     }
2967fabda3fSAlex Fikl     ierr = VecCopy(shellA->right_owned,shellB->right_owned);CHKERRQ(ierr);
2977fabda3fSAlex Fikl     shellB->right = shellB->right_owned;
2987fabda3fSAlex Fikl   } else {
2997fabda3fSAlex Fikl     shellB->right = NULL;
3007fabda3fSAlex Fikl   }
3017fabda3fSAlex Fikl   PetscFunctionReturn(0);
3027fabda3fSAlex Fikl }
3037fabda3fSAlex Fikl 
304cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
305cb8c8a77SBarry Smith {
306cb8c8a77SBarry Smith   PetscErrorCode ierr;
307cb8c8a77SBarry Smith   void           *ctx;
308cb8c8a77SBarry Smith 
309cb8c8a77SBarry Smith   PetscFunctionBegin;
310cb8c8a77SBarry Smith   ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr);
311cb8c8a77SBarry Smith   ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr);
312cb8c8a77SBarry Smith   ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
313cb8c8a77SBarry Smith   PetscFunctionReturn(0);
314cb8c8a77SBarry Smith }
315cb8c8a77SBarry Smith 
316dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
317ef66eb69SBarry Smith {
318ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
319dfbe8321SBarry Smith   PetscErrorCode   ierr;
32025578ef6SJed Brown   Vec              xx;
321e3f487b0SBarry Smith   PetscObjectState instate,outstate;
322ef66eb69SBarry Smith 
323ef66eb69SBarry Smith   PetscFunctionBegin;
3248fe8eb27SJed Brown   ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr);
325e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
32628f357e3SAlex Fikl   ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr);
327e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
328e3f487b0SBarry Smith   if (instate == outstate) {
329e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
330e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
331e3f487b0SBarry Smith   }
3328fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
3338fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
334ef66eb69SBarry Smith   PetscFunctionReturn(0);
335ef66eb69SBarry Smith }
336ef66eb69SBarry Smith 
3375edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
3385edf6516SJed Brown {
3395edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
3405edf6516SJed Brown   PetscErrorCode ierr;
3415edf6516SJed Brown 
3425edf6516SJed Brown   PetscFunctionBegin;
3435edf6516SJed Brown   if (y == z) {
3445edf6516SJed Brown     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
3455edf6516SJed Brown     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
346b8430d49SBarry Smith     ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr);
3475edf6516SJed Brown   } else {
3485edf6516SJed Brown     ierr = MatMult(A,x,z);CHKERRQ(ierr);
3495edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
3505edf6516SJed Brown   }
3515edf6516SJed Brown   PetscFunctionReturn(0);
3525edf6516SJed Brown }
3535edf6516SJed Brown 
35418be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
35518be62a5SSatish Balay {
35618be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
35718be62a5SSatish Balay   PetscErrorCode   ierr;
35825578ef6SJed Brown   Vec              xx;
359e3f487b0SBarry Smith   PetscObjectState instate,outstate;
36018be62a5SSatish Balay 
36118be62a5SSatish Balay   PetscFunctionBegin;
3628fe8eb27SJed Brown   ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr);
363e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
36428f357e3SAlex Fikl   ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr);
365e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
366e3f487b0SBarry Smith   if (instate == outstate) {
367e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
368e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
369e3f487b0SBarry Smith   }
3708fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
3718fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
37218be62a5SSatish Balay   PetscFunctionReturn(0);
37318be62a5SSatish Balay }
37418be62a5SSatish Balay 
3755edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
3765edf6516SJed Brown {
3775edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
3785edf6516SJed Brown   PetscErrorCode ierr;
3795edf6516SJed Brown 
3805edf6516SJed Brown   PetscFunctionBegin;
3815edf6516SJed Brown   if (y == z) {
3825edf6516SJed Brown     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
3835edf6516SJed Brown     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
3845edf6516SJed Brown     ierr = VecWAXPY(z,1.0,shell->left_add_work,y);CHKERRQ(ierr);
3855edf6516SJed Brown   } else {
3865edf6516SJed Brown     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
3875edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
3885edf6516SJed Brown   }
3895edf6516SJed Brown   PetscFunctionReturn(0);
3905edf6516SJed Brown }
3915edf6516SJed Brown 
39218be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
39318be62a5SSatish Balay {
39418be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
39518be62a5SSatish Balay   PetscErrorCode ierr;
39618be62a5SSatish Balay 
39718be62a5SSatish Balay   PetscFunctionBegin;
39828f357e3SAlex Fikl   ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr);
39918be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
4008fe8eb27SJed Brown   if (shell->dshift) {
4018fe8eb27SJed Brown     ierr = VecPointwiseMult(v,v,shell->dshift);CHKERRQ(ierr);
4028fe8eb27SJed Brown   } else {
40318be62a5SSatish Balay     ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
40418be62a5SSatish Balay   }
4058fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
4068fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
40718be62a5SSatish Balay   PetscFunctionReturn(0);
40818be62a5SSatish Balay }
40918be62a5SSatish Balay 
410f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
411ef66eb69SBarry Smith {
412ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4138fe8eb27SJed Brown   PetscErrorCode ierr;
414b24ad042SBarry Smith 
415ef66eb69SBarry Smith   PetscFunctionBegin;
4168fe8eb27SJed Brown   if (shell->left || shell->right || shell->dshift) {
4178fe8eb27SJed Brown     if (!shell->dshift) {
4188fe8eb27SJed Brown       if (!shell->dshift_owned) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift_owned);CHKERRQ(ierr);}
4198fe8eb27SJed Brown       shell->dshift = shell->dshift_owned;
4208fe8eb27SJed Brown       ierr          = VecSet(shell->dshift,shell->vshift+a);CHKERRQ(ierr);
4218fe8eb27SJed Brown     } else {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);}
4228fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
4238fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
4248fe8eb27SJed Brown   } else shell->vshift += a;
4258fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
426ef66eb69SBarry Smith   PetscFunctionReturn(0);
427ef66eb69SBarry Smith }
428ef66eb69SBarry Smith 
4296464bf51SAlex Fikl PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
4306464bf51SAlex Fikl {
4316464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
4326464bf51SAlex Fikl   PetscErrorCode ierr;
4336464bf51SAlex Fikl 
4346464bf51SAlex Fikl   PetscFunctionBegin;
4356464bf51SAlex Fikl   if (shell->vscale != 1.0 || shell->left || shell->right) {
4366464bf51SAlex Fikl     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE, "Operation not supported on scaled matrix");
4376464bf51SAlex Fikl   }
4386464bf51SAlex Fikl 
43928f357e3SAlex Fikl   if (shell->ops->diagonalset) {
44028f357e3SAlex Fikl     ierr = (*shell->ops->diagonalset)(A,D,ins);CHKERRQ(ierr);
44128f357e3SAlex Fikl   }
4426464bf51SAlex Fikl   shell->vshift = 0.0;
4436464bf51SAlex Fikl   if (shell->dshift) { ierr = VecZeroEntries(shell->dshift);CHKERRQ(ierr); }
4446464bf51SAlex Fikl   PetscFunctionReturn(0);
4456464bf51SAlex Fikl }
4466464bf51SAlex Fikl 
447f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
448ef66eb69SBarry Smith {
449ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4508fe8eb27SJed Brown   PetscErrorCode ierr;
451b24ad042SBarry Smith 
452ef66eb69SBarry Smith   PetscFunctionBegin;
453f4df32b1SMatthew Knepley   shell->vscale *= a;
4542205254eSKarl Rupp   if (shell->dshift) {
4552205254eSKarl Rupp     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
4562205254eSKarl Rupp   } else shell->vshift *= a;
4578fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
4588fe8eb27SJed Brown   PetscFunctionReturn(0);
45918be62a5SSatish Balay }
4608fe8eb27SJed Brown 
4618fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
4628fe8eb27SJed Brown {
4638fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4648fe8eb27SJed Brown   PetscErrorCode ierr;
4658fe8eb27SJed Brown 
4668fe8eb27SJed Brown   PetscFunctionBegin;
4678fe8eb27SJed Brown   if (left) {
4688fe8eb27SJed Brown     if (!shell->left_owned) {ierr = VecDuplicate(left,&shell->left_owned);CHKERRQ(ierr);}
4692205254eSKarl Rupp     if (shell->left) {
4702205254eSKarl Rupp       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
4712205254eSKarl Rupp     } else {
4728fe8eb27SJed Brown       shell->left = shell->left_owned;
4738fe8eb27SJed Brown       ierr        = VecCopy(left,shell->left);CHKERRQ(ierr);
47418be62a5SSatish Balay     }
475ef66eb69SBarry Smith   }
4768fe8eb27SJed Brown   if (right) {
4778fe8eb27SJed Brown     if (!shell->right_owned) {ierr = VecDuplicate(right,&shell->right_owned);CHKERRQ(ierr);}
4782205254eSKarl Rupp     if (shell->right) {
4792205254eSKarl Rupp       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
4802205254eSKarl Rupp     } else {
4818fe8eb27SJed Brown       shell->right = shell->right_owned;
4828fe8eb27SJed Brown       ierr         = VecCopy(right,shell->right);CHKERRQ(ierr);
4838fe8eb27SJed Brown     }
4848fe8eb27SJed Brown   }
4858fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
486ef66eb69SBarry Smith   PetscFunctionReturn(0);
487ef66eb69SBarry Smith }
488ef66eb69SBarry Smith 
489dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
490ef66eb69SBarry Smith {
491ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell*)Y->data;
492ef66eb69SBarry Smith 
493ef66eb69SBarry Smith   PetscFunctionBegin;
4948fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
495ef66eb69SBarry Smith     shell->vshift = 0.0;
496ef66eb69SBarry Smith     shell->vscale = 1.0;
4970298fd71SBarry Smith     shell->dshift = NULL;
4980298fd71SBarry Smith     shell->left   = NULL;
4990298fd71SBarry Smith     shell->right  = NULL;
50028f357e3SAlex Fikl     if (shell->ops->mult) {
50128f357e3SAlex Fikl       Y->ops->mult = shell->ops->mult;
50228f357e3SAlex Fikl       shell->ops->mult  = NULL;
5037fb7d96aSJed Brown     }
50428f357e3SAlex Fikl     if (shell->ops->multtranspose) {
50528f357e3SAlex Fikl       Y->ops->multtranspose = shell->ops->multtranspose;
50628f357e3SAlex Fikl       shell->ops->multtranspose = NULL;
5077fb7d96aSJed Brown     }
50828f357e3SAlex Fikl     if (shell->ops->getdiagonal) {
50928f357e3SAlex Fikl       Y->ops->getdiagonal = shell->ops->getdiagonal;
51028f357e3SAlex Fikl       shell->ops->getdiagonal = NULL;
51128f357e3SAlex Fikl     }
51228f357e3SAlex Fikl     if (shell->ops->copy) {
51328f357e3SAlex Fikl       Y->ops->copy = shell->ops->copy;
51428f357e3SAlex Fikl       shell->ops->copy = NULL;
5157fb7d96aSJed Brown     }
5167fb7d96aSJed Brown     shell->usingscaled = PETSC_FALSE;
517ef66eb69SBarry Smith   }
518ef66eb69SBarry Smith   PetscFunctionReturn(0);
519ef66eb69SBarry Smith }
520ef66eb69SBarry Smith 
521cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Shell(Mat, MatType,MatReuse,Mat*);
522b951964fSBarry Smith 
5233b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool  *missing,PetscInt *d)
5243b49f96aSBarry Smith {
5253b49f96aSBarry Smith   PetscFunctionBegin;
5263b49f96aSBarry Smith   *missing = PETSC_FALSE;
5273b49f96aSBarry Smith   PetscFunctionReturn(0);
5283b49f96aSBarry Smith }
5293b49f96aSBarry Smith 
53009dc0095SBarry Smith static struct _MatOps MatOps_Values = {0,
53120563c6bSBarry Smith                                        0,
53220563c6bSBarry Smith                                        0,
53320563c6bSBarry Smith                                        0,
53497304618SKris Buschelman                                 /* 4*/ 0,
53520563c6bSBarry Smith                                        0,
536b951964fSBarry Smith                                        0,
537b951964fSBarry Smith                                        0,
538b951964fSBarry Smith                                        0,
539b951964fSBarry Smith                                        0,
54097304618SKris Buschelman                                 /*10*/ 0,
541b951964fSBarry Smith                                        0,
542b951964fSBarry Smith                                        0,
543b951964fSBarry Smith                                        0,
544b951964fSBarry Smith                                        0,
54597304618SKris Buschelman                                 /*15*/ 0,
546b951964fSBarry Smith                                        0,
547b951964fSBarry Smith                                        0,
5488fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
549b951964fSBarry Smith                                        0,
55097304618SKris Buschelman                                 /*20*/ 0,
551ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
552b951964fSBarry Smith                                        0,
553b951964fSBarry Smith                                        0,
554d519adbfSMatthew Knepley                                 /*24*/ 0,
555b951964fSBarry Smith                                        0,
556b951964fSBarry Smith                                        0,
557b951964fSBarry Smith                                        0,
558b951964fSBarry Smith                                        0,
559d519adbfSMatthew Knepley                                 /*29*/ 0,
560b951964fSBarry Smith                                        0,
561273d9f13SBarry Smith                                        0,
562b951964fSBarry Smith                                        0,
563b951964fSBarry Smith                                        0,
564cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
565b951964fSBarry Smith                                        0,
566b951964fSBarry Smith                                        0,
56709dc0095SBarry Smith                                        0,
56809dc0095SBarry Smith                                        0,
569d519adbfSMatthew Knepley                                 /*39*/ 0,
57009dc0095SBarry Smith                                        0,
57109dc0095SBarry Smith                                        0,
57209dc0095SBarry Smith                                        0,
573cb8c8a77SBarry Smith                                        MatCopy_Shell,
574d519adbfSMatthew Knepley                                 /*44*/ 0,
575ef66eb69SBarry Smith                                        MatScale_Shell,
576ef66eb69SBarry Smith                                        MatShift_Shell,
5776464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
57809dc0095SBarry Smith                                        0,
579f73d5cc4SBarry Smith                                 /*49*/ 0,
58009dc0095SBarry Smith                                        0,
58109dc0095SBarry Smith                                        0,
58209dc0095SBarry Smith                                        0,
58309dc0095SBarry Smith                                        0,
584d519adbfSMatthew Knepley                                 /*54*/ 0,
58509dc0095SBarry Smith                                        0,
58609dc0095SBarry Smith                                        0,
58709dc0095SBarry Smith                                        0,
58809dc0095SBarry Smith                                        0,
589d519adbfSMatthew Knepley                                 /*59*/ 0,
590b9b97703SBarry Smith                                        MatDestroy_Shell,
59109dc0095SBarry Smith                                        0,
592357abbc8SBarry Smith                                        0,
593273d9f13SBarry Smith                                        0,
594d519adbfSMatthew Knepley                                 /*64*/ 0,
595273d9f13SBarry Smith                                        0,
596273d9f13SBarry Smith                                        0,
597273d9f13SBarry Smith                                        0,
598273d9f13SBarry Smith                                        0,
599d519adbfSMatthew Knepley                                 /*69*/ 0,
600273d9f13SBarry Smith                                        0,
601c87e5d42SMatthew Knepley                                        MatConvert_Shell,
602273d9f13SBarry Smith                                        0,
60397304618SKris Buschelman                                        0,
604d519adbfSMatthew Knepley                                 /*74*/ 0,
60597304618SKris Buschelman                                        0,
60697304618SKris Buschelman                                        0,
60797304618SKris Buschelman                                        0,
60897304618SKris Buschelman                                        0,
609d519adbfSMatthew Knepley                                 /*79*/ 0,
61097304618SKris Buschelman                                        0,
61197304618SKris Buschelman                                        0,
61297304618SKris Buschelman                                        0,
613865e5f61SKris Buschelman                                        0,
614d519adbfSMatthew Knepley                                 /*84*/ 0,
615865e5f61SKris Buschelman                                        0,
616865e5f61SKris Buschelman                                        0,
617865e5f61SKris Buschelman                                        0,
618865e5f61SKris Buschelman                                        0,
619d519adbfSMatthew Knepley                                 /*89*/ 0,
620865e5f61SKris Buschelman                                        0,
621865e5f61SKris Buschelman                                        0,
622865e5f61SKris Buschelman                                        0,
623865e5f61SKris Buschelman                                        0,
624d519adbfSMatthew Knepley                                 /*94*/ 0,
625865e5f61SKris Buschelman                                        0,
626865e5f61SKris Buschelman                                        0,
6273964eb88SJed Brown                                        0,
6283964eb88SJed Brown                                        0,
6293964eb88SJed Brown                                 /*99*/ 0,
6303964eb88SJed Brown                                        0,
6313964eb88SJed Brown                                        0,
6323964eb88SJed Brown                                        0,
6333964eb88SJed Brown                                        0,
6343964eb88SJed Brown                                /*104*/ 0,
6353964eb88SJed Brown                                        0,
6363964eb88SJed Brown                                        0,
6373964eb88SJed Brown                                        0,
6383964eb88SJed Brown                                        0,
6393964eb88SJed Brown                                /*109*/ 0,
6403964eb88SJed Brown                                        0,
6413964eb88SJed Brown                                        0,
6423964eb88SJed Brown                                        0,
6433b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
6443964eb88SJed Brown                                /*114*/ 0,
6453964eb88SJed Brown                                        0,
6463964eb88SJed Brown                                        0,
6473964eb88SJed Brown                                        0,
6483964eb88SJed Brown                                        0,
6493964eb88SJed Brown                                /*119*/ 0,
6503964eb88SJed Brown                                        0,
6513964eb88SJed Brown                                        0,
6523964eb88SJed Brown                                        0,
6533964eb88SJed Brown                                        0,
6543964eb88SJed Brown                                /*124*/ 0,
6553964eb88SJed Brown                                        0,
6563964eb88SJed Brown                                        0,
6573964eb88SJed Brown                                        0,
6583964eb88SJed Brown                                        0,
6593964eb88SJed Brown                                /*129*/ 0,
6603964eb88SJed Brown                                        0,
6613964eb88SJed Brown                                        0,
6623964eb88SJed Brown                                        0,
6633964eb88SJed Brown                                        0,
6643964eb88SJed Brown                                /*134*/ 0,
6653964eb88SJed Brown                                        0,
6663964eb88SJed Brown                                        0,
6673964eb88SJed Brown                                        0,
6683964eb88SJed Brown                                        0,
6693964eb88SJed Brown                                /*139*/ 0,
670f9426fe0SMark Adams                                        0,
6713964eb88SJed Brown                                        0
6723964eb88SJed Brown };
673273d9f13SBarry Smith 
6740bad9183SKris Buschelman /*MC
675fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
6760bad9183SKris Buschelman 
6770bad9183SKris Buschelman   Level: advanced
6780bad9183SKris Buschelman 
6790bad9183SKris Buschelman .seealso: MatCreateShell
6800bad9183SKris Buschelman M*/
6810bad9183SKris Buschelman 
6828cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
683273d9f13SBarry Smith {
684273d9f13SBarry Smith   Mat_Shell      *b;
685dfbe8321SBarry Smith   PetscErrorCode ierr;
686273d9f13SBarry Smith 
687273d9f13SBarry Smith   PetscFunctionBegin;
688273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
689273d9f13SBarry Smith 
690b00a9115SJed Brown   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
691273d9f13SBarry Smith   A->data = (void*)b;
692273d9f13SBarry Smith 
69326283091SBarry Smith   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
69426283091SBarry Smith   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
695273d9f13SBarry Smith 
696273d9f13SBarry Smith   b->ctx           = 0;
697ef66eb69SBarry Smith   b->vshift        = 0.0;
698ef66eb69SBarry Smith   b->vscale        = 1.0;
699273d9f13SBarry Smith   A->assembled     = PETSC_TRUE;
700210f0121SBarry Smith   A->preallocated  = PETSC_FALSE;
7012205254eSKarl Rupp 
70217667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
703273d9f13SBarry Smith   PetscFunctionReturn(0);
704273d9f13SBarry Smith }
705e51e0e81SBarry Smith 
7064b828684SBarry Smith /*@C
707052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
708ff756334SLois Curfman McInnes    private data storage format.
709e51e0e81SBarry Smith 
710c7fcc2eaSBarry Smith   Collective on MPI_Comm
711c7fcc2eaSBarry Smith 
712e51e0e81SBarry Smith    Input Parameters:
713c7fcc2eaSBarry Smith +  comm - MPI communicator
714c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
715c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
716c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
717c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
718c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
719e51e0e81SBarry Smith 
720ff756334SLois Curfman McInnes    Output Parameter:
72144cd7ae7SLois Curfman McInnes .  A - the matrix
722e51e0e81SBarry Smith 
723ff2fd236SBarry Smith    Level: advanced
724ff2fd236SBarry Smith 
725f39d1f56SLois Curfman McInnes   Usage:
7267b2a1423SBarry Smith $    extern int mult(Mat,Vec,Vec);
727f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
728c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
729f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
730f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
731f39d1f56SLois Curfman McInnes 
732ff756334SLois Curfman McInnes    Notes:
733ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
734ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
735ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
736e51e0e81SBarry Smith 
737daf670e6SBarry Smith    Fortran Notes: To use this from Fortran with a ctx you must write an interface definition for this
738daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
739daf670e6SBarry Smith     in as the ctx argument.
740f38a8d56SBarry Smith 
741f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
742f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
743645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
744645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
745645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
746645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
747645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
748645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
749645985a0SLois Curfman McInnes    For example,
750f39d1f56SLois Curfman McInnes 
751f39d1f56SLois Curfman McInnes $
752f39d1f56SLois Curfman McInnes $     Vec x, y
7537b2a1423SBarry Smith $     extern int mult(Mat,Vec,Vec);
754645985a0SLois Curfman McInnes $     Mat A
755f39d1f56SLois Curfman McInnes $
756c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
757c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
758f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
759c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
760c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
761c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
762645985a0SLois Curfman McInnes $     MatMult(A,x,y);
763645985a0SLois Curfman McInnes $     MatDestroy(A);
764f39d1f56SLois Curfman McInnes $     VecDestroy(y); VecDestroy(x);
765645985a0SLois Curfman McInnes $
766e51e0e81SBarry Smith 
7670b627109SLois Curfman McInnes .keywords: matrix, shell, create
7680b627109SLois Curfman McInnes 
769ab50ec6bSBarry Smith .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
770e51e0e81SBarry Smith @*/
7717087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
772e51e0e81SBarry Smith {
773dfbe8321SBarry Smith   PetscErrorCode ierr;
774ed3cc1f0SBarry Smith 
7753a40ed3dSBarry Smith   PetscFunctionBegin;
776f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
777f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
778273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
779273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
7800fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
781273d9f13SBarry Smith   PetscFunctionReturn(0);
782c7fcc2eaSBarry Smith }
783c7fcc2eaSBarry Smith 
784c6866cfdSSatish Balay /*@
785273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
786c7fcc2eaSBarry Smith 
7873f9fe445SBarry Smith    Logically Collective on Mat
788c7fcc2eaSBarry Smith 
789273d9f13SBarry Smith     Input Parameters:
790273d9f13SBarry Smith +   mat - the shell matrix
791273d9f13SBarry Smith -   ctx - the context
792273d9f13SBarry Smith 
793273d9f13SBarry Smith    Level: advanced
794273d9f13SBarry Smith 
795daf670e6SBarry Smith    Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this
796daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
797273d9f13SBarry Smith 
798273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
7990bc0a719SBarry Smith @*/
8007087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
801273d9f13SBarry Smith {
802273d9f13SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
803dfbe8321SBarry Smith   PetscErrorCode ierr;
804ace3abfcSBarry Smith   PetscBool      flg;
805273d9f13SBarry Smith 
806273d9f13SBarry Smith   PetscFunctionBegin;
8070700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
808251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
809273d9f13SBarry Smith   if (flg) {
810273d9f13SBarry Smith     shell->ctx = ctx;
811ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
8123a40ed3dSBarry Smith   PetscFunctionReturn(0);
813e51e0e81SBarry Smith }
814e51e0e81SBarry Smith 
815c16cb8f2SBarry Smith /*@C
816f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
817f3b1f45cSBarry Smith 
818f3b1f45cSBarry Smith    Logically Collective on Mat
819f3b1f45cSBarry Smith 
820f3b1f45cSBarry Smith     Input Parameters:
821f3b1f45cSBarry Smith +   mat - the shell matrix
822f3b1f45cSBarry Smith .   f - the function
823f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
824f3b1f45cSBarry Smith -   ctx - an optional context for the function
825f3b1f45cSBarry Smith 
826f3b1f45cSBarry Smith    Output Parameter:
827f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
828f3b1f45cSBarry Smith 
829f3b1f45cSBarry Smith    Options Database:
830f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
831f3b1f45cSBarry Smith 
832f3b1f45cSBarry Smith    Level: advanced
833f3b1f45cSBarry Smith 
834f3b1f45cSBarry Smith    Fortran Notes: Not supported from Fortran
835f3b1f45cSBarry Smith 
836f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose()
837f3b1f45cSBarry Smith @*/
838f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
839f3b1f45cSBarry Smith {
840f3b1f45cSBarry Smith   PetscErrorCode ierr;
841f3b1f45cSBarry Smith   PetscInt       m,n;
842f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
843f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
844*74e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
845f3b1f45cSBarry Smith 
846f3b1f45cSBarry Smith   PetscFunctionBegin;
847f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
848f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr);
849f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
850f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr);
851f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
852f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
853f3b1f45cSBarry Smith 
854f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr);
855f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mat,&Dmat);CHKERRQ(ierr);
856f3b1f45cSBarry Smith 
857f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
858f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
859f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
860f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
861f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
862f3b1f45cSBarry Smith     flag = PETSC_FALSE;
863f3b1f45cSBarry Smith     if (v) {
864f3b1f45cSBarry Smith       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));
865f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
866f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
867f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
868f3b1f45cSBarry Smith     }
869f3b1f45cSBarry Smith   } else if (v) {
870f3b1f45cSBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");
871f3b1f45cSBarry Smith   }
872f3b1f45cSBarry Smith   if (flg) *flg = flag;
873f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
874f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
875f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
876f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
877f3b1f45cSBarry Smith   PetscFunctionReturn(0);
878f3b1f45cSBarry Smith }
879f3b1f45cSBarry Smith 
880f3b1f45cSBarry Smith /*@C
881f3b1f45cSBarry Smith     MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
882f3b1f45cSBarry Smith 
883f3b1f45cSBarry Smith    Logically Collective on Mat
884f3b1f45cSBarry Smith 
885f3b1f45cSBarry Smith     Input Parameters:
886f3b1f45cSBarry Smith +   mat - the shell matrix
887f3b1f45cSBarry Smith .   f - the function
888f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
889f3b1f45cSBarry Smith -   ctx - an optional context for the function
890f3b1f45cSBarry Smith 
891f3b1f45cSBarry Smith    Output Parameter:
892f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
893f3b1f45cSBarry Smith 
894f3b1f45cSBarry Smith    Options Database:
895f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
896f3b1f45cSBarry Smith 
897f3b1f45cSBarry Smith    Level: advanced
898f3b1f45cSBarry Smith 
899f3b1f45cSBarry Smith    Fortran Notes: Not supported from Fortran
900f3b1f45cSBarry Smith 
901f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult()
902f3b1f45cSBarry Smith @*/
903f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
904f3b1f45cSBarry Smith {
905f3b1f45cSBarry Smith   PetscErrorCode ierr;
906f3b1f45cSBarry Smith   Vec            x,y,z;
907f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
908f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
909f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
910*74e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
911f3b1f45cSBarry Smith 
912f3b1f45cSBarry Smith   PetscFunctionBegin;
913f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
914f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr);
915f3b1f45cSBarry Smith   ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr);
916f3b1f45cSBarry Smith   ierr = VecDuplicate(y,&z);CHKERRQ(ierr);
917f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
918f3b1f45cSBarry Smith   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
919f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr);
920f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
921f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
922f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr);
923f3b1f45cSBarry Smith   ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr);
924f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperatorTranspose(mat,&Dmat);CHKERRQ(ierr);
925f3b1f45cSBarry Smith 
926f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
927f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
928f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
929f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
930f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
931f3b1f45cSBarry Smith     flag = PETSC_FALSE;
932f3b1f45cSBarry Smith     if (v) {
933f3b1f45cSBarry Smith       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));
934f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
935f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
936f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
937f3b1f45cSBarry Smith     }
938f3b1f45cSBarry Smith   } else if (v) {
939f3b1f45cSBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");
940f3b1f45cSBarry Smith   }
941f3b1f45cSBarry Smith   if (flg) *flg = flag;
942f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
943f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
944f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
945f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
946f3b1f45cSBarry Smith   ierr = VecDestroy(&x);CHKERRQ(ierr);
947f3b1f45cSBarry Smith   ierr = VecDestroy(&y);CHKERRQ(ierr);
948f3b1f45cSBarry Smith   ierr = VecDestroy(&z);CHKERRQ(ierr);
949f3b1f45cSBarry Smith   PetscFunctionReturn(0);
950f3b1f45cSBarry Smith }
951f3b1f45cSBarry Smith 
952f3b1f45cSBarry Smith /*@C
9533a3eedf2SBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for
9543a3eedf2SBarry Smith                            a shell matrix.
955e51e0e81SBarry Smith 
9563f9fe445SBarry Smith    Logically Collective on Mat
957fee21e36SBarry Smith 
958c7fcc2eaSBarry Smith     Input Parameters:
959c7fcc2eaSBarry Smith +   mat - the shell matrix
960c7fcc2eaSBarry Smith .   op - the name of the operation
961c7fcc2eaSBarry Smith -   f - the function that provides the operation.
962c7fcc2eaSBarry Smith 
96315091d37SBarry Smith    Level: advanced
96415091d37SBarry Smith 
965fae171e0SBarry Smith     Usage:
966e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
967f39d1f56SLois Curfman McInnes $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
968c134de8dSSatish Balay $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
9690b627109SLois Curfman McInnes 
970a62d957aSLois Curfman McInnes     Notes:
971e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
9721c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
973a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
9741c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
975a62d957aSLois Curfman McInnes 
976a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
977deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
978deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
979deebb3c3SLois Curfman McInnes     routines, e.g.,
980a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
981a62d957aSLois Curfman McInnes 
9824aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
9834aa34b0aSBarry Smith     nonzero on failure.
9844aa34b0aSBarry Smith 
985a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
986a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
987a62d957aSLois Curfman McInnes     set by MatCreateShell().
988a62d957aSLois Curfman McInnes 
9892a7a6963SBarry Smith     Fortran Notes: For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
990501d9185SBarry Smith        generate a matrix. See src/mat/examples/tests/ex120f.F
991501d9185SBarry Smith 
992a62d957aSLois Curfman McInnes .keywords: matrix, shell, set, operation
993a62d957aSLois Curfman McInnes 
994ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
995e51e0e81SBarry Smith @*/
9967087cfbeSBarry Smith PetscErrorCode  MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
997e51e0e81SBarry Smith {
998dfbe8321SBarry Smith   PetscErrorCode ierr;
999ace3abfcSBarry Smith   PetscBool      flg;
1000273d9f13SBarry Smith 
10013a40ed3dSBarry Smith   PetscFunctionBegin;
10020700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
10035edf6516SJed Brown   switch (op) {
10045edf6516SJed Brown   case MATOP_DESTROY:
1005251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1006273d9f13SBarry Smith     if (flg) {
1007a62d957aSLois Curfman McInnes       Mat_Shell *shell = (Mat_Shell*)mat->data;
100828f357e3SAlex Fikl       shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
10096849ba73SBarry Smith     } else mat->ops->destroy = (PetscErrorCode (*)(Mat))f;
10105edf6516SJed Brown     break;
10116464bf51SAlex Fikl   case MATOP_DIAGONAL_SET:
10126464bf51SAlex Fikl     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
10136464bf51SAlex Fikl     if (flg) {
10146464bf51SAlex Fikl       Mat_Shell *shell = (Mat_Shell*)mat->data;
101528f357e3SAlex Fikl       shell->ops->diagonalset = (PetscErrorCode (*)(Mat,Vec,InsertMode))f;
10166464bf51SAlex Fikl     } else {
10176464bf51SAlex Fikl       mat->ops->diagonalset = (PetscErrorCode (*)(Mat,Vec,InsertMode))f;
10186464bf51SAlex Fikl     }
10196464bf51SAlex Fikl     break;
10205edf6516SJed Brown   case MATOP_VIEW:
102140a5a6c4SBarry Smith     if (!mat->ops->viewnative) {
102240a5a6c4SBarry Smith       mat->ops->viewnative = mat->ops->view;
102340a5a6c4SBarry Smith     }
10245edf6516SJed Brown     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
10255edf6516SJed Brown     break;
10265edf6516SJed Brown   case MATOP_MULT:
10275edf6516SJed Brown     mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1028875c1aa2SLisandro Dalcin     if (!mat->ops->multadd) {
1029875c1aa2SLisandro Dalcin       ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1030875c1aa2SLisandro Dalcin       if (flg) mat->ops->multadd = MatMultAdd_Shell;
1031875c1aa2SLisandro Dalcin     }
10325edf6516SJed Brown     break;
10335edf6516SJed Brown   case MATOP_MULT_TRANSPOSE:
10345edf6516SJed Brown     mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1035875c1aa2SLisandro Dalcin     if (!mat->ops->multtransposeadd) {
1036875c1aa2SLisandro Dalcin       ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1037875c1aa2SLisandro Dalcin       if (flg) mat->ops->multtransposeadd = MatMultTransposeAdd_Shell;
1038875c1aa2SLisandro Dalcin     }
10395edf6516SJed Brown     break;
10405edf6516SJed Brown   default:
10415edf6516SJed Brown     (((void(**)(void))mat->ops)[op]) = f;
1042a62d957aSLois Curfman McInnes   }
10433a40ed3dSBarry Smith   PetscFunctionReturn(0);
1044e51e0e81SBarry Smith }
1045f0479e8cSBarry Smith 
1046d4bb536fSBarry Smith /*@C
1047d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
1048d4bb536fSBarry Smith 
1049c7fcc2eaSBarry Smith     Not Collective
1050c7fcc2eaSBarry Smith 
1051d4bb536fSBarry Smith     Input Parameters:
1052c7fcc2eaSBarry Smith +   mat - the shell matrix
1053c7fcc2eaSBarry Smith -   op - the name of the operation
1054d4bb536fSBarry Smith 
1055d4bb536fSBarry Smith     Output Parameter:
1056d4bb536fSBarry Smith .   f - the function that provides the operation.
1057d4bb536fSBarry Smith 
105815091d37SBarry Smith     Level: advanced
105915091d37SBarry Smith 
1060d4bb536fSBarry Smith     Notes:
1061e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
1062d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
1063d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
1064d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
1065d4bb536fSBarry Smith 
1066d4bb536fSBarry Smith     All user-provided functions have the same calling
1067d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
1068d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
1069d4bb536fSBarry Smith     routines, e.g.,
1070d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1071d4bb536fSBarry Smith 
1072d4bb536fSBarry Smith     Within each user-defined routine, the user should call
1073d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
1074d4bb536fSBarry Smith     set by MatCreateShell().
1075d4bb536fSBarry Smith 
1076d4bb536fSBarry Smith .keywords: matrix, shell, set, operation
1077d4bb536fSBarry Smith 
1078ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
1079d4bb536fSBarry Smith @*/
10807087cfbeSBarry Smith PetscErrorCode  MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
1081d4bb536fSBarry Smith {
1082dfbe8321SBarry Smith   PetscErrorCode ierr;
1083ace3abfcSBarry Smith   PetscBool      flg;
1084273d9f13SBarry Smith 
10853a40ed3dSBarry Smith   PetscFunctionBegin;
10860700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
108728f357e3SAlex Fikl   switch (op) {
108828f357e3SAlex Fikl   case MATOP_DESTROY:
1089251f4c67SDmitry Karpeev     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1090273d9f13SBarry Smith     if (flg) {
1091d4bb536fSBarry Smith       Mat_Shell *shell = (Mat_Shell*)mat->data;
109228f357e3SAlex Fikl       *f = (void (*)(void))shell->ops->destroy;
1093c7fcc2eaSBarry Smith     } else {
1094c134de8dSSatish Balay       *f = (void (*)(void))mat->ops->destroy;
1095d4bb536fSBarry Smith     }
109628f357e3SAlex Fikl     break;
109728f357e3SAlex Fikl   case MATOP_DIAGONAL_SET:
109828f357e3SAlex Fikl     ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
109928f357e3SAlex Fikl     if (flg) {
110028f357e3SAlex Fikl       Mat_Shell *shell = (Mat_Shell*)mat->data;
110128f357e3SAlex Fikl       *f = (void (*)(void))shell->ops->diagonalset;
1102c7fcc2eaSBarry Smith     } else {
110328f357e3SAlex Fikl       *f = (void (*)(void))mat->ops->diagonalset;
110428f357e3SAlex Fikl     }
110528f357e3SAlex Fikl     break;
110628f357e3SAlex Fikl   case MATOP_VIEW:
110728f357e3SAlex Fikl     *f = (void (*)(void))mat->ops->view;
110828f357e3SAlex Fikl     break;
110928f357e3SAlex Fikl   default:
1110c134de8dSSatish Balay     *f = (((void (**)(void))mat->ops)[op]);
1111d4bb536fSBarry Smith   }
11123a40ed3dSBarry Smith   PetscFunctionReturn(0);
1113d4bb536fSBarry Smith }
1114d4bb536fSBarry Smith 
1115