xref: /petsc/src/mat/impls/shell/shell.c (revision a4b1380ba24222b987e478d0638cf6874d12d2ef)
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 {
11976e8c5aSLisandro Dalcin   /*  3 */ PetscErrorCode (*mult)(Mat,Vec,Vec);
12976e8c5aSLisandro Dalcin   /*  5 */ PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
13976e8c5aSLisandro Dalcin   /* 17 */ PetscErrorCode (*getdiagonal)(Mat,Vec);
14976e8c5aSLisandro Dalcin   /* 43 */ PetscErrorCode (*copy)(Mat,Mat,MatStructure);
15976e8c5aSLisandro Dalcin   /* 60 */ PetscErrorCode (*destroy)(Mat);
1628f357e3SAlex Fikl };
1728f357e3SAlex Fikl 
1828f357e3SAlex Fikl typedef struct {
1928f357e3SAlex Fikl   struct _MatShellOps ops[1];
202205254eSKarl Rupp 
21ef66eb69SBarry Smith   PetscScalar vscale,vshift;
228fe8eb27SJed Brown   Vec         dshift;
238fe8eb27SJed Brown   Vec         left,right;
248fe8eb27SJed Brown   Vec         left_work,right_work;
255edf6516SJed Brown   Vec         left_add_work,right_add_work;
269f137db4SBarry Smith   Mat         axpy;
279f137db4SBarry Smith   PetscScalar axpy_vscale;
280c0fd78eSBarry Smith   PetscBool   managescalingshifts;                   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
2920563c6bSBarry Smith   void        *ctx;
3088cf3e7dSBarry Smith } Mat_Shell;
310c0fd78eSBarry Smith 
328fe8eb27SJed Brown /*
330c0fd78eSBarry Smith       xx = diag(left)*x
348fe8eb27SJed Brown */
358fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
368fe8eb27SJed Brown {
378fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
388fe8eb27SJed Brown   PetscErrorCode ierr;
398fe8eb27SJed Brown 
408fe8eb27SJed Brown   PetscFunctionBegin;
410298fd71SBarry Smith   *xx = NULL;
428fe8eb27SJed Brown   if (!shell->left) {
438fe8eb27SJed Brown     *xx = x;
448fe8eb27SJed Brown   } else {
458fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
468fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
478fe8eb27SJed Brown     *xx  = shell->left_work;
488fe8eb27SJed Brown   }
498fe8eb27SJed Brown   PetscFunctionReturn(0);
508fe8eb27SJed Brown }
518fe8eb27SJed Brown 
520c0fd78eSBarry Smith /*
530c0fd78eSBarry Smith      xx = diag(right)*x
540c0fd78eSBarry Smith */
558fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
568fe8eb27SJed Brown {
578fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
588fe8eb27SJed Brown   PetscErrorCode ierr;
598fe8eb27SJed Brown 
608fe8eb27SJed Brown   PetscFunctionBegin;
610298fd71SBarry Smith   *xx = NULL;
628fe8eb27SJed Brown   if (!shell->right) {
638fe8eb27SJed Brown     *xx = x;
648fe8eb27SJed Brown   } else {
658fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
668fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
678fe8eb27SJed Brown     *xx  = shell->right_work;
688fe8eb27SJed Brown   }
698fe8eb27SJed Brown   PetscFunctionReturn(0);
708fe8eb27SJed Brown }
718fe8eb27SJed Brown 
720c0fd78eSBarry Smith /*
730c0fd78eSBarry Smith     x = diag(left)*x
740c0fd78eSBarry Smith */
758fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
768fe8eb27SJed Brown {
778fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
788fe8eb27SJed Brown   PetscErrorCode ierr;
798fe8eb27SJed Brown 
808fe8eb27SJed Brown   PetscFunctionBegin;
818fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
828fe8eb27SJed Brown   PetscFunctionReturn(0);
838fe8eb27SJed Brown }
848fe8eb27SJed Brown 
850c0fd78eSBarry Smith /*
860c0fd78eSBarry Smith     x = diag(right)*x
870c0fd78eSBarry Smith */
888fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
898fe8eb27SJed Brown {
908fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
918fe8eb27SJed Brown   PetscErrorCode ierr;
928fe8eb27SJed Brown 
938fe8eb27SJed Brown   PetscFunctionBegin;
948fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
958fe8eb27SJed Brown   PetscFunctionReturn(0);
968fe8eb27SJed Brown }
978fe8eb27SJed Brown 
980c0fd78eSBarry Smith /*
990c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
1000c0fd78eSBarry Smith 
1010c0fd78eSBarry Smith          On input Y already contains A*x
1020c0fd78eSBarry Smith */
1038fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
1048fe8eb27SJed Brown {
1058fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1068fe8eb27SJed Brown   PetscErrorCode ierr;
1078fe8eb27SJed Brown 
1088fe8eb27SJed Brown   PetscFunctionBegin;
1098fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
1108fe8eb27SJed Brown     PetscInt          i,m;
1118fe8eb27SJed Brown     const PetscScalar *x,*d;
1128fe8eb27SJed Brown     PetscScalar       *y;
1138fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
1148fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1158fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
1168fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
1178fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
1188fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
1198fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
1208fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
1210c0fd78eSBarry Smith   } else {
122027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
1238fe8eb27SJed Brown   }
124d4c7de66SBarry Smith   if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */
1258fe8eb27SJed Brown   PetscFunctionReturn(0);
1268fe8eb27SJed Brown }
127e51e0e81SBarry Smith 
1289d225801SJed Brown /*@
129a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
130b4fd4287SBarry Smith 
131c7fcc2eaSBarry Smith     Not Collective
132c7fcc2eaSBarry Smith 
133b4fd4287SBarry Smith     Input Parameter:
134b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
135b4fd4287SBarry Smith 
136b4fd4287SBarry Smith     Output Parameter:
137b4fd4287SBarry Smith .   ctx - the user provided context
138b4fd4287SBarry Smith 
13915091d37SBarry Smith     Level: advanced
14015091d37SBarry Smith 
14195452b02SPatrick Sanan    Fortran Notes:
14295452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
143daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
144a62d957aSLois Curfman McInnes 
145a62d957aSLois Curfman McInnes .keywords: matrix, shell, get, context
146a62d957aSLois Curfman McInnes 
147ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
1480bc0a719SBarry Smith @*/
1498fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
150b4fd4287SBarry Smith {
151dfbe8321SBarry Smith   PetscErrorCode ierr;
152ace3abfcSBarry Smith   PetscBool      flg;
153273d9f13SBarry Smith 
1543a40ed3dSBarry Smith   PetscFunctionBegin;
1550700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1564482741eSBarry Smith   PetscValidPointer(ctx,2);
157251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
158940183f3SBarry Smith   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
159ce94432eSBarry Smith   else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
1603a40ed3dSBarry Smith   PetscFunctionReturn(0);
161b4fd4287SBarry Smith }
162b4fd4287SBarry Smith 
163dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
164e51e0e81SBarry Smith {
165dfbe8321SBarry Smith   PetscErrorCode ierr;
166bf0cc555SLisandro Dalcin   Mat_Shell      *shell = (Mat_Shell*)mat->data;
167ed3cc1f0SBarry Smith 
1683a40ed3dSBarry Smith   PetscFunctionBegin;
16928f357e3SAlex Fikl   if (shell->ops->destroy) {
17028f357e3SAlex Fikl     ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr);
171bf0cc555SLisandro Dalcin   }
1720c0fd78eSBarry Smith   ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
1730c0fd78eSBarry Smith   ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
1740c0fd78eSBarry Smith   ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
1758fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
1768fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
1775edf6516SJed Brown   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
1785edf6516SJed Brown   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
1799f137db4SBarry Smith   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
180bf0cc555SLisandro Dalcin   ierr = PetscFree(mat->data);CHKERRQ(ierr);
1813a40ed3dSBarry Smith   PetscFunctionReturn(0);
182e51e0e81SBarry Smith }
183e51e0e81SBarry Smith 
1847fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
1857fabda3fSAlex Fikl {
18628f357e3SAlex Fikl   Mat_Shell       *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
1877fabda3fSAlex Fikl   PetscErrorCode  ierr;
188cb8c8a77SBarry Smith   PetscBool       matflg;
1897fabda3fSAlex Fikl 
1907fabda3fSAlex Fikl   PetscFunctionBegin;
19128f357e3SAlex Fikl   ierr = PetscObjectTypeCompare((PetscObject)B,MATSHELL,&matflg);CHKERRQ(ierr);
192cb8c8a77SBarry Smith   if (!matflg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_NOTSAMETYPE,"Output matrix must be a MATSHELL");
1937fabda3fSAlex Fikl 
194cb8c8a77SBarry Smith   ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
195cb8c8a77SBarry Smith   ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
1967fabda3fSAlex Fikl 
197cb8c8a77SBarry Smith   if (shellA->ops->copy) {
19828f357e3SAlex Fikl     ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr);
199cb8c8a77SBarry Smith   }
2007fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
2017fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
2020c0fd78eSBarry Smith   if (shellA->dshift) {
2030c0fd78eSBarry Smith     if (!shellB->dshift) {
2040c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr);
2057fabda3fSAlex Fikl     }
2060c0fd78eSBarry Smith     ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr);
2077fabda3fSAlex Fikl   } else {
2089f137db4SBarry Smith     ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr);
2097fabda3fSAlex Fikl   }
2100c0fd78eSBarry Smith   if (shellA->left) {
2110c0fd78eSBarry Smith     if (!shellB->left) {
2120c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr);
2137fabda3fSAlex Fikl     }
2140c0fd78eSBarry Smith     ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr);
2157fabda3fSAlex Fikl   } else {
2169f137db4SBarry Smith     ierr = VecDestroy(&shellB->left);CHKERRQ(ierr);
2177fabda3fSAlex Fikl   }
2180c0fd78eSBarry Smith   if (shellA->right) {
2190c0fd78eSBarry Smith     if (!shellB->right) {
2200c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr);
2217fabda3fSAlex Fikl     }
2220c0fd78eSBarry Smith     ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr);
2237fabda3fSAlex Fikl   } else {
2249f137db4SBarry Smith     ierr = VecDestroy(&shellB->right);CHKERRQ(ierr);
2257fabda3fSAlex Fikl   }
22640e381c3SBarry Smith   ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr);
22740e381c3SBarry Smith   if (shellA->axpy) {
22840e381c3SBarry Smith     ierr                 = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr);
22940e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
23040e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
23140e381c3SBarry Smith   }
2327fabda3fSAlex Fikl   PetscFunctionReturn(0);
2337fabda3fSAlex Fikl }
2347fabda3fSAlex Fikl 
235cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
236cb8c8a77SBarry Smith {
237cb8c8a77SBarry Smith   PetscErrorCode ierr;
238cb8c8a77SBarry Smith   void           *ctx;
239cb8c8a77SBarry Smith 
240cb8c8a77SBarry Smith   PetscFunctionBegin;
241cb8c8a77SBarry Smith   ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr);
242cb8c8a77SBarry Smith   ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr);
243*a4b1380bSStefano Zampini   if (op != MAT_DO_NOT_COPY_VALUES) {
244cb8c8a77SBarry Smith     ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
245*a4b1380bSStefano Zampini   }
246cb8c8a77SBarry Smith   PetscFunctionReturn(0);
247cb8c8a77SBarry Smith }
248cb8c8a77SBarry Smith 
249dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
250ef66eb69SBarry Smith {
251ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
252dfbe8321SBarry Smith   PetscErrorCode   ierr;
25325578ef6SJed Brown   Vec              xx;
254e3f487b0SBarry Smith   PetscObjectState instate,outstate;
255ef66eb69SBarry Smith 
256ef66eb69SBarry Smith   PetscFunctionBegin;
2578fe8eb27SJed Brown   ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr);
258e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
259976e8c5aSLisandro Dalcin   if (!shell->ops->mult) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
26028f357e3SAlex Fikl   ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr);
261e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
262e3f487b0SBarry Smith   if (instate == outstate) {
263e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
264e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
265e3f487b0SBarry Smith   }
2668fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
2678fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
2689f137db4SBarry Smith 
2699f137db4SBarry Smith   if (shell->axpy) {
2709f137db4SBarry Smith     if (!shell->left_work) {ierr = MatCreateVecs(A,&shell->left_work,NULL);CHKERRQ(ierr);}
2719f137db4SBarry Smith     ierr = MatMult(shell->axpy,x,shell->left_work);CHKERRQ(ierr);
2729f137db4SBarry Smith     ierr = VecAXPY(y,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr);
2739f137db4SBarry Smith   }
274ef66eb69SBarry Smith   PetscFunctionReturn(0);
275ef66eb69SBarry Smith }
276ef66eb69SBarry Smith 
2775edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
2785edf6516SJed Brown {
2795edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2805edf6516SJed Brown   PetscErrorCode ierr;
2815edf6516SJed Brown 
2825edf6516SJed Brown   PetscFunctionBegin;
2835edf6516SJed Brown   if (y == z) {
2845edf6516SJed Brown     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
2855edf6516SJed Brown     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
286b8430d49SBarry Smith     ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr);
2875edf6516SJed Brown   } else {
2885edf6516SJed Brown     ierr = MatMult(A,x,z);CHKERRQ(ierr);
2895edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
2905edf6516SJed Brown   }
2915edf6516SJed Brown   PetscFunctionReturn(0);
2925edf6516SJed Brown }
2935edf6516SJed Brown 
29418be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
29518be62a5SSatish Balay {
29618be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
29718be62a5SSatish Balay   PetscErrorCode   ierr;
29825578ef6SJed Brown   Vec              xx;
299e3f487b0SBarry Smith   PetscObjectState instate,outstate;
30018be62a5SSatish Balay 
30118be62a5SSatish Balay   PetscFunctionBegin;
3028fe8eb27SJed Brown   ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr);
303e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
3040c0fd78eSBarry Smith   if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
30528f357e3SAlex Fikl   ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr);
306e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
307e3f487b0SBarry Smith   if (instate == outstate) {
308e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
309e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
310e3f487b0SBarry Smith   }
3118fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
3128fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
313350ec83bSStefano Zampini 
314350ec83bSStefano Zampini   if (shell->axpy) {
315350ec83bSStefano Zampini     if (!shell->right_work) {ierr = MatCreateVecs(A,NULL,&shell->right_work);CHKERRQ(ierr);}
316350ec83bSStefano Zampini     ierr = MatMultTranspose(shell->axpy,x,shell->right_work);CHKERRQ(ierr);
317350ec83bSStefano Zampini     ierr = VecAXPY(y,shell->axpy_vscale,shell->right_work);CHKERRQ(ierr);
318350ec83bSStefano Zampini   }
31918be62a5SSatish Balay   PetscFunctionReturn(0);
32018be62a5SSatish Balay }
32118be62a5SSatish Balay 
3225edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
3235edf6516SJed Brown {
3245edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
3255edf6516SJed Brown   PetscErrorCode ierr;
3265edf6516SJed Brown 
3275edf6516SJed Brown   PetscFunctionBegin;
3285edf6516SJed Brown   if (y == z) {
3295edf6516SJed Brown     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
3305edf6516SJed Brown     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
331dac989eaS“Marek     ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr);
3325edf6516SJed Brown   } else {
3335edf6516SJed Brown     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
3345edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
3355edf6516SJed Brown   }
3365edf6516SJed Brown   PetscFunctionReturn(0);
3375edf6516SJed Brown }
3385edf6516SJed Brown 
3390c0fd78eSBarry Smith /*
3400c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
3410c0fd78eSBarry Smith */
34218be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
34318be62a5SSatish Balay {
34418be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
34518be62a5SSatish Balay   PetscErrorCode ierr;
34618be62a5SSatish Balay 
34718be62a5SSatish Balay   PetscFunctionBegin;
3480c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
34928f357e3SAlex Fikl     ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr);
350305211d5SBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)");
35118be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
3528fe8eb27SJed Brown   if (shell->dshift) {
3530c0fd78eSBarry Smith     ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr);
35418be62a5SSatish Balay   }
3550c0fd78eSBarry Smith   ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
3568fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
3578fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
35881c02519SBarry Smith   if (shell->axpy) {
35981c02519SBarry Smith     if (!shell->left_work) {ierr = VecDuplicate(v,&shell->left_work);CHKERRQ(ierr);}
36081c02519SBarry Smith     ierr = MatGetDiagonal(shell->axpy,shell->left_work);CHKERRQ(ierr);
36181c02519SBarry Smith     ierr = VecAXPY(v,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr);
36281c02519SBarry Smith   }
36318be62a5SSatish Balay   PetscFunctionReturn(0);
36418be62a5SSatish Balay }
36518be62a5SSatish Balay 
366f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
367ef66eb69SBarry Smith {
368ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
3698fe8eb27SJed Brown   PetscErrorCode ierr;
370b24ad042SBarry Smith 
371ef66eb69SBarry Smith   PetscFunctionBegin;
3720c0fd78eSBarry Smith   if (shell->left || shell->right) {
3738fe8eb27SJed Brown     if (!shell->dshift) {
3740c0fd78eSBarry Smith       ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr);
3750c0fd78eSBarry Smith       ierr = VecSet(shell->dshift,a);CHKERRQ(ierr);
3760c0fd78eSBarry Smith     } else {
3770c0fd78eSBarry Smith       if (shell->left)  {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
3780c0fd78eSBarry Smith       if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
3799f137db4SBarry Smith       ierr = VecShift(shell->dshift,a);CHKERRQ(ierr);
3800c0fd78eSBarry Smith     }
3818fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
3828fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
3838fe8eb27SJed Brown   } else shell->vshift += a;
384ef66eb69SBarry Smith   PetscFunctionReturn(0);
385ef66eb69SBarry Smith }
386ef66eb69SBarry Smith 
387b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
3886464bf51SAlex Fikl {
3896464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
3906464bf51SAlex Fikl   PetscErrorCode ierr;
3916464bf51SAlex Fikl 
3926464bf51SAlex Fikl   PetscFunctionBegin;
3930c0fd78eSBarry Smith   if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);}
3940c0fd78eSBarry Smith   if (shell->left || shell->right) {
39592fabd1fSBarry Smith     if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);}
3969f137db4SBarry Smith     if (shell->left && shell->right)  {
3979f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
3989f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
3999f137db4SBarry Smith     } else if (shell->left) {
4009f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
4019f137db4SBarry Smith     } else {
4029f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr);
4039f137db4SBarry Smith     }
4049f137db4SBarry Smith     if (!shell->dshift) {
4059f137db4SBarry Smith       ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr);
4069f137db4SBarry Smith       ierr = VecCopy(shell->dshift,shell->right_work);CHKERRQ(ierr);
4079f137db4SBarry Smith     } else {
408b253ae0bS“Marek       ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr);
4099f137db4SBarry Smith     }
4100c0fd78eSBarry Smith   } else {
411b253ae0bS“Marek     ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr);
412b253ae0bS“Marek   }
413b253ae0bS“Marek   PetscFunctionReturn(0);
414b253ae0bS“Marek }
415b253ae0bS“Marek 
416b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
417b253ae0bS“Marek {
418b253ae0bS“Marek   Vec            d;
419b253ae0bS“Marek   PetscErrorCode ierr;
420b253ae0bS“Marek 
421b253ae0bS“Marek   PetscFunctionBegin;
422b253ae0bS“Marek   if (ins == INSERT_VALUES) {
423b253ae0bS“Marek     if (!A->ops->getdiagonal) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
424b253ae0bS“Marek     ierr = VecDuplicate(D,&d);CHKERRQ(ierr);
425b253ae0bS“Marek     ierr = MatGetDiagonal(A,d);CHKERRQ(ierr);
426b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr);
427b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
428b253ae0bS“Marek     ierr = VecDestroy(&d);CHKERRQ(ierr);
429b253ae0bS“Marek   } else {
430b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
4316464bf51SAlex Fikl   }
4326464bf51SAlex Fikl   PetscFunctionReturn(0);
4336464bf51SAlex Fikl }
4346464bf51SAlex Fikl 
435f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
436ef66eb69SBarry Smith {
437ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4388fe8eb27SJed Brown   PetscErrorCode ierr;
439b24ad042SBarry Smith 
440ef66eb69SBarry Smith   PetscFunctionBegin;
441f4df32b1SMatthew Knepley   shell->vscale *= a;
4420c0fd78eSBarry Smith   shell->vshift *= a;
4432205254eSKarl Rupp   if (shell->dshift) {
4442205254eSKarl Rupp     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
4450c0fd78eSBarry Smith   }
44681c02519SBarry Smith   shell->axpy_vscale *= a;
4478fe8eb27SJed Brown   PetscFunctionReturn(0);
44818be62a5SSatish Balay }
4498fe8eb27SJed Brown 
4508fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
4518fe8eb27SJed Brown {
4528fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4538fe8eb27SJed Brown   PetscErrorCode ierr;
4548fe8eb27SJed Brown 
4558fe8eb27SJed Brown   PetscFunctionBegin;
45681c02519SBarry Smith   if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation");
4578fe8eb27SJed Brown   if (left) {
4580c0fd78eSBarry Smith     if (!shell->left) {
4590c0fd78eSBarry Smith       ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr);
4608fe8eb27SJed Brown       ierr = VecCopy(left,shell->left);CHKERRQ(ierr);
4610c0fd78eSBarry Smith     } else {
4620c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
46318be62a5SSatish Balay     }
464ef66eb69SBarry Smith   }
4658fe8eb27SJed Brown   if (right) {
4660c0fd78eSBarry Smith     if (!shell->right) {
4670c0fd78eSBarry Smith       ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr);
4688fe8eb27SJed Brown       ierr = VecCopy(right,shell->right);CHKERRQ(ierr);
4690c0fd78eSBarry Smith     } else {
4700c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
4718fe8eb27SJed Brown     }
4728fe8eb27SJed Brown   }
473ef66eb69SBarry Smith   PetscFunctionReturn(0);
474ef66eb69SBarry Smith }
475ef66eb69SBarry Smith 
476dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
477ef66eb69SBarry Smith {
478ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
4790c0fd78eSBarry Smith   PetscErrorCode ierr;
480ef66eb69SBarry Smith 
481ef66eb69SBarry Smith   PetscFunctionBegin;
4828fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
483ef66eb69SBarry Smith     shell->vshift = 0.0;
484ef66eb69SBarry Smith     shell->vscale = 1.0;
4850c0fd78eSBarry Smith     ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
4860c0fd78eSBarry Smith     ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
4870c0fd78eSBarry Smith     ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
48881c02519SBarry Smith     ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
489ef66eb69SBarry Smith   }
490ef66eb69SBarry Smith   PetscFunctionReturn(0);
491ef66eb69SBarry Smith }
492ef66eb69SBarry Smith 
4933b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool  *missing,PetscInt *d)
4943b49f96aSBarry Smith {
4953b49f96aSBarry Smith   PetscFunctionBegin;
4963b49f96aSBarry Smith   *missing = PETSC_FALSE;
4973b49f96aSBarry Smith   PetscFunctionReturn(0);
4983b49f96aSBarry Smith }
4993b49f96aSBarry Smith 
5009f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
5019f137db4SBarry Smith {
5029f137db4SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
5039f137db4SBarry Smith   PetscErrorCode ierr;
5049f137db4SBarry Smith 
5059f137db4SBarry Smith   PetscFunctionBegin;
5069f137db4SBarry Smith   ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
5079f137db4SBarry Smith   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
5089f137db4SBarry Smith   shell->axpy        = X;
5099f137db4SBarry Smith   shell->axpy_vscale = a;
5109f137db4SBarry Smith   PetscFunctionReturn(0);
5119f137db4SBarry Smith }
5129f137db4SBarry Smith 
51309dc0095SBarry Smith static struct _MatOps MatOps_Values = {0,
51420563c6bSBarry Smith                                        0,
51520563c6bSBarry Smith                                        0,
5169f137db4SBarry Smith                                        0,
5170c0fd78eSBarry Smith                                 /* 4*/ MatMultAdd_Shell,
5189f137db4SBarry Smith                                        0,
5190c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
520b951964fSBarry Smith                                        0,
521b951964fSBarry Smith                                        0,
522b951964fSBarry Smith                                        0,
52397304618SKris Buschelman                                 /*10*/ 0,
524b951964fSBarry Smith                                        0,
525b951964fSBarry Smith                                        0,
526b951964fSBarry Smith                                        0,
527b951964fSBarry Smith                                        0,
52897304618SKris Buschelman                                 /*15*/ 0,
529b951964fSBarry Smith                                        0,
53000849d43SBarry Smith                                        0,
5318fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
532b951964fSBarry Smith                                        0,
53397304618SKris Buschelman                                 /*20*/ 0,
534ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
535b951964fSBarry Smith                                        0,
536b951964fSBarry Smith                                        0,
537d519adbfSMatthew Knepley                                 /*24*/ 0,
538b951964fSBarry Smith                                        0,
539b951964fSBarry Smith                                        0,
540b951964fSBarry Smith                                        0,
541b951964fSBarry Smith                                        0,
542d519adbfSMatthew Knepley                                 /*29*/ 0,
543b951964fSBarry Smith                                        0,
544273d9f13SBarry Smith                                        0,
545b951964fSBarry Smith                                        0,
546b951964fSBarry Smith                                        0,
547cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
548b951964fSBarry Smith                                        0,
549b951964fSBarry Smith                                        0,
55009dc0095SBarry Smith                                        0,
55109dc0095SBarry Smith                                        0,
5529f137db4SBarry Smith                                 /*39*/ MatAXPY_Shell,
55309dc0095SBarry Smith                                        0,
55409dc0095SBarry Smith                                        0,
55509dc0095SBarry Smith                                        0,
556cb8c8a77SBarry Smith                                        MatCopy_Shell,
557d519adbfSMatthew Knepley                                 /*44*/ 0,
558ef66eb69SBarry Smith                                        MatScale_Shell,
559ef66eb69SBarry Smith                                        MatShift_Shell,
5606464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
56109dc0095SBarry Smith                                        0,
562f73d5cc4SBarry Smith                                 /*49*/ 0,
56309dc0095SBarry Smith                                        0,
56409dc0095SBarry Smith                                        0,
56509dc0095SBarry Smith                                        0,
56609dc0095SBarry Smith                                        0,
567d519adbfSMatthew Knepley                                 /*54*/ 0,
56809dc0095SBarry Smith                                        0,
56909dc0095SBarry Smith                                        0,
57009dc0095SBarry Smith                                        0,
57109dc0095SBarry Smith                                        0,
572d519adbfSMatthew Knepley                                 /*59*/ 0,
573b9b97703SBarry Smith                                        MatDestroy_Shell,
57409dc0095SBarry Smith                                        0,
575357abbc8SBarry Smith                                        0,
576273d9f13SBarry Smith                                        0,
577d519adbfSMatthew Knepley                                 /*64*/ 0,
578273d9f13SBarry Smith                                        0,
579273d9f13SBarry Smith                                        0,
580273d9f13SBarry Smith                                        0,
581273d9f13SBarry Smith                                        0,
582d519adbfSMatthew Knepley                                 /*69*/ 0,
583273d9f13SBarry Smith                                        0,
584c87e5d42SMatthew Knepley                                        MatConvert_Shell,
585273d9f13SBarry Smith                                        0,
58697304618SKris Buschelman                                        0,
587d519adbfSMatthew Knepley                                 /*74*/ 0,
58897304618SKris Buschelman                                        0,
58997304618SKris Buschelman                                        0,
59097304618SKris Buschelman                                        0,
59197304618SKris Buschelman                                        0,
592d519adbfSMatthew Knepley                                 /*79*/ 0,
59397304618SKris Buschelman                                        0,
59497304618SKris Buschelman                                        0,
59597304618SKris Buschelman                                        0,
596865e5f61SKris Buschelman                                        0,
597d519adbfSMatthew Knepley                                 /*84*/ 0,
598865e5f61SKris Buschelman                                        0,
599865e5f61SKris Buschelman                                        0,
600865e5f61SKris Buschelman                                        0,
601865e5f61SKris Buschelman                                        0,
602d519adbfSMatthew Knepley                                 /*89*/ 0,
603865e5f61SKris Buschelman                                        0,
604865e5f61SKris Buschelman                                        0,
605865e5f61SKris Buschelman                                        0,
606865e5f61SKris Buschelman                                        0,
607d519adbfSMatthew Knepley                                 /*94*/ 0,
608865e5f61SKris Buschelman                                        0,
609865e5f61SKris Buschelman                                        0,
6103964eb88SJed Brown                                        0,
6113964eb88SJed Brown                                        0,
6123964eb88SJed Brown                                 /*99*/ 0,
6133964eb88SJed Brown                                        0,
6143964eb88SJed Brown                                        0,
6153964eb88SJed Brown                                        0,
6163964eb88SJed Brown                                        0,
6173964eb88SJed Brown                                /*104*/ 0,
6183964eb88SJed Brown                                        0,
6193964eb88SJed Brown                                        0,
6203964eb88SJed Brown                                        0,
6213964eb88SJed Brown                                        0,
6223964eb88SJed Brown                                /*109*/ 0,
6233964eb88SJed Brown                                        0,
6243964eb88SJed Brown                                        0,
6253964eb88SJed Brown                                        0,
6263b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
6273964eb88SJed Brown                                /*114*/ 0,
6283964eb88SJed Brown                                        0,
6293964eb88SJed Brown                                        0,
6303964eb88SJed Brown                                        0,
6313964eb88SJed Brown                                        0,
6323964eb88SJed Brown                                /*119*/ 0,
6333964eb88SJed Brown                                        0,
6343964eb88SJed Brown                                        0,
6353964eb88SJed Brown                                        0,
6363964eb88SJed Brown                                        0,
6373964eb88SJed Brown                                /*124*/ 0,
6383964eb88SJed Brown                                        0,
6393964eb88SJed Brown                                        0,
6403964eb88SJed Brown                                        0,
6413964eb88SJed Brown                                        0,
6423964eb88SJed Brown                                /*129*/ 0,
6433964eb88SJed Brown                                        0,
6443964eb88SJed Brown                                        0,
6453964eb88SJed Brown                                        0,
6463964eb88SJed Brown                                        0,
6473964eb88SJed Brown                                /*134*/ 0,
6483964eb88SJed Brown                                        0,
6493964eb88SJed Brown                                        0,
6503964eb88SJed Brown                                        0,
6513964eb88SJed Brown                                        0,
6523964eb88SJed Brown                                /*139*/ 0,
653f9426fe0SMark Adams                                        0,
6543964eb88SJed Brown                                        0
6553964eb88SJed Brown };
656273d9f13SBarry Smith 
6570bad9183SKris Buschelman /*MC
658fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
6590bad9183SKris Buschelman 
6600bad9183SKris Buschelman   Level: advanced
6610bad9183SKris Buschelman 
6620c0fd78eSBarry Smith .seealso: MatCreateShell()
6630bad9183SKris Buschelman M*/
6640bad9183SKris Buschelman 
6658cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
666273d9f13SBarry Smith {
667273d9f13SBarry Smith   Mat_Shell      *b;
668dfbe8321SBarry Smith   PetscErrorCode ierr;
669273d9f13SBarry Smith 
670273d9f13SBarry Smith   PetscFunctionBegin;
671273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
672273d9f13SBarry Smith 
673b00a9115SJed Brown   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
674273d9f13SBarry Smith   A->data = (void*)b;
675273d9f13SBarry Smith 
67626283091SBarry Smith   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
67726283091SBarry Smith   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
678273d9f13SBarry Smith 
679273d9f13SBarry Smith   b->ctx                 = 0;
680ef66eb69SBarry Smith   b->vshift              = 0.0;
681ef66eb69SBarry Smith   b->vscale              = 1.0;
6820c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
683273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
684210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
6852205254eSKarl Rupp 
68617667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
687273d9f13SBarry Smith   PetscFunctionReturn(0);
688273d9f13SBarry Smith }
689e51e0e81SBarry Smith 
6904b828684SBarry Smith /*@C
691052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
692ff756334SLois Curfman McInnes    private data storage format.
693e51e0e81SBarry Smith 
694c7fcc2eaSBarry Smith   Collective on MPI_Comm
695c7fcc2eaSBarry Smith 
696e51e0e81SBarry Smith    Input Parameters:
697c7fcc2eaSBarry Smith +  comm - MPI communicator
698c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
699c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
700c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
701c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
702c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
703e51e0e81SBarry Smith 
704ff756334SLois Curfman McInnes    Output Parameter:
70544cd7ae7SLois Curfman McInnes .  A - the matrix
706e51e0e81SBarry Smith 
707ff2fd236SBarry Smith    Level: advanced
708ff2fd236SBarry Smith 
709f39d1f56SLois Curfman McInnes   Usage:
7107b2a1423SBarry Smith $    extern int mult(Mat,Vec,Vec);
711f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
712c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
713f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
714f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
715f39d1f56SLois Curfman McInnes 
716ff756334SLois Curfman McInnes    Notes:
717ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
718ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
719ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
720e51e0e81SBarry Smith 
72195452b02SPatrick Sanan    Fortran Notes:
72295452b02SPatrick Sanan     To use this from Fortran with a ctx you must write an interface definition for this
723daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
724daf670e6SBarry Smith     in as the ctx argument.
725f38a8d56SBarry Smith 
726f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
727f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
728645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
729645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
730645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
731645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
732645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
733645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
734645985a0SLois Curfman McInnes    For example,
735f39d1f56SLois Curfman McInnes 
736f39d1f56SLois Curfman McInnes $
737f39d1f56SLois Curfman McInnes $     Vec x, y
7387b2a1423SBarry Smith $     extern int mult(Mat,Vec,Vec);
739645985a0SLois Curfman McInnes $     Mat A
740f39d1f56SLois Curfman McInnes $
741c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
742c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
743f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
744c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
745c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
746c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
747645985a0SLois Curfman McInnes $     MatMult(A,x,y);
748645985a0SLois Curfman McInnes $     MatDestroy(A);
749f39d1f56SLois Curfman McInnes $     VecDestroy(y); VecDestroy(x);
750645985a0SLois Curfman McInnes $
751e51e0e81SBarry Smith 
7529b53d762SBarry Smith 
7539b53d762SBarry Smith    MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), and MatScale() internally so these
7549b53d762SBarry Smith    operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
7559b53d762SBarry Smith 
7569b53d762SBarry Smith 
7570c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
7580c0fd78eSBarry Smith 
75995452b02SPatrick Sanan     Developers Notes:
76095452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
7610c0fd78eSBarry Smith 
7620c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
7630c0fd78eSBarry Smith 
7640c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
7650c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
7660c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
7670c0fd78eSBarry Smith 
7680c0fd78eSBarry Smith           A is the user provided function.
7690c0fd78eSBarry Smith 
770ad2f5c3fSBarry Smith    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
771ad2f5c3fSBarry Smith    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
772ad2f5c3fSBarry Smith    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
773ad2f5c3fSBarry Smith    each time the MATSHELL matrix has changed.
774ad2f5c3fSBarry Smith 
775ad2f5c3fSBarry Smith    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
776ad2f5c3fSBarry Smith    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
777ad2f5c3fSBarry Smith 
7780b627109SLois Curfman McInnes .keywords: matrix, shell, create
7790b627109SLois Curfman McInnes 
7800c0fd78eSBarry Smith .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts()
781e51e0e81SBarry Smith @*/
7827087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
783e51e0e81SBarry Smith {
784dfbe8321SBarry Smith   PetscErrorCode ierr;
785ed3cc1f0SBarry Smith 
7863a40ed3dSBarry Smith   PetscFunctionBegin;
787f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
788f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
789273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
790273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
7910fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
792273d9f13SBarry Smith   PetscFunctionReturn(0);
793c7fcc2eaSBarry Smith }
794c7fcc2eaSBarry Smith 
795c6866cfdSSatish Balay /*@
796273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
797c7fcc2eaSBarry Smith 
7983f9fe445SBarry Smith    Logically Collective on Mat
799c7fcc2eaSBarry Smith 
800273d9f13SBarry Smith     Input Parameters:
801273d9f13SBarry Smith +   mat - the shell matrix
802273d9f13SBarry Smith -   ctx - the context
803273d9f13SBarry Smith 
804273d9f13SBarry Smith    Level: advanced
805273d9f13SBarry Smith 
80695452b02SPatrick Sanan    Fortran Notes:
80795452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
808daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
809273d9f13SBarry Smith 
810273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
8110bc0a719SBarry Smith @*/
8127087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
813273d9f13SBarry Smith {
814273d9f13SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
815dfbe8321SBarry Smith   PetscErrorCode ierr;
816ace3abfcSBarry Smith   PetscBool      flg;
817273d9f13SBarry Smith 
818273d9f13SBarry Smith   PetscFunctionBegin;
8190700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
820251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
821273d9f13SBarry Smith   if (flg) {
822273d9f13SBarry Smith     shell->ctx = ctx;
823ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
8243a40ed3dSBarry Smith   PetscFunctionReturn(0);
825e51e0e81SBarry Smith }
826e51e0e81SBarry Smith 
8270c0fd78eSBarry Smith /*@
8280c0fd78eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
8290c0fd78eSBarry Smith           after MatCreateShell()
8300c0fd78eSBarry Smith 
8310c0fd78eSBarry Smith    Logically Collective on Mat
8320c0fd78eSBarry Smith 
8330c0fd78eSBarry Smith     Input Parameter:
8340c0fd78eSBarry Smith .   mat - the shell matrix
8350c0fd78eSBarry Smith 
8360c0fd78eSBarry Smith   Level: advanced
8370c0fd78eSBarry Smith 
8380c0fd78eSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation()
8390c0fd78eSBarry Smith @*/
8400c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A)
8410c0fd78eSBarry Smith {
8420c0fd78eSBarry Smith   PetscErrorCode ierr;
843976e8c5aSLisandro Dalcin   Mat_Shell      *shell;
8440c0fd78eSBarry Smith   PetscBool      flg;
8450c0fd78eSBarry Smith 
8460c0fd78eSBarry Smith   PetscFunctionBegin;
8470c0fd78eSBarry Smith   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
8480c0fd78eSBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)A,MATSHELL,&flg);CHKERRQ(ierr);
8490c0fd78eSBarry Smith   if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
850976e8c5aSLisandro Dalcin   shell = (Mat_Shell*)A->data;
8510c0fd78eSBarry Smith   shell->managescalingshifts = PETSC_FALSE;
852976e8c5aSLisandro Dalcin   A->ops->diagonalset   = NULL;
853976e8c5aSLisandro Dalcin   A->ops->diagonalscale = NULL;
854976e8c5aSLisandro Dalcin   A->ops->scale         = NULL;
855976e8c5aSLisandro Dalcin   A->ops->shift         = NULL;
856976e8c5aSLisandro Dalcin   A->ops->axpy          = NULL;
8570c0fd78eSBarry Smith   PetscFunctionReturn(0);
8580c0fd78eSBarry Smith }
8590c0fd78eSBarry Smith 
860c16cb8f2SBarry Smith /*@C
861f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
862f3b1f45cSBarry Smith 
863f3b1f45cSBarry Smith    Logically Collective on Mat
864f3b1f45cSBarry Smith 
865f3b1f45cSBarry Smith     Input Parameters:
866f3b1f45cSBarry Smith +   mat - the shell matrix
867f3b1f45cSBarry Smith .   f - the function
868f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
869f3b1f45cSBarry Smith -   ctx - an optional context for the function
870f3b1f45cSBarry Smith 
871f3b1f45cSBarry Smith    Output Parameter:
872f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
873f3b1f45cSBarry Smith 
874f3b1f45cSBarry Smith    Options Database:
875f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
876f3b1f45cSBarry Smith 
877f3b1f45cSBarry Smith    Level: advanced
878f3b1f45cSBarry Smith 
87995452b02SPatrick Sanan    Fortran Notes:
88095452b02SPatrick Sanan     Not supported from Fortran
881f3b1f45cSBarry Smith 
882f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose()
883f3b1f45cSBarry Smith @*/
884f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
885f3b1f45cSBarry Smith {
886f3b1f45cSBarry Smith   PetscErrorCode ierr;
887f3b1f45cSBarry Smith   PetscInt       m,n;
888f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
889f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
89074e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
891f3b1f45cSBarry Smith 
892f3b1f45cSBarry Smith   PetscFunctionBegin;
893f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
894f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr);
895f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
896f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr);
897f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
898f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
899f3b1f45cSBarry Smith 
900f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr);
901f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mat,&Dmat);CHKERRQ(ierr);
902f3b1f45cSBarry Smith 
903f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
904f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
905f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
906f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
907f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
908f3b1f45cSBarry Smith     flag = PETSC_FALSE;
909f3b1f45cSBarry Smith     if (v) {
910fc7aafd1SBarry 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));CHKERRQ(ierr);
911f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
912f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
913f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
914f3b1f45cSBarry Smith     }
915f3b1f45cSBarry Smith   } else if (v) {
916fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
917f3b1f45cSBarry Smith   }
918f3b1f45cSBarry Smith   if (flg) *flg = flag;
919f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
920f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
921f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
922f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
923f3b1f45cSBarry Smith   PetscFunctionReturn(0);
924f3b1f45cSBarry Smith }
925f3b1f45cSBarry Smith 
926f3b1f45cSBarry Smith /*@C
927f3b1f45cSBarry Smith     MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
928f3b1f45cSBarry Smith 
929f3b1f45cSBarry Smith    Logically Collective on Mat
930f3b1f45cSBarry Smith 
931f3b1f45cSBarry Smith     Input Parameters:
932f3b1f45cSBarry Smith +   mat - the shell matrix
933f3b1f45cSBarry Smith .   f - the function
934f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
935f3b1f45cSBarry Smith -   ctx - an optional context for the function
936f3b1f45cSBarry Smith 
937f3b1f45cSBarry Smith    Output Parameter:
938f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
939f3b1f45cSBarry Smith 
940f3b1f45cSBarry Smith    Options Database:
941f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
942f3b1f45cSBarry Smith 
943f3b1f45cSBarry Smith    Level: advanced
944f3b1f45cSBarry Smith 
94595452b02SPatrick Sanan    Fortran Notes:
94695452b02SPatrick Sanan     Not supported from Fortran
947f3b1f45cSBarry Smith 
948f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult()
949f3b1f45cSBarry Smith @*/
950f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
951f3b1f45cSBarry Smith {
952f3b1f45cSBarry Smith   PetscErrorCode ierr;
953f3b1f45cSBarry Smith   Vec            x,y,z;
954f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
955f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
956f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
95774e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
958f3b1f45cSBarry Smith 
959f3b1f45cSBarry Smith   PetscFunctionBegin;
960f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
961f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr);
962f3b1f45cSBarry Smith   ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr);
963f3b1f45cSBarry Smith   ierr = VecDuplicate(y,&z);CHKERRQ(ierr);
964f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
965f3b1f45cSBarry Smith   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
966f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr);
967f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
968f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
969f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr);
970f3b1f45cSBarry Smith   ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr);
971f3b1f45cSBarry Smith   ierr = MatComputeExplicitOperatorTranspose(mat,&Dmat);CHKERRQ(ierr);
972f3b1f45cSBarry Smith 
973f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
974f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
975f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
976f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
977f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
978f3b1f45cSBarry Smith     flag = PETSC_FALSE;
979f3b1f45cSBarry Smith     if (v) {
980fc7aafd1SBarry 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));CHKERRQ(ierr);
981f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
982f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
983f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
984f3b1f45cSBarry Smith     }
985f3b1f45cSBarry Smith   } else if (v) {
986fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
987f3b1f45cSBarry Smith   }
988f3b1f45cSBarry Smith   if (flg) *flg = flag;
989f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
990f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
991f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
992f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
993f3b1f45cSBarry Smith   ierr = VecDestroy(&x);CHKERRQ(ierr);
994f3b1f45cSBarry Smith   ierr = VecDestroy(&y);CHKERRQ(ierr);
995f3b1f45cSBarry Smith   ierr = VecDestroy(&z);CHKERRQ(ierr);
996f3b1f45cSBarry Smith   PetscFunctionReturn(0);
997f3b1f45cSBarry Smith }
998f3b1f45cSBarry Smith 
999f3b1f45cSBarry Smith /*@C
10000c0fd78eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
1001e51e0e81SBarry Smith 
10023f9fe445SBarry Smith    Logically Collective on Mat
1003fee21e36SBarry Smith 
1004c7fcc2eaSBarry Smith     Input Parameters:
1005c7fcc2eaSBarry Smith +   mat - the shell matrix
1006c7fcc2eaSBarry Smith .   op - the name of the operation
1007c7fcc2eaSBarry Smith -   f - the function that provides the operation.
1008c7fcc2eaSBarry Smith 
100915091d37SBarry Smith    Level: advanced
101015091d37SBarry Smith 
1011fae171e0SBarry Smith     Usage:
1012e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
1013f39d1f56SLois Curfman McInnes $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
1014c134de8dSSatish Balay $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
10150b627109SLois Curfman McInnes 
1016a62d957aSLois Curfman McInnes     Notes:
1017e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
10181c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
1019a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
10201c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
1021a62d957aSLois Curfman McInnes 
1022a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
1023deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
1024deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
1025deebb3c3SLois Curfman McInnes     routines, e.g.,
1026a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1027a62d957aSLois Curfman McInnes 
10284aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
10294aa34b0aSBarry Smith     nonzero on failure.
10304aa34b0aSBarry Smith 
1031a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
1032a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
1033a62d957aSLois Curfman McInnes     set by MatCreateShell().
1034a62d957aSLois Curfman McInnes 
103595452b02SPatrick Sanan     Fortran Notes:
103695452b02SPatrick Sanan     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
1037501d9185SBarry Smith        generate a matrix. See src/mat/examples/tests/ex120f.F
1038501d9185SBarry Smith 
10390c0fd78eSBarry Smith     Use MatSetOperation() to set an operation for any matrix type
10400c0fd78eSBarry Smith 
1041a62d957aSLois Curfman McInnes .keywords: matrix, shell, set, operation
1042a62d957aSLois Curfman McInnes 
10430c0fd78eSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts()
1044e51e0e81SBarry Smith @*/
10457087cfbeSBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
1046e51e0e81SBarry Smith {
1047ace3abfcSBarry Smith   PetscBool      flg;
1048976e8c5aSLisandro Dalcin   Mat_Shell      *shell;
1049976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
1050273d9f13SBarry Smith 
10513a40ed3dSBarry Smith   PetscFunctionBegin;
10520700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
10530c0fd78eSBarry Smith   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
10540c0fd78eSBarry Smith   if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
1055976e8c5aSLisandro Dalcin   shell = (Mat_Shell*)mat->data;
1056976e8c5aSLisandro Dalcin 
10575edf6516SJed Brown   switch (op) {
10585edf6516SJed Brown   case MATOP_DESTROY:
105928f357e3SAlex Fikl     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
10605edf6516SJed Brown     break;
1061976e8c5aSLisandro Dalcin   case MATOP_VIEW:
1062976e8c5aSLisandro Dalcin     if (!mat->ops->viewnative) {
1063976e8c5aSLisandro Dalcin       mat->ops->viewnative = mat->ops->view;
1064976e8c5aSLisandro Dalcin     }
1065976e8c5aSLisandro Dalcin     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1066976e8c5aSLisandro Dalcin     break;
1067976e8c5aSLisandro Dalcin   case MATOP_COPY:
1068976e8c5aSLisandro Dalcin     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1069976e8c5aSLisandro Dalcin     break;
10706464bf51SAlex Fikl   case MATOP_DIAGONAL_SET:
10710c0fd78eSBarry Smith   case MATOP_DIAGONAL_SCALE:
10720c0fd78eSBarry Smith   case MATOP_SHIFT:
10730c0fd78eSBarry Smith   case MATOP_SCALE:
10749f137db4SBarry Smith   case MATOP_AXPY:
10750c0fd78eSBarry Smith     if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
10760c0fd78eSBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
10776464bf51SAlex Fikl     break;
10780c0fd78eSBarry Smith   case MATOP_GET_DIAGONAL:
1079976e8c5aSLisandro Dalcin     if (shell->managescalingshifts) {
1080976e8c5aSLisandro Dalcin       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1081976e8c5aSLisandro Dalcin       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1082976e8c5aSLisandro Dalcin     } else {
1083976e8c5aSLisandro Dalcin       shell->ops->getdiagonal = NULL;
1084976e8c5aSLisandro Dalcin       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
108540a5a6c4SBarry Smith     }
10865edf6516SJed Brown     break;
10875edf6516SJed Brown   case MATOP_MULT:
10889f137db4SBarry Smith     if (shell->managescalingshifts) {
10899f137db4SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
10909f137db4SBarry Smith       mat->ops->mult   = MatMult_Shell;
1091976e8c5aSLisandro Dalcin     } else {
1092976e8c5aSLisandro Dalcin       shell->ops->mult = NULL;
1093976e8c5aSLisandro Dalcin       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1094976e8c5aSLisandro Dalcin     }
10955edf6516SJed Brown     break;
10965edf6516SJed Brown   case MATOP_MULT_TRANSPOSE:
10979f137db4SBarry Smith     if (shell->managescalingshifts) {
10989f137db4SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
10995259c5a4SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1100976e8c5aSLisandro Dalcin     } else {
1101976e8c5aSLisandro Dalcin       shell->ops->multtranspose = NULL;
1102976e8c5aSLisandro Dalcin       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1103976e8c5aSLisandro Dalcin     }
11045edf6516SJed Brown     break;
11055edf6516SJed Brown   default:
11065edf6516SJed Brown     (((void(**)(void))mat->ops)[op]) = f;
11075ab264f3SAlp Dener     break;
1108a62d957aSLois Curfman McInnes   }
11093a40ed3dSBarry Smith   PetscFunctionReturn(0);
1110e51e0e81SBarry Smith }
1111f0479e8cSBarry Smith 
1112d4bb536fSBarry Smith /*@C
1113d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
1114d4bb536fSBarry Smith 
1115c7fcc2eaSBarry Smith     Not Collective
1116c7fcc2eaSBarry Smith 
1117d4bb536fSBarry Smith     Input Parameters:
1118c7fcc2eaSBarry Smith +   mat - the shell matrix
1119c7fcc2eaSBarry Smith -   op - the name of the operation
1120d4bb536fSBarry Smith 
1121d4bb536fSBarry Smith     Output Parameter:
1122d4bb536fSBarry Smith .   f - the function that provides the operation.
1123d4bb536fSBarry Smith 
112415091d37SBarry Smith     Level: advanced
112515091d37SBarry Smith 
1126d4bb536fSBarry Smith     Notes:
1127e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
1128d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
1129d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
1130d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
1131d4bb536fSBarry Smith 
1132d4bb536fSBarry Smith     All user-provided functions have the same calling
1133d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
1134d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
1135d4bb536fSBarry Smith     routines, e.g.,
1136d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1137d4bb536fSBarry Smith 
1138d4bb536fSBarry Smith     Within each user-defined routine, the user should call
1139d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
1140d4bb536fSBarry Smith     set by MatCreateShell().
1141d4bb536fSBarry Smith 
1142d4bb536fSBarry Smith .keywords: matrix, shell, set, operation
1143d4bb536fSBarry Smith 
1144ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
1145d4bb536fSBarry Smith @*/
11467087cfbeSBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
1147d4bb536fSBarry Smith {
1148ace3abfcSBarry Smith   PetscBool      flg;
1149976e8c5aSLisandro Dalcin   Mat_Shell      *shell;
1150976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
1151273d9f13SBarry Smith 
11523a40ed3dSBarry Smith   PetscFunctionBegin;
11530700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1154976e8c5aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
1155976e8c5aSLisandro Dalcin   if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices");
1156976e8c5aSLisandro Dalcin   shell = (Mat_Shell*)mat->data;
1157976e8c5aSLisandro Dalcin 
115828f357e3SAlex Fikl   switch (op) {
115928f357e3SAlex Fikl   case MATOP_DESTROY:
116028f357e3SAlex Fikl     *f = (void (*)(void))shell->ops->destroy;
116128f357e3SAlex Fikl     break;
116228f357e3SAlex Fikl   case MATOP_VIEW:
116328f357e3SAlex Fikl     *f = (void (*)(void))mat->ops->view;
116428f357e3SAlex Fikl     break;
1165976e8c5aSLisandro Dalcin   case MATOP_COPY:
1166976e8c5aSLisandro Dalcin     *f = (void (*)(void))shell->ops->copy;
1167976e8c5aSLisandro Dalcin     break;
1168976e8c5aSLisandro Dalcin   case MATOP_DIAGONAL_SET:
1169976e8c5aSLisandro Dalcin   case MATOP_DIAGONAL_SCALE:
1170976e8c5aSLisandro Dalcin   case MATOP_SHIFT:
1171976e8c5aSLisandro Dalcin   case MATOP_SCALE:
1172976e8c5aSLisandro Dalcin   case MATOP_AXPY:
1173976e8c5aSLisandro Dalcin     *f = (((void (**)(void))mat->ops)[op]);
1174976e8c5aSLisandro Dalcin     break;
1175976e8c5aSLisandro Dalcin   case MATOP_GET_DIAGONAL:
1176976e8c5aSLisandro Dalcin     if (shell->ops->getdiagonal)
1177976e8c5aSLisandro Dalcin       *f = (void (*)(void))shell->ops->getdiagonal;
1178976e8c5aSLisandro Dalcin     else
1179976e8c5aSLisandro Dalcin       *f = (((void (**)(void))mat->ops)[op]);
1180976e8c5aSLisandro Dalcin     break;
1181976e8c5aSLisandro Dalcin   case MATOP_MULT:
1182976e8c5aSLisandro Dalcin     if (shell->ops->mult)
1183976e8c5aSLisandro Dalcin       *f = (void (*)(void))shell->ops->mult;
1184976e8c5aSLisandro Dalcin     else
1185976e8c5aSLisandro Dalcin       *f = (((void (**)(void))mat->ops)[op]);
1186976e8c5aSLisandro Dalcin     break;
1187976e8c5aSLisandro Dalcin   case MATOP_MULT_TRANSPOSE:
1188976e8c5aSLisandro Dalcin     if (shell->ops->multtranspose)
1189976e8c5aSLisandro Dalcin       *f = (void (*)(void))shell->ops->multtranspose;
1190976e8c5aSLisandro Dalcin     else
1191976e8c5aSLisandro Dalcin       *f = (((void (**)(void))mat->ops)[op]);
1192976e8c5aSLisandro Dalcin     break;
119328f357e3SAlex Fikl   default:
1194c134de8dSSatish Balay     *f = (((void (**)(void))mat->ops)[op]);
1195d4bb536fSBarry Smith   }
11963a40ed3dSBarry Smith   PetscFunctionReturn(0);
1197d4bb536fSBarry Smith }
1198