xref: /petsc/src/mat/impls/shell/shell.c (revision b45d2f2cb7e031d9c0de5873eca80614ca7b863b)
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 
8*b45d2f2cSJed Brown #include <petsc-private/matimpl.h>        /*I "petscmat.h" I*/
9*b45d2f2cSJed 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);
16ef66eb69SBarry Smith   PetscScalar    vscale,vshift;
178fe8eb27SJed Brown   Vec            dshift;
188fe8eb27SJed Brown   Vec            left,right;
198fe8eb27SJed Brown   Vec            dshift_owned,left_owned,right_owned;
208fe8eb27SJed Brown   Vec            left_work,right_work;
218fe8eb27SJed Brown   PetscBool      usingscaled;
2220563c6bSBarry Smith   void           *ctx;
2388cf3e7dSBarry Smith } Mat_Shell;
248fe8eb27SJed Brown /*
258fe8eb27SJed Brown  The most general expression for the matrix is
268fe8eb27SJed Brown 
278fe8eb27SJed Brown  S = L (a A + B) R
288fe8eb27SJed Brown 
298fe8eb27SJed Brown  where
308fe8eb27SJed Brown  A is the matrix defined by the user's function
318fe8eb27SJed Brown  a is a scalar multiple
328fe8eb27SJed Brown  L is left scaling
338fe8eb27SJed Brown  R is right scaling
348fe8eb27SJed Brown  B is a diagonal shift defined by
358fe8eb27SJed Brown    diag(dshift) if the vector dshift is non-NULL
368fe8eb27SJed Brown    vscale*identity otherwise
378fe8eb27SJed Brown 
388fe8eb27SJed Brown  The following identities apply:
398fe8eb27SJed Brown 
408fe8eb27SJed Brown  Scale by c:
418fe8eb27SJed Brown   c [L (a A + B) R] = L [(a c) A + c B] R
428fe8eb27SJed Brown 
438fe8eb27SJed Brown  Shift by c:
448fe8eb27SJed Brown   [L (a A + B) R] + c = L [a A + (B + c Linv Rinv)] R
458fe8eb27SJed Brown 
468fe8eb27SJed Brown  Diagonal scaling is achieved by simply multiplying with existing L and R vectors
478fe8eb27SJed Brown 
488fe8eb27SJed Brown  In the data structure:
498fe8eb27SJed Brown 
508fe8eb27SJed Brown  vscale=1.0  means no special scaling will be applied
518fe8eb27SJed Brown  dshift=NULL means a constant diagonal shift (fall back to vshift)
528fe8eb27SJed Brown  vshift=0.0  means no constant diagonal shift, note that vshift is only used if dshift is NULL
538fe8eb27SJed Brown */
548fe8eb27SJed Brown 
558fe8eb27SJed Brown static PetscErrorCode MatMult_Shell(Mat,Vec,Vec);
568fe8eb27SJed Brown static PetscErrorCode MatMultTranspose_Shell(Mat,Vec,Vec);
578fe8eb27SJed Brown static PetscErrorCode MatGetDiagonal_Shell(Mat,Vec);
588fe8eb27SJed Brown 
598fe8eb27SJed Brown #undef __FUNCT__
608fe8eb27SJed Brown #define __FUNCT__ "MatShellUseScaledMethods"
618fe8eb27SJed Brown static PetscErrorCode MatShellUseScaledMethods(Mat Y)
628fe8eb27SJed Brown {
638fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)Y->data;
648fe8eb27SJed Brown 
658fe8eb27SJed Brown   PetscFunctionBegin;
668fe8eb27SJed Brown   if (shell->usingscaled) PetscFunctionReturn(0);
678fe8eb27SJed Brown   shell->mult  = Y->ops->mult;
688fe8eb27SJed Brown   Y->ops->mult = MatMult_Shell;
698fe8eb27SJed Brown   if (Y->ops->multtranspose) {
708fe8eb27SJed Brown     shell->multtranspose  = Y->ops->multtranspose;
718fe8eb27SJed Brown     Y->ops->multtranspose = MatMultTranspose_Shell;
728fe8eb27SJed Brown   }
738fe8eb27SJed Brown   if (Y->ops->getdiagonal) {
748fe8eb27SJed Brown     shell->getdiagonal  = Y->ops->getdiagonal;
758fe8eb27SJed Brown     Y->ops->getdiagonal = MatGetDiagonal_Shell;
768fe8eb27SJed Brown   }
778fe8eb27SJed Brown   shell->usingscaled = PETSC_TRUE;
788fe8eb27SJed Brown   PetscFunctionReturn(0);
798fe8eb27SJed Brown }
808fe8eb27SJed Brown 
818fe8eb27SJed Brown #undef __FUNCT__
828fe8eb27SJed Brown #define __FUNCT__ "MatShellPreScaleLeft"
838fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
848fe8eb27SJed Brown {
858fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)A->data;
868fe8eb27SJed Brown   PetscErrorCode ierr;
878fe8eb27SJed Brown 
888fe8eb27SJed Brown   PetscFunctionBegin;
89d63f877fSJed Brown   *xx = PETSC_NULL;
908fe8eb27SJed Brown   if (!shell->left) {
918fe8eb27SJed Brown     *xx = x;
928fe8eb27SJed Brown   } else {
938fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
948fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
958fe8eb27SJed Brown     *xx = shell->left_work;
968fe8eb27SJed Brown   }
978fe8eb27SJed Brown   PetscFunctionReturn(0);
988fe8eb27SJed Brown }
998fe8eb27SJed Brown 
1008fe8eb27SJed Brown #undef __FUNCT__
1018fe8eb27SJed Brown #define __FUNCT__ "MatShellPreScaleRight"
1028fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1038fe8eb27SJed Brown {
1048fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)A->data;
1058fe8eb27SJed Brown   PetscErrorCode ierr;
1068fe8eb27SJed Brown 
1078fe8eb27SJed Brown   PetscFunctionBegin;
108d63f877fSJed Brown   *xx = PETSC_NULL;
1098fe8eb27SJed Brown   if (!shell->right) {
1108fe8eb27SJed Brown     *xx = x;
1118fe8eb27SJed Brown   } else {
1128fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
1138fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
1148fe8eb27SJed Brown     *xx = shell->right_work;
1158fe8eb27SJed Brown   }
1168fe8eb27SJed Brown   PetscFunctionReturn(0);
1178fe8eb27SJed Brown }
1188fe8eb27SJed Brown 
1198fe8eb27SJed Brown #undef __FUNCT__
1208fe8eb27SJed Brown #define __FUNCT__ "MatShellPostScaleLeft"
1218fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1228fe8eb27SJed Brown {
1238fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)A->data;
1248fe8eb27SJed Brown   PetscErrorCode ierr;
1258fe8eb27SJed Brown 
1268fe8eb27SJed Brown   PetscFunctionBegin;
1278fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
1288fe8eb27SJed Brown   PetscFunctionReturn(0);
1298fe8eb27SJed Brown }
1308fe8eb27SJed Brown 
1318fe8eb27SJed Brown #undef __FUNCT__
1328fe8eb27SJed Brown #define __FUNCT__ "MatShellPostScaleRight"
1338fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
1348fe8eb27SJed Brown {
1358fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)A->data;
1368fe8eb27SJed Brown   PetscErrorCode ierr;
1378fe8eb27SJed Brown 
1388fe8eb27SJed Brown   PetscFunctionBegin;
1398fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
1408fe8eb27SJed Brown   PetscFunctionReturn(0);
1418fe8eb27SJed Brown }
1428fe8eb27SJed Brown 
1438fe8eb27SJed Brown #undef __FUNCT__
1448fe8eb27SJed Brown #define __FUNCT__ "MatShellShiftAndScale"
1458fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
1468fe8eb27SJed Brown {
1478fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)A->data;
1488fe8eb27SJed Brown   PetscErrorCode ierr;
1498fe8eb27SJed Brown 
1508fe8eb27SJed Brown   PetscFunctionBegin;
1518fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
1528fe8eb27SJed Brown     PetscInt          i,m;
1538fe8eb27SJed Brown     const PetscScalar *x,*d;
1548fe8eb27SJed Brown     PetscScalar       *y;
1558fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
1568fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1578fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1588fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
1598fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
1608fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1618fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1628fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
163880538faSHong Zhang   } else if (PetscAbsScalar(shell->vshift) != 0) {
1648fe8eb27SJed Brown     ierr = VecAXPBY(Y,shell->vshift,shell->vscale,X);CHKERRQ(ierr);
165027c5fb5SJed Brown   } else if (shell->vscale != 1.0) {
166027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
1678fe8eb27SJed Brown   }
1688fe8eb27SJed Brown   PetscFunctionReturn(0);
1698fe8eb27SJed Brown }
170e51e0e81SBarry Smith 
171711e205bSSatish Balay #undef __FUNCT__
172711e205bSSatish Balay #define __FUNCT__ "MatShellGetContext"
1739d225801SJed Brown /*@
174a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
175b4fd4287SBarry Smith 
176c7fcc2eaSBarry Smith     Not Collective
177c7fcc2eaSBarry Smith 
178b4fd4287SBarry Smith     Input Parameter:
179b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
180b4fd4287SBarry Smith 
181b4fd4287SBarry Smith     Output Parameter:
182b4fd4287SBarry Smith .   ctx - the user provided context
183b4fd4287SBarry Smith 
18415091d37SBarry Smith     Level: advanced
18515091d37SBarry Smith 
186a62d957aSLois Curfman McInnes     Notes:
187a62d957aSLois Curfman McInnes     This routine is intended for use within various shell matrix routines,
188a62d957aSLois Curfman McInnes     as set with MatShellSetOperation().
189a62d957aSLois Curfman McInnes 
190a62d957aSLois Curfman McInnes .keywords: matrix, shell, get, context
191a62d957aSLois Curfman McInnes 
192ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
1930bc0a719SBarry Smith @*/
1948fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
195b4fd4287SBarry Smith {
196dfbe8321SBarry Smith   PetscErrorCode ierr;
197ace3abfcSBarry Smith   PetscBool      flg;
198273d9f13SBarry Smith 
1993a40ed3dSBarry Smith   PetscFunctionBegin;
2000700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2014482741eSBarry Smith   PetscValidPointer(ctx,2);
202273d9f13SBarry Smith   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
203940183f3SBarry Smith   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
204940183f3SBarry Smith   else SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
2053a40ed3dSBarry Smith   PetscFunctionReturn(0);
206b4fd4287SBarry Smith }
207b4fd4287SBarry Smith 
208711e205bSSatish Balay #undef __FUNCT__
209711e205bSSatish Balay #define __FUNCT__ "MatDestroy_Shell"
210dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
211e51e0e81SBarry Smith {
212dfbe8321SBarry Smith   PetscErrorCode ierr;
213bf0cc555SLisandro Dalcin   Mat_Shell      *shell = (Mat_Shell*)mat->data;
214ed3cc1f0SBarry Smith 
2153a40ed3dSBarry Smith   PetscFunctionBegin;
216bf0cc555SLisandro Dalcin   if (shell->destroy) {
217bf0cc555SLisandro Dalcin     ierr = (*shell->destroy)(mat);CHKERRQ(ierr);
218bf0cc555SLisandro Dalcin   }
2198fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_owned);CHKERRQ(ierr);
2208fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_owned);CHKERRQ(ierr);
2218fe8eb27SJed Brown   ierr = VecDestroy(&shell->dshift_owned);CHKERRQ(ierr);
2228fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
2238fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
224bf0cc555SLisandro Dalcin   ierr = PetscFree(mat->data);CHKERRQ(ierr);
2253a40ed3dSBarry Smith   PetscFunctionReturn(0);
226e51e0e81SBarry Smith }
227e51e0e81SBarry Smith 
228711e205bSSatish Balay #undef __FUNCT__
229ef66eb69SBarry Smith #define __FUNCT__ "MatMult_Shell"
230dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
231ef66eb69SBarry Smith {
232ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
233dfbe8321SBarry Smith   PetscErrorCode ierr;
23425578ef6SJed Brown   Vec            xx;
235ef66eb69SBarry Smith 
236ef66eb69SBarry Smith   PetscFunctionBegin;
2378fe8eb27SJed Brown   ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr);
2388fe8eb27SJed Brown   ierr = (*shell->mult)(A,xx,y);CHKERRQ(ierr);
2398fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
2408fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
241ef66eb69SBarry Smith   PetscFunctionReturn(0);
242ef66eb69SBarry Smith }
243ef66eb69SBarry Smith 
244ef66eb69SBarry Smith #undef __FUNCT__
24518be62a5SSatish Balay #define __FUNCT__ "MatMultTranspose_Shell"
24618be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
24718be62a5SSatish Balay {
24818be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
24918be62a5SSatish Balay   PetscErrorCode ierr;
25025578ef6SJed Brown   Vec            xx;
25118be62a5SSatish Balay 
25218be62a5SSatish Balay   PetscFunctionBegin;
2538fe8eb27SJed Brown   ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr);
2548fe8eb27SJed Brown   ierr = (*shell->multtranspose)(A,xx,y);CHKERRQ(ierr);
2558fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
2568fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
25718be62a5SSatish Balay   PetscFunctionReturn(0);
25818be62a5SSatish Balay }
25918be62a5SSatish Balay 
26018be62a5SSatish Balay #undef __FUNCT__
26118be62a5SSatish Balay #define __FUNCT__ "MatGetDiagonal_Shell"
26218be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
26318be62a5SSatish Balay {
26418be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
26518be62a5SSatish Balay   PetscErrorCode ierr;
26618be62a5SSatish Balay 
26718be62a5SSatish Balay   PetscFunctionBegin;
26818be62a5SSatish Balay   ierr = (*shell->getdiagonal)(A,v);CHKERRQ(ierr);
26918be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
2708fe8eb27SJed Brown   if (shell->dshift) {
2718fe8eb27SJed Brown     ierr = VecPointwiseMult(v,v,shell->dshift);CHKERRQ(ierr);
2728fe8eb27SJed Brown   } else {
27318be62a5SSatish Balay     ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
27418be62a5SSatish Balay   }
2758fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
2768fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
27718be62a5SSatish Balay   PetscFunctionReturn(0);
27818be62a5SSatish Balay }
27918be62a5SSatish Balay 
28018be62a5SSatish Balay #undef __FUNCT__
281ef66eb69SBarry Smith #define __FUNCT__ "MatShift_Shell"
282f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
283ef66eb69SBarry Smith {
284ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell*)Y->data;
2858fe8eb27SJed Brown   PetscErrorCode ierr;
286b24ad042SBarry Smith 
287ef66eb69SBarry Smith   PetscFunctionBegin;
2888fe8eb27SJed Brown   if (shell->left || shell->right || shell->dshift) {
2898fe8eb27SJed Brown     if (!shell->dshift) {
2908fe8eb27SJed Brown       if (!shell->dshift_owned) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift_owned);CHKERRQ(ierr);}
2918fe8eb27SJed Brown       shell->dshift = shell->dshift_owned;
2928fe8eb27SJed Brown       ierr = VecSet(shell->dshift,shell->vshift+a);CHKERRQ(ierr);
2938fe8eb27SJed Brown     } else {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);}
2948fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
2958fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
2968fe8eb27SJed Brown   } else shell->vshift += a;
2978fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
298ef66eb69SBarry Smith   PetscFunctionReturn(0);
299ef66eb69SBarry Smith }
300ef66eb69SBarry Smith 
301ef66eb69SBarry Smith #undef __FUNCT__
302ef66eb69SBarry Smith #define __FUNCT__ "MatScale_Shell"
303f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
304ef66eb69SBarry Smith {
305ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
3068fe8eb27SJed Brown   PetscErrorCode ierr;
307b24ad042SBarry Smith 
308ef66eb69SBarry Smith   PetscFunctionBegin;
309f4df32b1SMatthew Knepley   shell->vscale *= a;
3108fe8eb27SJed Brown   if (shell->dshift) {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);}
3118fe8eb27SJed Brown   else shell->vshift *= a;
3128fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
3138fe8eb27SJed Brown   PetscFunctionReturn(0);
31418be62a5SSatish Balay }
3158fe8eb27SJed Brown 
3168fe8eb27SJed Brown #undef __FUNCT__
3178fe8eb27SJed Brown #define __FUNCT__ "MatDiagonalScale_Shell"
3188fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
3198fe8eb27SJed Brown {
3208fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell*)Y->data;
3218fe8eb27SJed Brown   PetscErrorCode ierr;
3228fe8eb27SJed Brown 
3238fe8eb27SJed Brown   PetscFunctionBegin;
3248fe8eb27SJed Brown   if (left) {
3258fe8eb27SJed Brown     if (!shell->left_owned) {ierr = VecDuplicate(left,&shell->left_owned);CHKERRQ(ierr);}
3268fe8eb27SJed Brown     if (shell->left) {ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);}
3278fe8eb27SJed Brown     else {
3288fe8eb27SJed Brown       shell->left = shell->left_owned;
3298fe8eb27SJed Brown       ierr = VecCopy(left,shell->left);CHKERRQ(ierr);
33018be62a5SSatish Balay     }
331ef66eb69SBarry Smith   }
3328fe8eb27SJed Brown   if (right) {
3338fe8eb27SJed Brown     if (!shell->right_owned) {ierr = VecDuplicate(right,&shell->right_owned);CHKERRQ(ierr);}
3348fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);}
3358fe8eb27SJed Brown     else {
3368fe8eb27SJed Brown       shell->right = shell->right_owned;
3378fe8eb27SJed Brown       ierr = VecCopy(right,shell->right);CHKERRQ(ierr);
3388fe8eb27SJed Brown     }
3398fe8eb27SJed Brown   }
3408fe8eb27SJed Brown   ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr);
341ef66eb69SBarry Smith   PetscFunctionReturn(0);
342ef66eb69SBarry Smith }
343ef66eb69SBarry Smith 
344ef66eb69SBarry Smith #undef __FUNCT__
345ef66eb69SBarry Smith #define __FUNCT__ "MatAssemblyEnd_Shell"
346dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
347ef66eb69SBarry Smith {
348ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell*)Y->data;
349ef66eb69SBarry Smith 
350ef66eb69SBarry Smith   PetscFunctionBegin;
3518fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
352ef66eb69SBarry Smith     shell->vshift      = 0.0;
353ef66eb69SBarry Smith     shell->vscale      = 1.0;
3548fe8eb27SJed Brown     shell->dshift      = PETSC_NULL;
3558fe8eb27SJed Brown     shell->left        = PETSC_NULL;
3568fe8eb27SJed Brown     shell->right       = PETSC_NULL;
3577fb7d96aSJed Brown     if (shell->mult) {
358ef66eb69SBarry Smith       Y->ops->mult = shell->mult;
3597fb7d96aSJed Brown       shell->mult  = PETSC_NULL;
3607fb7d96aSJed Brown     }
3617fb7d96aSJed Brown     if (shell->multtranspose) {
36218be62a5SSatish Balay       Y->ops->multtranspose = shell->multtranspose;
3637fb7d96aSJed Brown       shell->multtranspose  = PETSC_NULL;
3647fb7d96aSJed Brown     }
3657fb7d96aSJed Brown     if (shell->getdiagonal) {
36618be62a5SSatish Balay       Y->ops->getdiagonal = shell->getdiagonal;
3677fb7d96aSJed Brown       shell->getdiagonal  = PETSC_NULL;
3687fb7d96aSJed Brown     }
3697fb7d96aSJed Brown     shell->usingscaled = PETSC_FALSE;
370ef66eb69SBarry Smith   }
371ef66eb69SBarry Smith   PetscFunctionReturn(0);
372ef66eb69SBarry Smith }
373ef66eb69SBarry Smith 
37409573ac7SBarry Smith extern PetscErrorCode MatConvert_Shell(Mat, const MatType,MatReuse,Mat*);
375b951964fSBarry Smith 
376521d7252SBarry Smith #undef __FUNCT__
377521d7252SBarry Smith #define __FUNCT__ "MatSetBlockSize_Shell"
378521d7252SBarry Smith PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
379521d7252SBarry Smith {
38041c166b1SJed Brown   PetscErrorCode ierr;
38141c166b1SJed Brown 
382521d7252SBarry Smith   PetscFunctionBegin;
38341c166b1SJed Brown   ierr = PetscLayoutSetBlockSize(A->rmap,bs);CHKERRQ(ierr);
38441c166b1SJed Brown   ierr = PetscLayoutSetBlockSize(A->cmap,bs);CHKERRQ(ierr);
385521d7252SBarry Smith   PetscFunctionReturn(0);
386521d7252SBarry Smith }
387521d7252SBarry Smith 
38809dc0095SBarry Smith static struct _MatOps MatOps_Values = {0,
38920563c6bSBarry Smith        0,
39020563c6bSBarry Smith        0,
39120563c6bSBarry Smith        0,
39297304618SKris Buschelman /* 4*/ 0,
39320563c6bSBarry Smith        0,
394b951964fSBarry Smith        0,
395b951964fSBarry Smith        0,
396b951964fSBarry Smith        0,
397b951964fSBarry Smith        0,
39897304618SKris Buschelman /*10*/ 0,
399b951964fSBarry Smith        0,
400b951964fSBarry Smith        0,
401b951964fSBarry Smith        0,
402b951964fSBarry Smith        0,
40397304618SKris Buschelman /*15*/ 0,
404b951964fSBarry Smith        0,
405b951964fSBarry Smith        0,
4068fe8eb27SJed Brown        MatDiagonalScale_Shell,
407b951964fSBarry Smith        0,
40897304618SKris Buschelman /*20*/ 0,
409ef66eb69SBarry Smith        MatAssemblyEnd_Shell,
410b951964fSBarry Smith        0,
411b951964fSBarry Smith        0,
412d519adbfSMatthew Knepley /*24*/ 0,
413b951964fSBarry Smith        0,
414b951964fSBarry Smith        0,
415b951964fSBarry Smith        0,
416b951964fSBarry Smith        0,
417d519adbfSMatthew Knepley /*29*/ 0,
418b951964fSBarry Smith        0,
419273d9f13SBarry Smith        0,
420b951964fSBarry Smith        0,
421b951964fSBarry Smith        0,
422d519adbfSMatthew Knepley /*34*/ 0,
423b951964fSBarry Smith        0,
424b951964fSBarry Smith        0,
42509dc0095SBarry Smith        0,
42609dc0095SBarry Smith        0,
427d519adbfSMatthew Knepley /*39*/ 0,
42809dc0095SBarry Smith        0,
42909dc0095SBarry Smith        0,
43009dc0095SBarry Smith        0,
43109dc0095SBarry Smith        0,
432d519adbfSMatthew Knepley /*44*/ 0,
433ef66eb69SBarry Smith        MatScale_Shell,
434ef66eb69SBarry Smith        MatShift_Shell,
43509dc0095SBarry Smith        0,
43609dc0095SBarry Smith        0,
437d519adbfSMatthew Knepley /*49*/ MatSetBlockSize_Shell,
43809dc0095SBarry Smith        0,
43909dc0095SBarry Smith        0,
44009dc0095SBarry Smith        0,
44109dc0095SBarry Smith        0,
442d519adbfSMatthew Knepley /*54*/ 0,
44309dc0095SBarry Smith        0,
44409dc0095SBarry Smith        0,
44509dc0095SBarry Smith        0,
44609dc0095SBarry Smith        0,
447d519adbfSMatthew Knepley /*59*/ 0,
448b9b97703SBarry Smith        MatDestroy_Shell,
44909dc0095SBarry Smith        0,
450357abbc8SBarry Smith        0,
451273d9f13SBarry Smith        0,
452d519adbfSMatthew Knepley /*64*/ 0,
453273d9f13SBarry Smith        0,
454273d9f13SBarry Smith        0,
455273d9f13SBarry Smith        0,
456273d9f13SBarry Smith        0,
457d519adbfSMatthew Knepley /*69*/ 0,
458273d9f13SBarry Smith        0,
459c87e5d42SMatthew Knepley        MatConvert_Shell,
460273d9f13SBarry Smith        0,
46197304618SKris Buschelman        0,
462d519adbfSMatthew Knepley /*74*/ 0,
46397304618SKris Buschelman        0,
46497304618SKris Buschelman        0,
46597304618SKris Buschelman        0,
46697304618SKris Buschelman        0,
467d519adbfSMatthew Knepley /*79*/ 0,
46897304618SKris Buschelman        0,
46997304618SKris Buschelman        0,
47097304618SKris Buschelman        0,
471865e5f61SKris Buschelman        0,
472d519adbfSMatthew Knepley /*84*/ 0,
473865e5f61SKris Buschelman        0,
474865e5f61SKris Buschelman        0,
475865e5f61SKris Buschelman        0,
476865e5f61SKris Buschelman        0,
477d519adbfSMatthew Knepley /*89*/ 0,
478865e5f61SKris Buschelman        0,
479865e5f61SKris Buschelman        0,
480865e5f61SKris Buschelman        0,
481865e5f61SKris Buschelman        0,
482d519adbfSMatthew Knepley /*94*/ 0,
483865e5f61SKris Buschelman        0,
484865e5f61SKris Buschelman        0,
485865e5f61SKris Buschelman        0};
486273d9f13SBarry Smith 
4870bad9183SKris Buschelman /*MC
488fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
4890bad9183SKris Buschelman 
4900bad9183SKris Buschelman   Level: advanced
4910bad9183SKris Buschelman 
4920bad9183SKris Buschelman .seealso: MatCreateShell
4930bad9183SKris Buschelman M*/
4940bad9183SKris Buschelman 
495273d9f13SBarry Smith EXTERN_C_BEGIN
496711e205bSSatish Balay #undef __FUNCT__
497711e205bSSatish Balay #define __FUNCT__ "MatCreate_Shell"
4987087cfbeSBarry Smith PetscErrorCode  MatCreate_Shell(Mat A)
499273d9f13SBarry Smith {
500273d9f13SBarry Smith   Mat_Shell      *b;
501dfbe8321SBarry Smith   PetscErrorCode ierr;
502273d9f13SBarry Smith 
503273d9f13SBarry Smith   PetscFunctionBegin;
504273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
505273d9f13SBarry Smith 
50638f2d2fdSLisandro Dalcin   ierr = PetscNewLog(A,Mat_Shell,&b);CHKERRQ(ierr);
507273d9f13SBarry Smith   A->data = (void*)b;
508273d9f13SBarry Smith 
50926283091SBarry Smith   ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr);
51026283091SBarry Smith   ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr);
51126283091SBarry Smith   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
51226283091SBarry Smith   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
513273d9f13SBarry Smith 
514273d9f13SBarry Smith   b->ctx           = 0;
515ef66eb69SBarry Smith   b->vshift        = 0.0;
516ef66eb69SBarry Smith   b->vscale        = 1.0;
517ef66eb69SBarry Smith   b->mult          = 0;
51818be62a5SSatish Balay   b->multtranspose = 0;
51918be62a5SSatish Balay   b->getdiagonal   = 0;
520273d9f13SBarry Smith   A->assembled     = PETSC_TRUE;
521210f0121SBarry Smith   A->preallocated  = PETSC_FALSE;
52217667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
523273d9f13SBarry Smith   PetscFunctionReturn(0);
524273d9f13SBarry Smith }
525273d9f13SBarry Smith EXTERN_C_END
526e51e0e81SBarry Smith 
527711e205bSSatish Balay #undef __FUNCT__
528711e205bSSatish Balay #define __FUNCT__ "MatCreateShell"
5294b828684SBarry Smith /*@C
530052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
531ff756334SLois Curfman McInnes    private data storage format.
532e51e0e81SBarry Smith 
533c7fcc2eaSBarry Smith   Collective on MPI_Comm
534c7fcc2eaSBarry Smith 
535e51e0e81SBarry Smith    Input Parameters:
536c7fcc2eaSBarry Smith +  comm - MPI communicator
537c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
538c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
539c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
540c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
541c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
542e51e0e81SBarry Smith 
543ff756334SLois Curfman McInnes    Output Parameter:
54444cd7ae7SLois Curfman McInnes .  A - the matrix
545e51e0e81SBarry Smith 
546ff2fd236SBarry Smith    Level: advanced
547ff2fd236SBarry Smith 
548f39d1f56SLois Curfman McInnes   Usage:
5497b2a1423SBarry Smith $    extern int mult(Mat,Vec,Vec);
550f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
551c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
552f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
553f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
554f39d1f56SLois Curfman McInnes 
555ff756334SLois Curfman McInnes    Notes:
556ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
557ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
558ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
559e51e0e81SBarry Smith 
560f38a8d56SBarry Smith    Fortran Notes: The context can only be an integer or a PetscObject
561f38a8d56SBarry Smith       unfortunately it cannot be a Fortran array or derived type.
562f38a8d56SBarry Smith 
563f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
564f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
565645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
566645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
567645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
568645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
569645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
570645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
571645985a0SLois Curfman McInnes    For example,
572f39d1f56SLois Curfman McInnes 
573f39d1f56SLois Curfman McInnes $
574f39d1f56SLois Curfman McInnes $     Vec x, y
5757b2a1423SBarry Smith $     extern int mult(Mat,Vec,Vec);
576645985a0SLois Curfman McInnes $     Mat A
577f39d1f56SLois Curfman McInnes $
578c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
579c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
580f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
581c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
582c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
583c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
584645985a0SLois Curfman McInnes $     MatMult(A,x,y);
585645985a0SLois Curfman McInnes $     MatDestroy(A);
586f39d1f56SLois Curfman McInnes $     VecDestroy(y); VecDestroy(x);
587645985a0SLois Curfman McInnes $
588e51e0e81SBarry Smith 
5890b627109SLois Curfman McInnes .keywords: matrix, shell, create
5900b627109SLois Curfman McInnes 
591ab50ec6bSBarry Smith .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
592e51e0e81SBarry Smith @*/
5937087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
594e51e0e81SBarry Smith {
595dfbe8321SBarry Smith   PetscErrorCode ierr;
596ed3cc1f0SBarry Smith 
5973a40ed3dSBarry Smith   PetscFunctionBegin;
598f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
599f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
600273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
601273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
6020fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
603273d9f13SBarry Smith   PetscFunctionReturn(0);
604c7fcc2eaSBarry Smith }
605c7fcc2eaSBarry Smith 
606711e205bSSatish Balay #undef __FUNCT__
607711e205bSSatish Balay #define __FUNCT__ "MatShellSetContext"
608c6866cfdSSatish Balay /*@
609273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
610c7fcc2eaSBarry Smith 
6113f9fe445SBarry Smith    Logically Collective on Mat
612c7fcc2eaSBarry Smith 
613273d9f13SBarry Smith     Input Parameters:
614273d9f13SBarry Smith +   mat - the shell matrix
615273d9f13SBarry Smith -   ctx - the context
616273d9f13SBarry Smith 
617273d9f13SBarry Smith    Level: advanced
618273d9f13SBarry Smith 
619f38a8d56SBarry Smith    Fortran Notes: The context can only be an integer or a PetscObject
620f38a8d56SBarry Smith       unfortunately it cannot be a Fortran array or derived type.
621273d9f13SBarry Smith 
622273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
6230bc0a719SBarry Smith @*/
6247087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
625273d9f13SBarry Smith {
626273d9f13SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
627dfbe8321SBarry Smith   PetscErrorCode ierr;
628ace3abfcSBarry Smith   PetscBool      flg;
629273d9f13SBarry Smith 
630273d9f13SBarry Smith   PetscFunctionBegin;
6310700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
632273d9f13SBarry Smith   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
633273d9f13SBarry Smith   if (flg) {
634273d9f13SBarry Smith     shell->ctx = ctx;
635940183f3SBarry Smith   } else SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
6363a40ed3dSBarry Smith   PetscFunctionReturn(0);
637e51e0e81SBarry Smith }
638e51e0e81SBarry Smith 
639711e205bSSatish Balay #undef __FUNCT__
640711e205bSSatish Balay #define __FUNCT__ "MatShellSetOperation"
641c16cb8f2SBarry Smith /*@C
6423a3eedf2SBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for
6433a3eedf2SBarry Smith                            a shell matrix.
644e51e0e81SBarry Smith 
6453f9fe445SBarry Smith    Logically Collective on Mat
646fee21e36SBarry Smith 
647c7fcc2eaSBarry Smith     Input Parameters:
648c7fcc2eaSBarry Smith +   mat - the shell matrix
649c7fcc2eaSBarry Smith .   op - the name of the operation
650c7fcc2eaSBarry Smith -   f - the function that provides the operation.
651c7fcc2eaSBarry Smith 
65215091d37SBarry Smith    Level: advanced
65315091d37SBarry Smith 
654fae171e0SBarry Smith     Usage:
655e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
656f39d1f56SLois Curfman McInnes $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
657c134de8dSSatish Balay $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
6580b627109SLois Curfman McInnes 
659a62d957aSLois Curfman McInnes     Notes:
660e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
6611c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
662a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
6631c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
664a62d957aSLois Curfman McInnes 
66525296bd5SBarry Smith     All user-provided functions (execept for MATOP_DESTROY) should have the same calling
666deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
667deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
668deebb3c3SLois Curfman McInnes     routines, e.g.,
669a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
670a62d957aSLois Curfman McInnes 
6714aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
6724aa34b0aSBarry Smith     nonzero on failure.
6734aa34b0aSBarry Smith 
674a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
675a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
676a62d957aSLois Curfman McInnes     set by MatCreateShell().
677a62d957aSLois Curfman McInnes 
678501d9185SBarry Smith     Fortran Notes: For MatGetVecs() the user code should check if the input left or right matrix is -1 and in that case not
679501d9185SBarry Smith        generate a matrix. See src/mat/examples/tests/ex120f.F
680501d9185SBarry Smith 
681a62d957aSLois Curfman McInnes .keywords: matrix, shell, set, operation
682a62d957aSLois Curfman McInnes 
683ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
684e51e0e81SBarry Smith @*/
6857087cfbeSBarry Smith PetscErrorCode  MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
686e51e0e81SBarry Smith {
687dfbe8321SBarry Smith   PetscErrorCode ierr;
688ace3abfcSBarry Smith   PetscBool      flg;
689273d9f13SBarry Smith 
6903a40ed3dSBarry Smith   PetscFunctionBegin;
6910700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
6921c1c02c0SLois Curfman McInnes   if (op == MATOP_DESTROY) {
693273d9f13SBarry Smith     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
694273d9f13SBarry Smith     if (flg) {
695a62d957aSLois Curfman McInnes        Mat_Shell *shell = (Mat_Shell*)mat->data;
6966849ba73SBarry Smith        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
6976849ba73SBarry Smith     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
698a62d957aSLois Curfman McInnes   }
6996849ba73SBarry Smith   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
700c134de8dSSatish Balay   else                       (((void(**)(void))mat->ops)[op]) = f;
701a62d957aSLois Curfman McInnes 
7023a40ed3dSBarry Smith   PetscFunctionReturn(0);
703e51e0e81SBarry Smith }
704f0479e8cSBarry Smith 
705711e205bSSatish Balay #undef __FUNCT__
706711e205bSSatish Balay #define __FUNCT__ "MatShellGetOperation"
707d4bb536fSBarry Smith /*@C
708d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
709d4bb536fSBarry Smith 
710c7fcc2eaSBarry Smith     Not Collective
711c7fcc2eaSBarry Smith 
712d4bb536fSBarry Smith     Input Parameters:
713c7fcc2eaSBarry Smith +   mat - the shell matrix
714c7fcc2eaSBarry Smith -   op - the name of the operation
715d4bb536fSBarry Smith 
716d4bb536fSBarry Smith     Output Parameter:
717d4bb536fSBarry Smith .   f - the function that provides the operation.
718d4bb536fSBarry Smith 
71915091d37SBarry Smith     Level: advanced
72015091d37SBarry Smith 
721d4bb536fSBarry Smith     Notes:
722e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
723d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
724d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
725d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
726d4bb536fSBarry Smith 
727d4bb536fSBarry Smith     All user-provided functions have the same calling
728d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
729d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
730d4bb536fSBarry Smith     routines, e.g.,
731d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
732d4bb536fSBarry Smith 
733d4bb536fSBarry Smith     Within each user-defined routine, the user should call
734d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
735d4bb536fSBarry Smith     set by MatCreateShell().
736d4bb536fSBarry Smith 
737d4bb536fSBarry Smith .keywords: matrix, shell, set, operation
738d4bb536fSBarry Smith 
739ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
740d4bb536fSBarry Smith @*/
7417087cfbeSBarry Smith PetscErrorCode  MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
742d4bb536fSBarry Smith {
743dfbe8321SBarry Smith   PetscErrorCode ierr;
744ace3abfcSBarry Smith   PetscBool      flg;
745273d9f13SBarry Smith 
7463a40ed3dSBarry Smith   PetscFunctionBegin;
7470700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
748d4bb536fSBarry Smith   if (op == MATOP_DESTROY) {
749273d9f13SBarry Smith     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
750273d9f13SBarry Smith     if (flg) {
751d4bb536fSBarry Smith       Mat_Shell *shell = (Mat_Shell*)mat->data;
752c134de8dSSatish Balay       *f = (void(*)(void))shell->destroy;
753c7fcc2eaSBarry Smith     } else {
754c134de8dSSatish Balay       *f = (void(*)(void))mat->ops->destroy;
755d4bb536fSBarry Smith     }
756c7fcc2eaSBarry Smith   } else if (op == MATOP_VIEW) {
757c134de8dSSatish Balay     *f = (void(*)(void))mat->ops->view;
758c7fcc2eaSBarry Smith   } else {
759c134de8dSSatish Balay     *f = (((void(**)(void))mat->ops)[op]);
760d4bb536fSBarry Smith   }
761d4bb536fSBarry Smith 
7623a40ed3dSBarry Smith   PetscFunctionReturn(0);
763d4bb536fSBarry Smith }
764d4bb536fSBarry Smith 
765