xref: /petsc/src/mat/impls/shell/shell.c (revision 99a7f59ec9f9ccee3cdf9fd88ce16d7f72105d85)
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*/
945960306SStefano Zampini #include <petsc/private/vecimpl.h>
10e51e0e81SBarry Smith 
1128f357e3SAlex Fikl struct _MatShellOps {
12976e8c5aSLisandro Dalcin   /*  3 */ PetscErrorCode (*mult)(Mat,Vec,Vec);
13976e8c5aSLisandro Dalcin   /*  5 */ PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
14976e8c5aSLisandro Dalcin   /* 17 */ PetscErrorCode (*getdiagonal)(Mat,Vec);
15976e8c5aSLisandro Dalcin   /* 43 */ PetscErrorCode (*copy)(Mat,Mat,MatStructure);
16976e8c5aSLisandro Dalcin   /* 60 */ PetscErrorCode (*destroy)(Mat);
1728f357e3SAlex Fikl };
1828f357e3SAlex Fikl 
19b77ba244SStefano Zampini struct _n_MatShellMatFunctionList {
20b77ba244SStefano Zampini   PetscErrorCode  (*symbolic)(Mat,Mat,Mat,void**);
21b77ba244SStefano Zampini   PetscErrorCode  (*numeric)(Mat,Mat,Mat,void*);
22b77ba244SStefano Zampini   PetscErrorCode  (*destroy)(void*);
23b77ba244SStefano Zampini   MatProductType  ptype;
24b77ba244SStefano Zampini   char            *composedname;  /* string to identify routine with double dispatch */
25b77ba244SStefano Zampini   char            *resultname; /* result matrix type */
26b77ba244SStefano Zampini 
27b77ba244SStefano Zampini   struct _n_MatShellMatFunctionList *next;
28b77ba244SStefano Zampini };
29b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList;
30b77ba244SStefano Zampini 
3128f357e3SAlex Fikl typedef struct {
3228f357e3SAlex Fikl   struct _MatShellOps ops[1];
332205254eSKarl Rupp 
34b77ba244SStefano Zampini   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
35b77ba244SStefano Zampini   PetscBool managescalingshifts;
36b77ba244SStefano Zampini 
37b77ba244SStefano Zampini   /* support for MatScale, MatShift and MatMultAdd */
38ef66eb69SBarry Smith   PetscScalar vscale,vshift;
398fe8eb27SJed Brown   Vec         dshift;
408fe8eb27SJed Brown   Vec         left,right;
418fe8eb27SJed Brown   Vec         left_work,right_work;
425edf6516SJed Brown   Vec         left_add_work,right_add_work;
43b77ba244SStefano Zampini 
44ef5c7bd2SStefano Zampini   /* support for MatAXPY */
459f137db4SBarry Smith   Mat              axpy;
469f137db4SBarry Smith   PetscScalar      axpy_vscale;
47b77ba244SStefano Zampini   Vec              axpy_left,axpy_right;
48ef5c7bd2SStefano Zampini   PetscObjectState axpy_state;
49b77ba244SStefano Zampini 
5045960306SStefano Zampini   /* support for ZeroRows/Columns operations */
5145960306SStefano Zampini   IS         zrows;
5245960306SStefano Zampini   IS         zcols;
5345960306SStefano Zampini   Vec        zvals;
5445960306SStefano Zampini   Vec        zvals_w;
5545960306SStefano Zampini   VecScatter zvals_sct_r;
5645960306SStefano Zampini   VecScatter zvals_sct_c;
57b77ba244SStefano Zampini 
58b77ba244SStefano Zampini   /* MatMat operations */
59b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
60b77ba244SStefano Zampini 
61b77ba244SStefano Zampini   /* user defined context */
6220563c6bSBarry Smith   void *ctx;
6388cf3e7dSBarry Smith } Mat_Shell;
640c0fd78eSBarry Smith 
6545960306SStefano Zampini /*
6645960306SStefano Zampini      Store and scale values on zeroed rows
6745960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed columns
6845960306SStefano Zampini */
6945960306SStefano Zampini static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx)
7045960306SStefano Zampini {
7145960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
7245960306SStefano Zampini 
7345960306SStefano Zampini   PetscFunctionBegin;
7445960306SStefano Zampini   *xx = x;
7545960306SStefano Zampini   if (shell->zrows) {
769566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w,0.0));
779566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
789566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
799566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals));
8045960306SStefano Zampini   }
8145960306SStefano Zampini   if (shell->zcols) {
8245960306SStefano Zampini     if (!shell->right_work) {
839566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(A,&shell->right_work,NULL));
8445960306SStefano Zampini     }
859566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->right_work));
869566063dSJacob Faibussowitsch     PetscCall(VecISSet(shell->right_work,shell->zcols,0.0));
8745960306SStefano Zampini     *xx  = shell->right_work;
8845960306SStefano Zampini   }
8945960306SStefano Zampini   PetscFunctionReturn(0);
9045960306SStefano Zampini }
9145960306SStefano Zampini 
9245960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
9345960306SStefano Zampini static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x)
9445960306SStefano Zampini {
9545960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
9645960306SStefano Zampini 
9745960306SStefano Zampini   PetscFunctionBegin;
9845960306SStefano Zampini   if (shell->zrows) {
999566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE));
1009566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE));
10145960306SStefano Zampini   }
10245960306SStefano Zampini   PetscFunctionReturn(0);
10345960306SStefano Zampini }
10445960306SStefano Zampini 
10545960306SStefano Zampini /*
10645960306SStefano Zampini      Store and scale values on zeroed rows
10745960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
10845960306SStefano Zampini */
10945960306SStefano Zampini static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx)
11045960306SStefano Zampini {
11145960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
11245960306SStefano Zampini 
11345960306SStefano Zampini   PetscFunctionBegin;
11445960306SStefano Zampini   *xx = NULL;
11545960306SStefano Zampini   if (!shell->zrows) {
11645960306SStefano Zampini     *xx = x;
11745960306SStefano Zampini   } else {
11845960306SStefano Zampini     if (!shell->left_work) {
1199566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(A,NULL,&shell->left_work));
12045960306SStefano Zampini     }
1219566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->left_work));
1229566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w,0.0));
1239566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE));
1249566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE));
1259566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
1269566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
1279566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals));
12845960306SStefano Zampini     *xx  = shell->left_work;
12945960306SStefano Zampini   }
13045960306SStefano Zampini   PetscFunctionReturn(0);
13145960306SStefano Zampini }
13245960306SStefano Zampini 
13345960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
13445960306SStefano Zampini static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x)
13545960306SStefano Zampini {
13645960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
13745960306SStefano Zampini 
13845960306SStefano Zampini   PetscFunctionBegin;
1391baa6e33SBarry Smith   if (shell->zcols) PetscCall(VecISSet(x,shell->zcols,0.0));
14045960306SStefano Zampini   if (shell->zrows) {
1419566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE));
1429566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE));
14345960306SStefano Zampini   }
14445960306SStefano Zampini   PetscFunctionReturn(0);
14545960306SStefano Zampini }
14645960306SStefano Zampini 
1478fe8eb27SJed Brown /*
1480c0fd78eSBarry Smith       xx = diag(left)*x
1498fe8eb27SJed Brown */
1508fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
1518fe8eb27SJed Brown {
1528fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1538fe8eb27SJed Brown 
1548fe8eb27SJed Brown   PetscFunctionBegin;
1550298fd71SBarry Smith   *xx = NULL;
1568fe8eb27SJed Brown   if (!shell->left) {
1578fe8eb27SJed Brown     *xx = x;
1588fe8eb27SJed Brown   } else {
1599566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left,&shell->left_work));
1609566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->left_work,x,shell->left));
1618fe8eb27SJed Brown     *xx  = shell->left_work;
1628fe8eb27SJed Brown   }
1638fe8eb27SJed Brown   PetscFunctionReturn(0);
1648fe8eb27SJed Brown }
1658fe8eb27SJed Brown 
1660c0fd78eSBarry Smith /*
1670c0fd78eSBarry Smith      xx = diag(right)*x
1680c0fd78eSBarry Smith */
1698fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1708fe8eb27SJed Brown {
1718fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1728fe8eb27SJed Brown 
1738fe8eb27SJed Brown   PetscFunctionBegin;
1740298fd71SBarry Smith   *xx = NULL;
1758fe8eb27SJed Brown   if (!shell->right) {
1768fe8eb27SJed Brown     *xx = x;
1778fe8eb27SJed Brown   } else {
1789566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right,&shell->right_work));
1799566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work,x,shell->right));
1808fe8eb27SJed Brown     *xx  = shell->right_work;
1818fe8eb27SJed Brown   }
1828fe8eb27SJed Brown   PetscFunctionReturn(0);
1838fe8eb27SJed Brown }
1848fe8eb27SJed Brown 
1850c0fd78eSBarry Smith /*
1860c0fd78eSBarry Smith     x = diag(left)*x
1870c0fd78eSBarry Smith */
1888fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1898fe8eb27SJed Brown {
1908fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1918fe8eb27SJed Brown 
1928fe8eb27SJed Brown   PetscFunctionBegin;
1939566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x,x,shell->left));
1948fe8eb27SJed Brown   PetscFunctionReturn(0);
1958fe8eb27SJed Brown }
1968fe8eb27SJed Brown 
1970c0fd78eSBarry Smith /*
1980c0fd78eSBarry Smith     x = diag(right)*x
1990c0fd78eSBarry Smith */
2008fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
2018fe8eb27SJed Brown {
2028fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2038fe8eb27SJed Brown 
2048fe8eb27SJed Brown   PetscFunctionBegin;
2059566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(x,x,shell->right));
2068fe8eb27SJed Brown   PetscFunctionReturn(0);
2078fe8eb27SJed Brown }
2088fe8eb27SJed Brown 
2090c0fd78eSBarry Smith /*
2100c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2110c0fd78eSBarry Smith 
2120c0fd78eSBarry Smith          On input Y already contains A*x
2130c0fd78eSBarry Smith */
2148fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
2158fe8eb27SJed Brown {
2168fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2178fe8eb27SJed Brown 
2188fe8eb27SJed Brown   PetscFunctionBegin;
2198fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
2208fe8eb27SJed Brown     PetscInt          i,m;
2218fe8eb27SJed Brown     const PetscScalar *x,*d;
2228fe8eb27SJed Brown     PetscScalar       *y;
2239566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X,&m));
2249566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift,&d));
2259566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X,&x));
2269566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y,&y));
2278fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
2289566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift,&d));
2299566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X,&x));
2309566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y,&y));
2310c0fd78eSBarry Smith   } else {
2329566063dSJacob Faibussowitsch     PetscCall(VecScale(Y,shell->vscale));
2338fe8eb27SJed Brown   }
2349566063dSJacob Faibussowitsch   if (shell->vshift != 0.0) PetscCall(VecAXPY(Y,shell->vshift,X)); /* if test is for non-square matrices */
2358fe8eb27SJed Brown   PetscFunctionReturn(0);
2368fe8eb27SJed Brown }
237e51e0e81SBarry Smith 
238789d8953SBarry Smith PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx)
239789d8953SBarry Smith {
240789d8953SBarry Smith   PetscFunctionBegin;
241789d8953SBarry Smith   *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
242789d8953SBarry Smith   PetscFunctionReturn(0);
243789d8953SBarry Smith }
244789d8953SBarry Smith 
2459d225801SJed Brown /*@
246a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
247b4fd4287SBarry Smith 
248c7fcc2eaSBarry Smith     Not Collective
249c7fcc2eaSBarry Smith 
250b4fd4287SBarry Smith     Input Parameter:
251b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
252b4fd4287SBarry Smith 
253b4fd4287SBarry Smith     Output Parameter:
254b4fd4287SBarry Smith .   ctx - the user provided context
255b4fd4287SBarry Smith 
25615091d37SBarry Smith     Level: advanced
25715091d37SBarry Smith 
25895452b02SPatrick Sanan    Fortran Notes:
25995452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
260daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
261a62d957aSLois Curfman McInnes 
262db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2630bc0a719SBarry Smith @*/
2648fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
265b4fd4287SBarry Smith {
2663a40ed3dSBarry Smith   PetscFunctionBegin;
2670700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2684482741eSBarry Smith   PetscValidPointer(ctx,2);
269cac4c232SBarry Smith   PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx));
2703a40ed3dSBarry Smith   PetscFunctionReturn(0);
271b4fd4287SBarry Smith }
272b4fd4287SBarry Smith 
27345960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)
27445960306SStefano Zampini {
27545960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
27645960306SStefano Zampini   Vec            x = NULL,b = NULL;
27745960306SStefano Zampini   IS             is1, is2;
27845960306SStefano Zampini   const PetscInt *ridxs;
27945960306SStefano Zampini   PetscInt       *idxs,*gidxs;
28045960306SStefano Zampini   PetscInt       cum,rst,cst,i;
28145960306SStefano Zampini 
28245960306SStefano Zampini   PetscFunctionBegin;
28345960306SStefano Zampini   if (!shell->zvals) {
2849566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,NULL,&shell->zvals));
28545960306SStefano Zampini   }
28645960306SStefano Zampini   if (!shell->zvals_w) {
2879566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shell->zvals,&shell->zvals_w));
28845960306SStefano Zampini   }
2899566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat,&rst,NULL));
2909566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat,&cst,NULL));
29145960306SStefano Zampini 
29245960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&idxs));
29445960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
2959566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1));
2969566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2979566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals,is1,diag));
29845960306SStefano Zampini   if (shell->zrows) {
2999566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows,is1,&is2));
3009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
3019566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
30245960306SStefano Zampini     shell->zrows = is2;
30345960306SStefano Zampini   } else shell->zrows = is1;
30445960306SStefano Zampini 
30545960306SStefano Zampini   /* Create scatters for diagonal values communications */
3069566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
3079566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
30845960306SStefano Zampini 
30945960306SStefano Zampini   /* row scatter: from/to left vector */
3109566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat,&x,&b));
3119566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r));
31245960306SStefano Zampini 
31345960306SStefano Zampini   /* col scatter: from right vector to left vector */
3149566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows,&ridxs));
3159566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows,&nr));
3169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&gidxs));
31745960306SStefano Zampini   for (i = 0, cum  = 0; i < nr; i++) {
31845960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
31945960306SStefano Zampini     gidxs[cum] = ridxs[i];
32045960306SStefano Zampini     cum++;
32145960306SStefano Zampini   }
3229566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1));
3239566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c));
3249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
3259566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
3269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
32745960306SStefano Zampini 
32845960306SStefano Zampini   /* Expand/create index set of zeroed columns */
32945960306SStefano Zampini   if (rc) {
3309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc,&idxs));
33145960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3329566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1));
3339566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
33445960306SStefano Zampini     if (shell->zcols) {
3359566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols,is1,&is2));
3369566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
33845960306SStefano Zampini       shell->zcols = is2;
33945960306SStefano Zampini     } else shell->zcols = is1;
34045960306SStefano Zampini   }
34145960306SStefano Zampini   PetscFunctionReturn(0);
34245960306SStefano Zampini }
34345960306SStefano Zampini 
34445960306SStefano Zampini static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
34545960306SStefano Zampini {
346ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
34745960306SStefano Zampini   PetscInt       nr, *lrows;
34845960306SStefano Zampini 
34945960306SStefano Zampini   PetscFunctionBegin;
35045960306SStefano Zampini   if (x && b) {
35145960306SStefano Zampini     Vec          xt;
35245960306SStefano Zampini     PetscScalar *vals;
35345960306SStefano Zampini     PetscInt    *gcols,i,st,nl,nc;
35445960306SStefano Zampini 
3559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n,&gcols));
35645960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
35745960306SStefano Zampini 
3589566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&xt,NULL));
3599566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,xt));
3609566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc,&vals));
3619566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */
3629566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3639566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3649566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3659566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt,-1.0,x));                           /* xt = [0, x2] */
36645960306SStefano Zampini 
3679566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt,&st,NULL));
3689566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt,&nl));
3699566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt,&vals));
37045960306SStefano Zampini     for (i = 0; i < nl; i++) {
37145960306SStefano Zampini       PetscInt g = i + st;
37245960306SStefano Zampini       if (g > mat->rmap->N) continue;
37345960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3749566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b,g,diag*vals[i],INSERT_VALUES));
37545960306SStefano Zampini     }
3769566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt,&vals));
3779566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3789566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b));                            /* b  = [b1, x2 * diag] */
3799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3809566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
38145960306SStefano Zampini   }
3829566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL));
3839566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE));
3841baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL));
3859566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
38645960306SStefano Zampini   PetscFunctionReturn(0);
38745960306SStefano Zampini }
38845960306SStefano Zampini 
38945960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)
39045960306SStefano Zampini {
391ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
39245960306SStefano Zampini   PetscInt       *lrows, *lcols;
39345960306SStefano Zampini   PetscInt       nr, nc;
39445960306SStefano Zampini   PetscBool      congruent;
39545960306SStefano Zampini 
39645960306SStefano Zampini   PetscFunctionBegin;
39745960306SStefano Zampini   if (x && b) {
39845960306SStefano Zampini     Vec          xt, bt;
39945960306SStefano Zampini     PetscScalar *vals;
40045960306SStefano Zampini     PetscInt    *grows,*gcols,i,st,nl;
40145960306SStefano Zampini 
4029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n,&grows,n,&gcols));
40345960306SStefano Zampini     for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
40445960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
4059566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n,&vals));
40645960306SStefano Zampini 
4079566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&xt,&bt));
4089566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,xt));
4099566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */
4109566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
4119566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
4129566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt,-1.0,x));                           /* xt = [0, -x2] */
4139566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,xt,bt));                           /* bt = [-A12*x2,-A22*x2] */
4149566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* bt = [-A12*x2,0] */
4159566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4169566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4179566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b,1.0,bt));                            /* b  = [b1 - A12*x2, b2] */
4189566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
4199566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4209566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4219566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
42245960306SStefano Zampini 
4239566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt,&st,NULL));
4249566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt,&nl));
4259566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt,&vals));
42645960306SStefano Zampini     for (i = 0; i < nl; i++) {
42745960306SStefano Zampini       PetscInt g = i + st;
42845960306SStefano Zampini       if (g > mat->rmap->N) continue;
42945960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4309566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b,g,-diag*vals[i],INSERT_VALUES));
43145960306SStefano Zampini     }
4329566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt,&vals));
4339566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4349566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b));                            /* b  = [b1 - A12*x2, x2 * diag] */
4359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4379566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows,gcols));
43845960306SStefano Zampini   }
4399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL));
4409566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat,&congruent));
44145960306SStefano Zampini   if (congruent) {
44245960306SStefano Zampini     nc    = nr;
44345960306SStefano Zampini     lcols = lrows;
44445960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
44545960306SStefano Zampini     PetscInt i,nt,*t;
44645960306SStefano Zampini 
4479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n,&t));
44845960306SStefano Zampini     for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4499566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL));
4509566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
45145960306SStefano Zampini   }
4529566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE));
45345960306SStefano Zampini   if (!congruent) {
4549566063dSJacob Faibussowitsch     PetscCall(PetscFree(lcols));
45545960306SStefano Zampini   }
4569566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4571baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL));
45845960306SStefano Zampini   PetscFunctionReturn(0);
45945960306SStefano Zampini }
46045960306SStefano Zampini 
461dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
462e51e0e81SBarry Smith {
463bf0cc555SLisandro Dalcin   Mat_Shell               *shell = (Mat_Shell*)mat->data;
464b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
465ed3cc1f0SBarry Smith 
4663a40ed3dSBarry Smith   PetscFunctionBegin;
4671baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4689566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops,sizeof(struct _MatShellOps)));
4699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4819566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4829566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4849566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
485b77ba244SStefano Zampini 
486b77ba244SStefano Zampini   matmat = shell->matmat;
487b77ba244SStefano Zampini   while (matmat) {
488b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
489b77ba244SStefano Zampini 
4909566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL));
4919566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
4929566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
4939566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
494b77ba244SStefano Zampini     matmat = next;
495b77ba244SStefano Zampini   }
4969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL));
4979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL));
4989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL));
4999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL));
5009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL));
5019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL));
5029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL));
5039566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
504b77ba244SStefano Zampini   PetscFunctionReturn(0);
505b77ba244SStefano Zampini }
506b77ba244SStefano Zampini 
507b77ba244SStefano Zampini typedef struct {
508b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat,Mat,Mat,void*);
509b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void*);
510b77ba244SStefano Zampini   void           *userdata;
511b77ba244SStefano Zampini   Mat            B;
512b77ba244SStefano Zampini   Mat            Bt;
513b77ba244SStefano Zampini   Mat            axpy;
514b77ba244SStefano Zampini } MatMatDataShell;
515b77ba244SStefano Zampini 
516b77ba244SStefano Zampini static PetscErrorCode DestroyMatMatDataShell(void *data)
517b77ba244SStefano Zampini {
518b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
519b77ba244SStefano Zampini 
520b77ba244SStefano Zampini   PetscFunctionBegin;
5211baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
5229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5259566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
526b77ba244SStefano Zampini   PetscFunctionReturn(0);
527b77ba244SStefano Zampini }
528b77ba244SStefano Zampini 
529b77ba244SStefano Zampini static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
530b77ba244SStefano Zampini {
531b77ba244SStefano Zampini   Mat_Product     *product;
532b77ba244SStefano Zampini   Mat             A, B;
533b77ba244SStefano Zampini   MatMatDataShell *mdata;
534b77ba244SStefano Zampini   PetscScalar     zero = 0.0;
535b77ba244SStefano Zampini 
536b77ba244SStefano Zampini   PetscFunctionBegin;
537b77ba244SStefano Zampini   MatCheckProduct(D,1);
538b77ba244SStefano Zampini   product = D->product;
53928b400f6SJacob Faibussowitsch   PetscCheck(product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty");
540b77ba244SStefano Zampini   A = product->A;
541b77ba244SStefano Zampini   B = product->B;
542b77ba244SStefano Zampini   mdata = (MatMatDataShell*)product->data;
543b77ba244SStefano Zampini   if (mdata->numeric) {
544b77ba244SStefano Zampini     Mat_Shell      *shell = (Mat_Shell*)A->data;
545b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
546b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
547b77ba244SStefano Zampini     PetscBool      useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
548b77ba244SStefano Zampini 
549b77ba244SStefano Zampini     if (shell->managescalingshifts) {
55008401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns");
551b77ba244SStefano Zampini       if (shell->right || shell->left) {
552b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
553b77ba244SStefano Zampini         if (!mdata->B) {
5549566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B));
555b77ba244SStefano Zampini         } else {
556b77ba244SStefano Zampini           newB = PETSC_FALSE;
557b77ba244SStefano Zampini         }
5589566063dSJacob Faibussowitsch         PetscCall(MatCopy(B,mdata->B,SAME_NONZERO_PATTERN));
559b77ba244SStefano Zampini       }
560b77ba244SStefano Zampini       switch (product->type) {
561b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5621baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL));
563b77ba244SStefano Zampini         break;
564b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5651baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B,shell->left,NULL));
566b77ba244SStefano Zampini         break;
567b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5681baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right));
569b77ba244SStefano Zampini         break;
570b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
571b77ba244SStefano Zampini         if (shell->right && shell->left) {
572b77ba244SStefano Zampini           PetscBool flg;
573b77ba244SStefano Zampini 
5749566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right,shell->left,&flg));
57528b400f6SJacob Faibussowitsch           PetscCheck(flg,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
576b77ba244SStefano Zampini         }
5771baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right));
578b77ba244SStefano Zampini         break;
579b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
580b77ba244SStefano Zampini         if (shell->right && shell->left) {
581b77ba244SStefano Zampini           PetscBool flg;
582b77ba244SStefano Zampini 
5839566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right,shell->left,&flg));
58428b400f6SJacob Faibussowitsch           PetscCheck(flg,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
585b77ba244SStefano Zampini         }
5861baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL));
587b77ba244SStefano Zampini         break;
58898921bdaSJacob Faibussowitsch       default: SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
589b77ba244SStefano Zampini       }
590b77ba244SStefano Zampini     }
591b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
592b77ba244SStefano Zampini     D->product = NULL;
593b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
594b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
595b77ba244SStefano Zampini 
5969566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata));
597b77ba244SStefano Zampini 
598b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
5999566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
600b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
601b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
602b77ba244SStefano Zampini     D->product = product;
603b77ba244SStefano Zampini 
604b77ba244SStefano Zampini     if (shell->managescalingshifts) {
6059566063dSJacob Faibussowitsch       PetscCall(MatScale(D,shell->vscale));
606b77ba244SStefano Zampini       switch (product->type) {
607b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
608b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
609b77ba244SStefano Zampini         if (shell->left) {
6109566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D,shell->left,NULL));
611b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
6129566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A,NULL,&shell->left_work));
613b77ba244SStefano Zampini             if (shell->dshift) {
6149566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift,shell->left_work));
6159566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work,shell->vshift));
6169566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work,shell->left_work,shell->left));
617b77ba244SStefano Zampini             } else {
6189566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work,shell->vshift));
619b77ba244SStefano Zampini             }
620b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
621b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
622b77ba244SStefano Zampini               MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
623b77ba244SStefano Zampini 
6249566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B,reuse,&mdata->Bt));
6259566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt,shell->left_work,NULL));
6269566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D,1.0,mdata->Bt,str));
627b77ba244SStefano Zampini             } else {
628b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
629b77ba244SStefano Zampini 
6309566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B,shell->left_work,NULL));
6319566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D,1.0,mdata->B,str));
632b77ba244SStefano Zampini             }
633b77ba244SStefano Zampini           }
634b77ba244SStefano Zampini         }
635b77ba244SStefano Zampini         break;
636b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
637b77ba244SStefano Zampini         if (shell->right) {
6389566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D,shell->right,NULL));
639b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
640b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
641b77ba244SStefano Zampini 
6429566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A,&shell->right_work,NULL));
643b77ba244SStefano Zampini             if (shell->dshift) {
6449566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift,shell->right_work));
6459566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work,shell->vshift));
6469566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work,shell->right_work,shell->right));
647b77ba244SStefano Zampini             } else {
6489566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work,shell->vshift));
649b77ba244SStefano Zampini             }
6509566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B,shell->right_work,NULL));
6519566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D,1.0,mdata->B,str));
652b77ba244SStefano Zampini           }
653b77ba244SStefano Zampini         }
654b77ba244SStefano Zampini         break;
655b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
656b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
657aed4548fSBarry Smith         PetscCheck(!shell->dshift && shell->vshift == zero,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices with diagonal shift",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
658b77ba244SStefano Zampini         break;
65998921bdaSJacob Faibussowitsch       default: SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
660b77ba244SStefano Zampini       }
661b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
662b77ba244SStefano Zampini         Mat              X;
663b77ba244SStefano Zampini         PetscObjectState axpy_state;
664b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
665b77ba244SStefano Zampini 
6669566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy,&X));
6679566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
66808401ef6SPierre Jolivet         PetscCheck(shell->axpy_state == axpy_state,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
669b77ba244SStefano Zampini         if (!mdata->axpy) {
670b77ba244SStefano Zampini           str  = DIFFERENT_NONZERO_PATTERN;
6719566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy,B,NULL,&mdata->axpy));
6729566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy,product->type));
6739566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6749566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
675b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
676b77ba244SStefano Zampini           PetscBool flg;
677b77ba244SStefano Zampini 
6789566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy));
6799566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg));
680b77ba244SStefano Zampini           if (!flg) {
681b77ba244SStefano Zampini             str  = DIFFERENT_NONZERO_PATTERN;
6829566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
6839566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
684b77ba244SStefano Zampini           }
685b77ba244SStefano Zampini         }
6869566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
6879566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D,shell->axpy_vscale,mdata->axpy,str));
688b77ba244SStefano Zampini       }
689b77ba244SStefano Zampini     }
690b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation");
691b77ba244SStefano Zampini   PetscFunctionReturn(0);
692b77ba244SStefano Zampini }
693b77ba244SStefano Zampini 
694b77ba244SStefano Zampini static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
695b77ba244SStefano Zampini {
696b77ba244SStefano Zampini   Mat_Product             *product;
697b77ba244SStefano Zampini   Mat                     A,B;
698b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
699b77ba244SStefano Zampini   Mat_Shell               *shell;
700b77ba244SStefano Zampini   PetscBool               flg;
701b77ba244SStefano Zampini   char                    composedname[256];
702b77ba244SStefano Zampini   MatMatDataShell         *mdata;
703b77ba244SStefano Zampini 
704b77ba244SStefano Zampini   PetscFunctionBegin;
705b77ba244SStefano Zampini   MatCheckProduct(D,1);
706b77ba244SStefano Zampini   product = D->product;
70728b400f6SJacob Faibussowitsch   PetscCheck(!product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty");
708b77ba244SStefano Zampini   A = product->A;
709b77ba244SStefano Zampini   B = product->B;
710b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
711b77ba244SStefano Zampini   matmat = shell->matmat;
7129566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name));
713b77ba244SStefano Zampini   while (matmat) {
7149566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg));
715b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
716b77ba244SStefano Zampini     if (flg) break;
717b77ba244SStefano Zampini     matmat = matmat->next;
718b77ba244SStefano Zampini   }
71928b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]);
720b77ba244SStefano Zampini   switch (product->type) {
721b77ba244SStefano Zampini   case MATPRODUCT_AB:
7229566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N));
723b77ba244SStefano Zampini     break;
724b77ba244SStefano Zampini   case MATPRODUCT_AtB:
7259566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N));
726b77ba244SStefano Zampini     break;
727b77ba244SStefano Zampini   case MATPRODUCT_ABt:
7289566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N));
729b77ba244SStefano Zampini     break;
730b77ba244SStefano Zampini   case MATPRODUCT_RARt:
7319566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N));
732b77ba244SStefano Zampini     break;
733b77ba244SStefano Zampini   case MATPRODUCT_PtAP:
7349566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N));
735b77ba244SStefano Zampini     break;
73698921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
737b77ba244SStefano Zampini   }
738b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
739b77ba244SStefano Zampini   if (matmat->resultname) {
7409566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg));
741b77ba244SStefano Zampini     if (!flg) {
7429566063dSJacob Faibussowitsch       PetscCall(MatSetType(D,matmat->resultname));
743b77ba244SStefano Zampini     }
744b77ba244SStefano Zampini   }
745b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
746b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
747b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
748b77ba244SStefano Zampini   /* attach product data */
7499566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
750b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
751b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
752b77ba244SStefano Zampini   if (matmat->symbolic) {
7539566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A,B,D,&mdata->userdata));
754b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7559566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
756b77ba244SStefano Zampini   }
75728b400f6SJacob Faibussowitsch   PetscCheck(D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase");
75828b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase");
759b77ba244SStefano Zampini   D->product->data = mdata;
760b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
761b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
762b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
763b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
764b77ba244SStefano Zampini   PetscFunctionReturn(0);
765b77ba244SStefano Zampini }
766b77ba244SStefano Zampini 
767b77ba244SStefano Zampini static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
768b77ba244SStefano Zampini {
769b77ba244SStefano Zampini   Mat_Product             *product;
770b77ba244SStefano Zampini   Mat                     A,B;
771b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
772b77ba244SStefano Zampini   Mat_Shell               *shell;
773b77ba244SStefano Zampini   PetscBool               flg;
774b77ba244SStefano Zampini   char                    composedname[256];
775b77ba244SStefano Zampini 
776b77ba244SStefano Zampini   PetscFunctionBegin;
777b77ba244SStefano Zampini   MatCheckProduct(D,1);
778b77ba244SStefano Zampini   product = D->product;
779b77ba244SStefano Zampini   A = product->A;
780b77ba244SStefano Zampini   B = product->B;
7819566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A,&flg));
782b77ba244SStefano Zampini   if (!flg) PetscFunctionReturn(0);
783b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
784b77ba244SStefano Zampini   matmat = shell->matmat;
7859566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name));
786b77ba244SStefano Zampini   while (matmat) {
7879566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg));
788b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
789b77ba244SStefano Zampini     if (flg) break;
790b77ba244SStefano Zampini     matmat = matmat->next;
791b77ba244SStefano Zampini   }
792b77ba244SStefano Zampini   if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; }
7939566063dSJacob Faibussowitsch   else PetscCall(PetscInfo(D,"  symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type]));
794b77ba244SStefano Zampini   PetscFunctionReturn(0);
795b77ba244SStefano Zampini }
796b77ba244SStefano Zampini 
797b77ba244SStefano Zampini static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void*),char *composedname,const char *resultname)
798b77ba244SStefano Zampini {
799b77ba244SStefano Zampini   PetscBool               flg;
800b77ba244SStefano Zampini   Mat_Shell               *shell;
801b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
802b77ba244SStefano Zampini 
803b77ba244SStefano Zampini   PetscFunctionBegin;
80428b400f6SJacob Faibussowitsch   PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine");
80528b400f6SJacob Faibussowitsch   PetscCheck(composedname,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name");
806b77ba244SStefano Zampini 
807b77ba244SStefano Zampini   /* add product callback */
808b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
809b77ba244SStefano Zampini   matmat = shell->matmat;
810b77ba244SStefano Zampini   if (!matmat) {
8119566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
812b77ba244SStefano Zampini     matmat = shell->matmat;
813b77ba244SStefano Zampini   } else {
814b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
815b77ba244SStefano Zampini     while (entry) {
8169566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname,entry->composedname,&flg));
817b77ba244SStefano Zampini       flg  = (PetscBool)(flg && (entry->ptype == ptype));
818b77ba244SStefano Zampini       matmat = entry;
8192e956fe4SStefano Zampini       if (flg) goto set;
820b77ba244SStefano Zampini       entry = entry->next;
821b77ba244SStefano Zampini     }
8229566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
823b77ba244SStefano Zampini     matmat = matmat->next;
824b77ba244SStefano Zampini   }
825b77ba244SStefano Zampini 
826843d480fSStefano Zampini set:
827b77ba244SStefano Zampini   matmat->symbolic = symbolic;
828b77ba244SStefano Zampini   matmat->numeric  = numeric;
829b77ba244SStefano Zampini   matmat->destroy  = destroy;
830b77ba244SStefano Zampini   matmat->ptype    = ptype;
8319566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8329566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8339566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname,&matmat->composedname));
8349566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname,&matmat->resultname));
8359566063dSJacob Faibussowitsch   PetscCall(PetscInfo(A,"Composing %s for product type %s with result %s\n",matmat->composedname,MatProductTypes[matmat->ptype],matmat->resultname ? matmat->resultname : "not specified"));
8369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X));
837b77ba244SStefano Zampini   PetscFunctionReturn(0);
838b77ba244SStefano Zampini }
839b77ba244SStefano Zampini 
840b77ba244SStefano Zampini /*@C
841b77ba244SStefano Zampini     MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix.
842b77ba244SStefano Zampini 
843b77ba244SStefano Zampini    Logically Collective on Mat
844b77ba244SStefano Zampini 
845b77ba244SStefano Zampini     Input Parameters:
846b77ba244SStefano Zampini +   A - the shell matrix
847b77ba244SStefano Zampini .   ptype - the product type
848b77ba244SStefano Zampini .   symbolic - the function for the symbolic phase (can be NULL)
849b77ba244SStefano Zampini .   numeric - the function for the numerical phase
850b77ba244SStefano Zampini .   destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL)
851b77ba244SStefano Zampini .   Btype - the matrix type for the matrix to be multiplied against
852b77ba244SStefano Zampini -   Ctype - the matrix type for the result (can be NULL)
853b77ba244SStefano Zampini 
854b77ba244SStefano Zampini    Level: advanced
855b77ba244SStefano Zampini 
856b77ba244SStefano Zampini     Usage:
857b77ba244SStefano Zampini $      extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**);
858b77ba244SStefano Zampini $      extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*);
859b77ba244SStefano Zampini $      extern PetscErrorCode userdestroy(void*);
860b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
861b77ba244SStefano Zampini $      MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE);
862b77ba244SStefano Zampini $      [ create B of type SEQAIJ etc..]
863b77ba244SStefano Zampini $      MatProductCreate(A,B,NULL,&C);
864b77ba244SStefano Zampini $      MatProductSetType(C,MATPRODUCT_AB);
865b77ba244SStefano Zampini $      MatProductSetFromOptions(C);
866b77ba244SStefano Zampini $      MatProductSymbolic(C); -> actually runs the user defined symbolic operation
867b77ba244SStefano Zampini $      MatProductNumeric(C); -> actually runs the user defined numeric operation
868b77ba244SStefano Zampini $      [ use C = A*B ]
869b77ba244SStefano Zampini 
870b77ba244SStefano Zampini     Notes:
871b77ba244SStefano Zampini     MATPRODUCT_ABC is not supported yet. Not supported in Fortran.
872b77ba244SStefano Zampini     If the symbolic phase is not specified, MatSetUp() is called on the result matrix that must have its type set if Ctype is NULL.
873b77ba244SStefano Zampini     Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
874b77ba244SStefano Zampini     PETSc will take care of calling the user-defined callbacks.
875b77ba244SStefano Zampini     It is allowed to specify the same callbacks for different Btype matrix types.
876b77ba244SStefano Zampini     The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence.
877b77ba244SStefano Zampini 
878db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
879b77ba244SStefano Zampini @*/
880b77ba244SStefano Zampini PetscErrorCode MatShellSetMatProductOperation(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void *),MatType Btype,MatType Ctype)
881b77ba244SStefano Zampini {
882b77ba244SStefano Zampini   PetscFunctionBegin;
883b77ba244SStefano Zampini   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
884b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A,ptype,2);
88508401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]);
88628b400f6SJacob Faibussowitsch   PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4");
887dadcf809SJacob Faibussowitsch   PetscValidCharPointer(Btype,6);
888dadcf809SJacob Faibussowitsch   if (Ctype) PetscValidCharPointer(Ctype,7);
889cac4c232SBarry Smith   PetscTryMethod(A,"MatShellSetMatProductOperation_C",(Mat,MatProductType,PetscErrorCode(*)(Mat,Mat,Mat,void**),PetscErrorCode(*)(Mat,Mat,Mat,void*),PetscErrorCode(*)(void*),MatType,MatType),(A,ptype,symbolic,numeric,destroy,Btype,Ctype));
890b77ba244SStefano Zampini   PetscFunctionReturn(0);
891b77ba244SStefano Zampini }
892b77ba244SStefano Zampini 
893b77ba244SStefano Zampini PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A,MatProductType ptype,PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**),PetscErrorCode (*numeric)(Mat,Mat,Mat,void*),PetscErrorCode (*destroy)(void *),MatType Btype,MatType Ctype)
894b77ba244SStefano Zampini {
895b77ba244SStefano Zampini   PetscBool      flg;
896b77ba244SStefano Zampini   char           composedname[256];
897b77ba244SStefano Zampini   MatRootName    Bnames = MatRootNameList, Cnames = MatRootNameList;
898b77ba244SStefano Zampini   PetscMPIInt    size;
899b77ba244SStefano Zampini 
900b77ba244SStefano Zampini   PetscFunctionBegin;
901b77ba244SStefano Zampini   PetscValidType(A,1);
902b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9039566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype,Bnames->rname,&flg));
904b77ba244SStefano Zampini     if (flg) break;
905b77ba244SStefano Zampini     Bnames = Bnames->next;
906b77ba244SStefano Zampini   }
907b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9089566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype,Cnames->rname,&flg));
909b77ba244SStefano Zampini     if (flg) break;
910b77ba244SStefano Zampini     Cnames = Cnames->next;
911b77ba244SStefano Zampini   }
9129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size));
913b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
914b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9159566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype));
9169566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype));
9173a40ed3dSBarry Smith   PetscFunctionReturn(0);
918e51e0e81SBarry Smith }
919e51e0e81SBarry Smith 
9207fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
9217fabda3fSAlex Fikl {
92228f357e3SAlex Fikl   Mat_Shell               *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
923cb8c8a77SBarry Smith   PetscBool               matflg;
924b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9257fabda3fSAlex Fikl 
9267fabda3fSAlex Fikl   PetscFunctionBegin;
9279566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B,&matflg));
92828b400f6SJacob Faibussowitsch   PetscCheck(matflg,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name);
9297fabda3fSAlex Fikl 
9309566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps)));
9319566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps)));
9327fabda3fSAlex Fikl 
9331baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A,B,str));
9347fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9357fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9360c0fd78eSBarry Smith   if (shellA->dshift) {
9370c0fd78eSBarry Smith     if (!shellB->dshift) {
9389566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->dshift,&shellB->dshift));
9397fabda3fSAlex Fikl     }
9409566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift,shellB->dshift));
9417fabda3fSAlex Fikl   } else {
9429566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9437fabda3fSAlex Fikl   }
9440c0fd78eSBarry Smith   if (shellA->left) {
9450c0fd78eSBarry Smith     if (!shellB->left) {
9469566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->left,&shellB->left));
9477fabda3fSAlex Fikl     }
9489566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left,shellB->left));
9497fabda3fSAlex Fikl   } else {
9509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9517fabda3fSAlex Fikl   }
9520c0fd78eSBarry Smith   if (shellA->right) {
9530c0fd78eSBarry Smith     if (!shellB->right) {
9549566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->right,&shellB->right));
9557fabda3fSAlex Fikl     }
9569566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right,shellB->right));
9577fabda3fSAlex Fikl   } else {
9589566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9597fabda3fSAlex Fikl   }
9609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
961ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
962ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
96340e381c3SBarry Smith   if (shellA->axpy) {
9649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
96540e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
96640e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
967ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
96840e381c3SBarry Smith   }
96945960306SStefano Zampini   if (shellA->zrows) {
9709566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows,&shellB->zrows));
97145960306SStefano Zampini     if (shellA->zcols) {
9729566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(shellA->zcols,&shellB->zcols));
97345960306SStefano Zampini     }
9749566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals,&shellB->zvals));
9759566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals,shellB->zvals));
9769566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w,&shellB->zvals_w));
9779566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9789566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
97945960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
98045960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
98145960306SStefano Zampini   }
982b77ba244SStefano Zampini 
983b77ba244SStefano Zampini   matmatA = shellA->matmat;
984b77ba244SStefano Zampini   if (matmatA) {
985b77ba244SStefano Zampini     while (matmatA->next) {
9869566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname));
987b77ba244SStefano Zampini       matmatA = matmatA->next;
988b77ba244SStefano Zampini     }
989b77ba244SStefano Zampini   }
9907fabda3fSAlex Fikl   PetscFunctionReturn(0);
9917fabda3fSAlex Fikl }
9927fabda3fSAlex Fikl 
993cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
994cb8c8a77SBarry Smith {
995cb8c8a77SBarry Smith   void           *ctx;
996cb8c8a77SBarry Smith 
997cb8c8a77SBarry Smith   PetscFunctionBegin;
9989566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(mat,&ctx));
9999566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M));
10009566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name));
1001a4b1380bSStefano Zampini   if (op != MAT_DO_NOT_COPY_VALUES) {
10029566063dSJacob Faibussowitsch     PetscCall(MatCopy(mat,*M,SAME_NONZERO_PATTERN));
1003a4b1380bSStefano Zampini   }
1004cb8c8a77SBarry Smith   PetscFunctionReturn(0);
1005cb8c8a77SBarry Smith }
1006cb8c8a77SBarry Smith 
1007dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
1008ef66eb69SBarry Smith {
1009ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
101025578ef6SJed Brown   Vec              xx;
1011e3f487b0SBarry Smith   PetscObjectState instate,outstate;
1012ef66eb69SBarry Smith 
1013ef66eb69SBarry Smith   PetscFunctionBegin;
101428b400f6SJacob Faibussowitsch   PetscCheck(shell->ops->mult,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
10159566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A,x,&xx));
10169566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A,xx,&xx));
10179566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10189566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A,xx,y));
10199566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1020e3f487b0SBarry Smith   if (instate == outstate) {
1021e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10229566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1023e3f487b0SBarry Smith   }
10249566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A,xx,y));
10259566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A,y));
10269566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A,y));
10279f137db4SBarry Smith 
10289f137db4SBarry Smith   if (shell->axpy) {
1029ef5c7bd2SStefano Zampini     Mat              X;
1030ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1031ef5c7bd2SStefano Zampini 
10329566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
10339566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
103408401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1035b77ba244SStefano Zampini 
10369566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left));
10379566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->axpy_right));
10389566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy,shell->axpy_right,shell->axpy_left));
10399566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_left));
10409f137db4SBarry Smith   }
1041ef66eb69SBarry Smith   PetscFunctionReturn(0);
1042ef66eb69SBarry Smith }
1043ef66eb69SBarry Smith 
10445edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
10455edf6516SJed Brown {
10465edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
10475edf6516SJed Brown 
10485edf6516SJed Brown   PetscFunctionBegin;
10495edf6516SJed Brown   if (y == z) {
10509566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z,&shell->right_add_work));
10519566063dSJacob Faibussowitsch     PetscCall(MatMult(A,x,shell->right_add_work));
10529566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,shell->right_add_work));
10535edf6516SJed Brown   } else {
10549566063dSJacob Faibussowitsch     PetscCall(MatMult(A,x,z));
10559566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,y));
10565edf6516SJed Brown   }
10575edf6516SJed Brown   PetscFunctionReturn(0);
10585edf6516SJed Brown }
10595edf6516SJed Brown 
106018be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
106118be62a5SSatish Balay {
106218be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
106325578ef6SJed Brown   Vec              xx;
1064e3f487b0SBarry Smith   PetscObjectState instate,outstate;
106518be62a5SSatish Balay 
106618be62a5SSatish Balay   PetscFunctionBegin;
106728b400f6SJacob Faibussowitsch   PetscCheck(shell->ops->multtranspose,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
10689566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A,x,&xx));
10699566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleLeft(A,xx,&xx));
10709566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10719566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A,xx,y));
10729566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1073e3f487b0SBarry Smith   if (instate == outstate) {
1074e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10759566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1076e3f487b0SBarry Smith   }
10779566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A,xx,y));
10789566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleRight(A,y));
10799566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A,y));
1080350ec83bSStefano Zampini 
1081350ec83bSStefano Zampini   if (shell->axpy) {
1082ef5c7bd2SStefano Zampini     Mat              X;
1083ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1084ef5c7bd2SStefano Zampini 
10859566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
10869566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
108708401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
10889566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left));
10899566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->axpy_left));
10909566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right));
10919566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_right));
1092350ec83bSStefano Zampini   }
109318be62a5SSatish Balay   PetscFunctionReturn(0);
109418be62a5SSatish Balay }
109518be62a5SSatish Balay 
10965edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
10975edf6516SJed Brown {
10985edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
10995edf6516SJed Brown 
11005edf6516SJed Brown   PetscFunctionBegin;
11015edf6516SJed Brown   if (y == z) {
11029566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z,&shell->left_add_work));
11039566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A,x,shell->left_add_work));
11049566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,shell->left_add_work));
11055edf6516SJed Brown   } else {
11069566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A,x,z));
11079566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,y));
11085edf6516SJed Brown   }
11095edf6516SJed Brown   PetscFunctionReturn(0);
11105edf6516SJed Brown }
11115edf6516SJed Brown 
11120c0fd78eSBarry Smith /*
11130c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11140c0fd78eSBarry Smith */
111518be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
111618be62a5SSatish Balay {
111718be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
111818be62a5SSatish Balay 
111918be62a5SSatish Balay   PetscFunctionBegin;
11200c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11219566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A,v));
1122305211d5SBarry 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,...)");
11239566063dSJacob Faibussowitsch   PetscCall(VecScale(v,shell->vscale));
11241baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v,1.0,shell->dshift));
11259566063dSJacob Faibussowitsch   PetscCall(VecShift(v,shell->vshift));
11269566063dSJacob Faibussowitsch   if (shell->left)  PetscCall(VecPointwiseMult(v,v,shell->left));
11279566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v,v,shell->right));
112845960306SStefano Zampini   if (shell->zrows) {
11299566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE));
11309566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE));
113145960306SStefano Zampini   }
113281c02519SBarry Smith   if (shell->axpy) {
1133ef5c7bd2SStefano Zampini     Mat              X;
1134ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1135ef5c7bd2SStefano Zampini 
11369566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
11379566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
113808401ef6SPierre Jolivet     PetscCheck(shell->axpy_state == axpy_state,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
11399566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left));
11409566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy,shell->axpy_left));
11419566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v,shell->axpy_vscale,shell->axpy_left));
114281c02519SBarry Smith   }
114318be62a5SSatish Balay   PetscFunctionReturn(0);
114418be62a5SSatish Balay }
114518be62a5SSatish Balay 
1146f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
1147ef66eb69SBarry Smith {
1148ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1149789d8953SBarry Smith   PetscBool      flg;
1150b24ad042SBarry Smith 
1151ef66eb69SBarry Smith   PetscFunctionBegin;
11529566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y,&flg));
115328b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent");
11540c0fd78eSBarry Smith   if (shell->left || shell->right) {
11558fe8eb27SJed Brown     if (!shell->dshift) {
11569566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11579566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift,a));
11580c0fd78eSBarry Smith     } else {
11599566063dSJacob Faibussowitsch       if (shell->left)  PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->left));
11609566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->right));
11619566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift,a));
11620c0fd78eSBarry Smith     }
11639566063dSJacob Faibussowitsch     if (shell->left)  PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->left));
11649566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->right));
11658fe8eb27SJed Brown   } else shell->vshift += a;
11661baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals,a));
1167ef66eb69SBarry Smith   PetscFunctionReturn(0);
1168ef66eb69SBarry Smith }
1169ef66eb69SBarry Smith 
1170b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
11716464bf51SAlex Fikl {
11726464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
11736464bf51SAlex Fikl 
11746464bf51SAlex Fikl   PetscFunctionBegin;
11759566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D,&shell->dshift));
11760c0fd78eSBarry Smith   if (shell->left || shell->right) {
11779566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
11789f137db4SBarry Smith     if (shell->left && shell->right)  {
11799566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left));
11809566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,shell->right_work,shell->right));
11819f137db4SBarry Smith     } else if (shell->left) {
11829566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left));
11839f137db4SBarry Smith     } else {
11849566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->right));
11859f137db4SBarry Smith     }
11869566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift,s,shell->right_work));
11870c0fd78eSBarry Smith   } else {
11889566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift,s,D));
1189b253ae0bS“Marek   }
1190b253ae0bS“Marek   PetscFunctionReturn(0);
1191b253ae0bS“Marek }
1192b253ae0bS“Marek 
1193b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
1194b253ae0bS“Marek {
119545960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
1196b253ae0bS“Marek   Vec            d;
1197789d8953SBarry Smith   PetscBool      flg;
1198b253ae0bS“Marek 
1199b253ae0bS“Marek   PetscFunctionBegin;
12009566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A,&flg));
120128b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent");
1202b253ae0bS“Marek   if (ins == INSERT_VALUES) {
120328b400f6SJacob Faibussowitsch     PetscCheck(A->ops->getdiagonal,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
12049566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D,&d));
12059566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A,d));
12069566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,d,-1.));
12079566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,D,1.));
12089566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12091baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D,shell->zvals));
1210b253ae0bS“Marek   } else {
12119566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,D,1.));
12121baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals,1.0,D));
12136464bf51SAlex Fikl   }
12146464bf51SAlex Fikl   PetscFunctionReturn(0);
12156464bf51SAlex Fikl }
12166464bf51SAlex Fikl 
1217f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
1218ef66eb69SBarry Smith {
1219ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1220b24ad042SBarry Smith 
1221ef66eb69SBarry Smith   PetscFunctionBegin;
1222f4df32b1SMatthew Knepley   shell->vscale *= a;
12230c0fd78eSBarry Smith   shell->vshift *= a;
12241baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift,a));
122581c02519SBarry Smith   shell->axpy_vscale *= a;
12261baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals,a));
12278fe8eb27SJed Brown   PetscFunctionReturn(0);
122818be62a5SSatish Balay }
12298fe8eb27SJed Brown 
12308fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
12318fe8eb27SJed Brown {
12328fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12338fe8eb27SJed Brown 
12348fe8eb27SJed Brown   PetscFunctionBegin;
12358fe8eb27SJed Brown   if (left) {
12360c0fd78eSBarry Smith     if (!shell->left) {
12379566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left,&shell->left));
12389566063dSJacob Faibussowitsch       PetscCall(VecCopy(left,shell->left));
12390c0fd78eSBarry Smith     } else {
12409566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left,shell->left,left));
124118be62a5SSatish Balay     }
12421baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,left));
1243ef66eb69SBarry Smith   }
12448fe8eb27SJed Brown   if (right) {
12450c0fd78eSBarry Smith     if (!shell->right) {
12469566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right,&shell->right));
12479566063dSJacob Faibussowitsch       PetscCall(VecCopy(right,shell->right));
12480c0fd78eSBarry Smith     } else {
12499566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right,shell->right,right));
12508fe8eb27SJed Brown     }
125145960306SStefano Zampini     if (shell->zrows) {
125245960306SStefano Zampini       if (!shell->left_work) {
12539566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(Y,NULL,&shell->left_work));
125445960306SStefano Zampini       }
12559566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w,1.0));
12569566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
12579566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
12589566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w));
125945960306SStefano Zampini     }
12608fe8eb27SJed Brown   }
12611baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy,left,right));
1262ef66eb69SBarry Smith   PetscFunctionReturn(0);
1263ef66eb69SBarry Smith }
1264ef66eb69SBarry Smith 
1265dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
1266ef66eb69SBarry Smith {
1267ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1268ef66eb69SBarry Smith 
1269ef66eb69SBarry Smith   PetscFunctionBegin;
12708fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1271ef66eb69SBarry Smith     shell->vshift = 0.0;
1272ef66eb69SBarry Smith     shell->vscale = 1.0;
1273ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1274ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
12759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
12769566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
12779566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
12789566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
12799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
12809566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
12819566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
12829566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
12839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
12849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1285ef66eb69SBarry Smith   }
1286ef66eb69SBarry Smith   PetscFunctionReturn(0);
1287ef66eb69SBarry Smith }
1288ef66eb69SBarry Smith 
12893b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d)
12903b49f96aSBarry Smith {
12913b49f96aSBarry Smith   PetscFunctionBegin;
12923b49f96aSBarry Smith   *missing = PETSC_FALSE;
12933b49f96aSBarry Smith   PetscFunctionReturn(0);
12943b49f96aSBarry Smith }
12953b49f96aSBarry Smith 
12969f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
12979f137db4SBarry Smith {
12989f137db4SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12999f137db4SBarry Smith 
13009f137db4SBarry Smith   PetscFunctionBegin;
1301ef5c7bd2SStefano Zampini   if (X == Y) {
13029566063dSJacob Faibussowitsch     PetscCall(MatScale(Y,1.0 + a));
1303ef5c7bd2SStefano Zampini     PetscFunctionReturn(0);
1304ef5c7bd2SStefano Zampini   }
1305ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13069566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy));
13079f137db4SBarry Smith     shell->axpy_vscale = a;
13089566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&shell->axpy_state));
1309ef5c7bd2SStefano Zampini   } else {
13109566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str));
1311ef5c7bd2SStefano Zampini   }
13129f137db4SBarry Smith   PetscFunctionReturn(0);
13139f137db4SBarry Smith }
13149f137db4SBarry Smith 
1315f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1316f4259b30SLisandro Dalcin                                        NULL,
1317f4259b30SLisandro Dalcin                                        NULL,
1318f4259b30SLisandro Dalcin                                        NULL,
13190c0fd78eSBarry Smith                                 /* 4*/ MatMultAdd_Shell,
1320f4259b30SLisandro Dalcin                                        NULL,
13210c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1322f4259b30SLisandro Dalcin                                        NULL,
1323f4259b30SLisandro Dalcin                                        NULL,
1324f4259b30SLisandro Dalcin                                        NULL,
1325f4259b30SLisandro Dalcin                                 /*10*/ NULL,
1326f4259b30SLisandro Dalcin                                        NULL,
1327f4259b30SLisandro Dalcin                                        NULL,
1328f4259b30SLisandro Dalcin                                        NULL,
1329f4259b30SLisandro Dalcin                                        NULL,
1330f4259b30SLisandro Dalcin                                 /*15*/ NULL,
1331f4259b30SLisandro Dalcin                                        NULL,
1332f4259b30SLisandro Dalcin                                        NULL,
13338fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1334f4259b30SLisandro Dalcin                                        NULL,
1335f4259b30SLisandro Dalcin                                 /*20*/ NULL,
1336ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1337f4259b30SLisandro Dalcin                                        NULL,
1338f4259b30SLisandro Dalcin                                        NULL,
133945960306SStefano Zampini                                 /*24*/ MatZeroRows_Shell,
1340f4259b30SLisandro Dalcin                                        NULL,
1341f4259b30SLisandro Dalcin                                        NULL,
1342f4259b30SLisandro Dalcin                                        NULL,
1343f4259b30SLisandro Dalcin                                        NULL,
1344f4259b30SLisandro Dalcin                                 /*29*/ NULL,
1345f4259b30SLisandro Dalcin                                        NULL,
1346f4259b30SLisandro Dalcin                                        NULL,
1347f4259b30SLisandro Dalcin                                        NULL,
1348f4259b30SLisandro Dalcin                                        NULL,
1349cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
1350f4259b30SLisandro Dalcin                                        NULL,
1351f4259b30SLisandro Dalcin                                        NULL,
1352f4259b30SLisandro Dalcin                                        NULL,
1353f4259b30SLisandro Dalcin                                        NULL,
13549f137db4SBarry Smith                                 /*39*/ MatAXPY_Shell,
1355f4259b30SLisandro Dalcin                                        NULL,
1356f4259b30SLisandro Dalcin                                        NULL,
1357f4259b30SLisandro Dalcin                                        NULL,
1358cb8c8a77SBarry Smith                                        MatCopy_Shell,
1359f4259b30SLisandro Dalcin                                 /*44*/ NULL,
1360ef66eb69SBarry Smith                                        MatScale_Shell,
1361ef66eb69SBarry Smith                                        MatShift_Shell,
13626464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
136345960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1364f4259b30SLisandro Dalcin                                 /*49*/ NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
1368f4259b30SLisandro Dalcin                                        NULL,
1369f4259b30SLisandro Dalcin                                 /*54*/ NULL,
1370f4259b30SLisandro Dalcin                                        NULL,
1371f4259b30SLisandro Dalcin                                        NULL,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                 /*59*/ NULL,
1375b9b97703SBarry Smith                                        MatDestroy_Shell,
1376f4259b30SLisandro Dalcin                                        NULL,
1377251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1378f4259b30SLisandro Dalcin                                        NULL,
1379f4259b30SLisandro Dalcin                                 /*64*/ NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381f4259b30SLisandro Dalcin                                        NULL,
1382f4259b30SLisandro Dalcin                                        NULL,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                 /*69*/ NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1387f4259b30SLisandro Dalcin                                        NULL,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                 /*74*/ NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        NULL,
1394f4259b30SLisandro Dalcin                                 /*79*/ NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        NULL,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        NULL,
1399f4259b30SLisandro Dalcin                                 /*84*/ NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                 /*89*/ NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        NULL,
1409f4259b30SLisandro Dalcin                                 /*94*/ NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        NULL,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
1414f4259b30SLisandro Dalcin                                 /*99*/ NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                /*104*/ NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424f4259b30SLisandro Dalcin                                /*109*/ NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
14283b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1429f4259b30SLisandro Dalcin                                /*114*/ NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                /*119*/ NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                /*124*/ NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                /*129*/ NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                /*134*/ NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451f4259b30SLisandro Dalcin                                        NULL,
1452f4259b30SLisandro Dalcin                                        NULL,
1453f4259b30SLisandro Dalcin                                        NULL,
1454f4259b30SLisandro Dalcin                                /*139*/ NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456d70f29a3SPierre Jolivet                                        NULL,
1457d70f29a3SPierre Jolivet                                        NULL,
1458d70f29a3SPierre Jolivet                                        NULL,
1459d70f29a3SPierre Jolivet                                /*144*/ NULL,
1460d70f29a3SPierre Jolivet                                        NULL,
1461d70f29a3SPierre Jolivet                                        NULL,
1462*99a7f59eSMark Adams                                        NULL,
1463*99a7f59eSMark Adams                                        NULL,
1464f4259b30SLisandro Dalcin                                        NULL
14653964eb88SJed Brown };
1466273d9f13SBarry Smith 
1467789d8953SBarry Smith PetscErrorCode  MatShellSetContext_Shell(Mat mat,void *ctx)
1468789d8953SBarry Smith {
1469789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell*)mat->data;
1470789d8953SBarry Smith 
1471789d8953SBarry Smith   PetscFunctionBegin;
1472789d8953SBarry Smith   shell->ctx = ctx;
1473789d8953SBarry Smith   PetscFunctionReturn(0);
1474789d8953SBarry Smith }
1475789d8953SBarry Smith 
1476db77db73SJeremy L Thompson static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype)
1477db77db73SJeremy L Thompson {
1478db77db73SJeremy L Thompson   PetscFunctionBegin;
14799566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
14809566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype,(char**)&mat->defaultvectype));
1481db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1482db77db73SJeremy L Thompson }
1483db77db73SJeremy L Thompson 
1484789d8953SBarry Smith PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1485789d8953SBarry Smith {
1486789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
1487789d8953SBarry Smith 
1488789d8953SBarry Smith   PetscFunctionBegin;
1489789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1490789d8953SBarry Smith   A->ops->diagonalset   = NULL;
1491789d8953SBarry Smith   A->ops->diagonalscale = NULL;
1492789d8953SBarry Smith   A->ops->scale         = NULL;
1493789d8953SBarry Smith   A->ops->shift         = NULL;
1494789d8953SBarry Smith   A->ops->axpy          = NULL;
1495789d8953SBarry Smith   PetscFunctionReturn(0);
1496789d8953SBarry Smith }
1497789d8953SBarry Smith 
1498789d8953SBarry Smith PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void))
1499789d8953SBarry Smith {
1500feb237baSPierre Jolivet   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1501789d8953SBarry Smith 
1502789d8953SBarry Smith   PetscFunctionBegin;
1503789d8953SBarry Smith   switch (op) {
1504789d8953SBarry Smith   case MATOP_DESTROY:
1505789d8953SBarry Smith     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1506789d8953SBarry Smith     break;
1507789d8953SBarry Smith   case MATOP_VIEW:
1508789d8953SBarry Smith     if (!mat->ops->viewnative) {
1509789d8953SBarry Smith       mat->ops->viewnative = mat->ops->view;
1510789d8953SBarry Smith     }
1511789d8953SBarry Smith     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1512789d8953SBarry Smith     break;
1513789d8953SBarry Smith   case MATOP_COPY:
1514789d8953SBarry Smith     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1515789d8953SBarry Smith     break;
1516789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1517789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1518789d8953SBarry Smith   case MATOP_SHIFT:
1519789d8953SBarry Smith   case MATOP_SCALE:
1520789d8953SBarry Smith   case MATOP_AXPY:
1521789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1522789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
152328b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1524789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1525789d8953SBarry Smith     break;
1526789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1527789d8953SBarry Smith     if (shell->managescalingshifts) {
1528789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1529789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1530789d8953SBarry Smith     } else {
1531789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1532789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
1533789d8953SBarry Smith     }
1534789d8953SBarry Smith     break;
1535789d8953SBarry Smith   case MATOP_MULT:
1536789d8953SBarry Smith     if (shell->managescalingshifts) {
1537789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1538789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1539789d8953SBarry Smith     } else {
1540789d8953SBarry Smith       shell->ops->mult = NULL;
1541789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1542789d8953SBarry Smith     }
1543789d8953SBarry Smith     break;
1544789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1545789d8953SBarry Smith     if (shell->managescalingshifts) {
1546789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1547789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1548789d8953SBarry Smith     } else {
1549789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1550789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1551789d8953SBarry Smith     }
1552789d8953SBarry Smith     break;
1553789d8953SBarry Smith   default:
1554789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1555789d8953SBarry Smith     break;
1556789d8953SBarry Smith   }
1557789d8953SBarry Smith   PetscFunctionReturn(0);
1558789d8953SBarry Smith }
1559789d8953SBarry Smith 
1560789d8953SBarry Smith PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void))
1561789d8953SBarry Smith {
1562789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1563789d8953SBarry Smith 
1564789d8953SBarry Smith   PetscFunctionBegin;
1565789d8953SBarry Smith   switch (op) {
1566789d8953SBarry Smith   case MATOP_DESTROY:
1567789d8953SBarry Smith     *f = (void (*)(void))shell->ops->destroy;
1568789d8953SBarry Smith     break;
1569789d8953SBarry Smith   case MATOP_VIEW:
1570789d8953SBarry Smith     *f = (void (*)(void))mat->ops->view;
1571789d8953SBarry Smith     break;
1572789d8953SBarry Smith   case MATOP_COPY:
1573789d8953SBarry Smith     *f = (void (*)(void))shell->ops->copy;
1574789d8953SBarry Smith     break;
1575789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1576789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1577789d8953SBarry Smith   case MATOP_SHIFT:
1578789d8953SBarry Smith   case MATOP_SCALE:
1579789d8953SBarry Smith   case MATOP_AXPY:
1580789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1581789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1582789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1583789d8953SBarry Smith     break;
1584789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1585789d8953SBarry Smith     if (shell->ops->getdiagonal)
1586789d8953SBarry Smith       *f = (void (*)(void))shell->ops->getdiagonal;
1587789d8953SBarry Smith     else
1588789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1589789d8953SBarry Smith     break;
1590789d8953SBarry Smith   case MATOP_MULT:
1591789d8953SBarry Smith     if (shell->ops->mult)
1592789d8953SBarry Smith       *f = (void (*)(void))shell->ops->mult;
1593789d8953SBarry Smith     else
1594789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1595789d8953SBarry Smith     break;
1596789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1597789d8953SBarry Smith     if (shell->ops->multtranspose)
1598789d8953SBarry Smith       *f = (void (*)(void))shell->ops->multtranspose;
1599789d8953SBarry Smith     else
1600789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1601789d8953SBarry Smith     break;
1602789d8953SBarry Smith   default:
1603789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1604789d8953SBarry Smith   }
1605789d8953SBarry Smith   PetscFunctionReturn(0);
1606789d8953SBarry Smith }
1607789d8953SBarry Smith 
16080bad9183SKris Buschelman /*MC
1609fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16100bad9183SKris Buschelman 
16110bad9183SKris Buschelman   Level: advanced
16120bad9183SKris Buschelman 
1613db781477SPatrick Sanan .seealso: `MatCreateShell()`
16140bad9183SKris Buschelman M*/
16150bad9183SKris Buschelman 
16168cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1617273d9f13SBarry Smith {
1618273d9f13SBarry Smith   Mat_Shell      *b;
1619273d9f13SBarry Smith 
1620273d9f13SBarry Smith   PetscFunctionBegin;
16219566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps)));
1622273d9f13SBarry Smith 
16239566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A,&b));
1624273d9f13SBarry Smith   A->data = (void*)b;
1625273d9f13SBarry Smith 
1626f4259b30SLisandro Dalcin   b->ctx                 = NULL;
1627ef66eb69SBarry Smith   b->vshift              = 0.0;
1628ef66eb69SBarry Smith   b->vscale              = 1.0;
16290c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1630273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1631210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
16322205254eSKarl Rupp 
16339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell));
16349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell));
16359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell));
16369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell));
16379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell));
16389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell));
16399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell));
16409566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATSHELL));
1641273d9f13SBarry Smith   PetscFunctionReturn(0);
1642273d9f13SBarry Smith }
1643e51e0e81SBarry Smith 
16444b828684SBarry Smith /*@C
1645052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
1646ff756334SLois Curfman McInnes    private data storage format.
1647e51e0e81SBarry Smith 
1648d083f849SBarry Smith   Collective
1649c7fcc2eaSBarry Smith 
1650e51e0e81SBarry Smith    Input Parameters:
1651c7fcc2eaSBarry Smith +  comm - MPI communicator
1652c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
1653c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
1654c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
1655c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
1656c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
1657e51e0e81SBarry Smith 
1658ff756334SLois Curfman McInnes    Output Parameter:
165944cd7ae7SLois Curfman McInnes .  A - the matrix
1660e51e0e81SBarry Smith 
1661ff2fd236SBarry Smith    Level: advanced
1662ff2fd236SBarry Smith 
1663f39d1f56SLois Curfman McInnes   Usage:
16645bd1e576SStefano Zampini $    extern PetscErrorCode mult(Mat,Vec,Vec);
1665f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
1666c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1667f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
1668f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
1669f39d1f56SLois Curfman McInnes 
1670ff756334SLois Curfman McInnes    Notes:
1671ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
1672ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
1673ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
1674e51e0e81SBarry Smith 
167595452b02SPatrick Sanan    Fortran Notes:
167695452b02SPatrick Sanan     To use this from Fortran with a ctx you must write an interface definition for this
1677daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
1678daf670e6SBarry Smith     in as the ctx argument.
1679f38a8d56SBarry Smith 
1680f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
1681f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
1682645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
1683645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
1684645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
1685645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
1686645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
1687645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
1688645985a0SLois Curfman McInnes    For example,
1689f39d1f56SLois Curfman McInnes 
1690f39d1f56SLois Curfman McInnes $
1691f39d1f56SLois Curfman McInnes $     Vec x, y
16925bd1e576SStefano Zampini $     extern PetscErrorCode mult(Mat,Vec,Vec);
1693645985a0SLois Curfman McInnes $     Mat A
1694f39d1f56SLois Curfman McInnes $
1695c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1696c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1697f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
1698c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
1699c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
1700c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1701645985a0SLois Curfman McInnes $     MatMult(A,x,y);
170245960306SStefano Zampini $     MatDestroy(&A);
170345960306SStefano Zampini $     VecDestroy(&y);
170445960306SStefano Zampini $     VecDestroy(&x);
1705645985a0SLois Curfman McInnes $
1706e51e0e81SBarry Smith 
170745960306SStefano Zampini    MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these
17089b53d762SBarry Smith    operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
17099b53d762SBarry Smith 
17100c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
17110c0fd78eSBarry Smith 
171295452b02SPatrick Sanan     Developers Notes:
171395452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
17140c0fd78eSBarry Smith 
17150c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17160c0fd78eSBarry Smith 
17170c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
17180c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17190c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
17200c0fd78eSBarry Smith 
17210c0fd78eSBarry Smith           A is the user provided function.
17220c0fd78eSBarry Smith 
1723ad2f5c3fSBarry Smith    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
1724ad2f5c3fSBarry Smith    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
1725ad2f5c3fSBarry Smith    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
1726ad2f5c3fSBarry Smith    each time the MATSHELL matrix has changed.
1727ad2f5c3fSBarry Smith 
17287301b172SPierre Jolivet    Matrix product operations (i.e. MatMat, MatTransposeMat etc) can be specified using MatShellSetMatProductOperation()
1729b77ba244SStefano Zampini 
1730ad2f5c3fSBarry Smith    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
1731ad2f5c3fSBarry Smith    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
1732ad2f5c3fSBarry Smith 
1733db781477SPatrick Sanan .seealso: `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MATSHELL`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1734e51e0e81SBarry Smith @*/
17357087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
1736e51e0e81SBarry Smith {
17373a40ed3dSBarry Smith   PetscFunctionBegin;
17389566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm,A));
17399566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A,m,n,M,N));
17409566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A,MATSHELL));
17419566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A,ctx));
17429566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
1743273d9f13SBarry Smith   PetscFunctionReturn(0);
1744c7fcc2eaSBarry Smith }
1745c7fcc2eaSBarry Smith 
1746c6866cfdSSatish Balay /*@
1747273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
1748c7fcc2eaSBarry Smith 
17493f9fe445SBarry Smith    Logically Collective on Mat
1750c7fcc2eaSBarry Smith 
1751273d9f13SBarry Smith     Input Parameters:
1752273d9f13SBarry Smith +   mat - the shell matrix
1753273d9f13SBarry Smith -   ctx - the context
1754273d9f13SBarry Smith 
1755273d9f13SBarry Smith    Level: advanced
1756273d9f13SBarry Smith 
175795452b02SPatrick Sanan    Fortran Notes:
175895452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
1759daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1760273d9f13SBarry Smith 
1761db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
17620bc0a719SBarry Smith @*/
17637087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
1764273d9f13SBarry Smith {
1765273d9f13SBarry Smith   PetscFunctionBegin;
17660700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1767cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx));
17683a40ed3dSBarry Smith   PetscFunctionReturn(0);
1769e51e0e81SBarry Smith }
1770e51e0e81SBarry Smith 
1771db77db73SJeremy L Thompson /*@C
1772db77db73SJeremy L Thompson  MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs()
1773db77db73SJeremy L Thompson 
1774db77db73SJeremy L Thompson  Logically collective
1775db77db73SJeremy L Thompson 
1776db77db73SJeremy L Thompson     Input Parameters:
1777db77db73SJeremy L Thompson +   mat   - the shell matrix
1778db77db73SJeremy L Thompson -   vtype - type to use for creating vectors
1779db77db73SJeremy L Thompson 
1780db77db73SJeremy L Thompson  Notes:
1781db77db73SJeremy L Thompson 
1782db77db73SJeremy L Thompson  Level: advanced
1783db77db73SJeremy L Thompson 
1784db781477SPatrick Sanan .seealso: `MatCreateVecs()`
1785db77db73SJeremy L Thompson @*/
1786db77db73SJeremy L Thompson PetscErrorCode  MatShellSetVecType(Mat mat,VecType vtype)
1787db77db73SJeremy L Thompson {
1788db77db73SJeremy L Thompson   PetscFunctionBegin;
1789cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype));
1790db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1791db77db73SJeremy L Thompson }
1792db77db73SJeremy L Thompson 
17930c0fd78eSBarry Smith /*@
17940c0fd78eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
17950c0fd78eSBarry Smith           after MatCreateShell()
17960c0fd78eSBarry Smith 
17970c0fd78eSBarry Smith    Logically Collective on Mat
17980c0fd78eSBarry Smith 
17990c0fd78eSBarry Smith     Input Parameter:
18000c0fd78eSBarry Smith .   mat - the shell matrix
18010c0fd78eSBarry Smith 
18020c0fd78eSBarry Smith   Level: advanced
18030c0fd78eSBarry Smith 
1804db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
18050c0fd78eSBarry Smith @*/
18060c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A)
18070c0fd78eSBarry Smith {
18080c0fd78eSBarry Smith   PetscFunctionBegin;
18090c0fd78eSBarry Smith   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1810cac4c232SBarry Smith   PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A));
18110c0fd78eSBarry Smith   PetscFunctionReturn(0);
18120c0fd78eSBarry Smith }
18130c0fd78eSBarry Smith 
1814c16cb8f2SBarry Smith /*@C
1815f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
1816f3b1f45cSBarry Smith 
1817f3b1f45cSBarry Smith    Logically Collective on Mat
1818f3b1f45cSBarry Smith 
1819f3b1f45cSBarry Smith     Input Parameters:
1820f3b1f45cSBarry Smith +   mat - the shell matrix
1821f3b1f45cSBarry Smith .   f - the function
1822f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1823f3b1f45cSBarry Smith -   ctx - an optional context for the function
1824f3b1f45cSBarry Smith 
1825f3b1f45cSBarry Smith    Output Parameter:
1826f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1827f3b1f45cSBarry Smith 
1828f3b1f45cSBarry Smith    Options Database:
1829f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1830f3b1f45cSBarry Smith 
1831f3b1f45cSBarry Smith    Level: advanced
1832f3b1f45cSBarry Smith 
183395452b02SPatrick Sanan    Fortran Notes:
183495452b02SPatrick Sanan     Not supported from Fortran
1835f3b1f45cSBarry Smith 
1836db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1837f3b1f45cSBarry Smith @*/
1838f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1839f3b1f45cSBarry Smith {
1840f3b1f45cSBarry Smith   PetscInt       m,n;
1841f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1842f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
184374e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1844f3b1f45cSBarry Smith 
1845f3b1f45cSBarry Smith   PetscFunctionBegin;
1846f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
18479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v));
18489566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat,&m,&n));
18499566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf));
18509566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf,f,ctx));
18519566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf,base,NULL));
1852f3b1f45cSBarry Smith 
18539566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf));
18549566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat,MATAIJ,&Dmat));
1855f3b1f45cSBarry Smith 
18569566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff));
18579566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN));
18589566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm));
18599566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm));
1860f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1861f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1862f3b1f45cSBarry Smith     if (v) {
18639566063dSJacob Faibussowitsch       PetscCall(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)));
18649566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view"));
18659566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view"));
18669566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view"));
1867f3b1f45cSBarry Smith     }
1868f3b1f45cSBarry Smith   } else if (v) {
18699566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n"));
1870f3b1f45cSBarry Smith   }
1871f3b1f45cSBarry Smith   if (flg) *flg = flag;
18729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
18739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
18749566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
18759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
1876f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1877f3b1f45cSBarry Smith }
1878f3b1f45cSBarry Smith 
1879f3b1f45cSBarry Smith /*@C
18807301b172SPierre Jolivet     MatShellTestMultTranspose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
1881f3b1f45cSBarry Smith 
1882f3b1f45cSBarry Smith    Logically Collective on Mat
1883f3b1f45cSBarry Smith 
1884f3b1f45cSBarry Smith     Input Parameters:
1885f3b1f45cSBarry Smith +   mat - the shell matrix
1886f3b1f45cSBarry Smith .   f - the function
1887f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1888f3b1f45cSBarry Smith -   ctx - an optional context for the function
1889f3b1f45cSBarry Smith 
1890f3b1f45cSBarry Smith    Output Parameter:
1891f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1892f3b1f45cSBarry Smith 
1893f3b1f45cSBarry Smith    Options Database:
1894f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1895f3b1f45cSBarry Smith 
1896f3b1f45cSBarry Smith    Level: advanced
1897f3b1f45cSBarry Smith 
189895452b02SPatrick Sanan    Fortran Notes:
189995452b02SPatrick Sanan     Not supported from Fortran
1900f3b1f45cSBarry Smith 
1901db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1902f3b1f45cSBarry Smith @*/
1903f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1904f3b1f45cSBarry Smith {
1905f3b1f45cSBarry Smith   Vec            x,y,z;
1906f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
1907f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1908f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
190974e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1910f3b1f45cSBarry Smith 
1911f3b1f45cSBarry Smith   PetscFunctionBegin;
1912f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
19139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v));
19149566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat,&x,&y));
19159566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y,&z));
19169566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat,&m,&n));
19179566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat,&M,&N));
19189566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf));
19199566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf,f,ctx));
19209566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf,base,NULL));
19219566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf));
19229566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf));
19239566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat,MATAIJ,&Dmat));
1924f3b1f45cSBarry Smith 
19259566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff));
19269566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN));
19279566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm));
19289566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm));
1929f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1930f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1931f3b1f45cSBarry Smith     if (v) {
19329566063dSJacob Faibussowitsch       PetscCall(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)));
19339566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
19349566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
19359566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
1936f3b1f45cSBarry Smith     }
1937f3b1f45cSBarry Smith   } else if (v) {
19389566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n"));
1939f3b1f45cSBarry Smith   }
1940f3b1f45cSBarry Smith   if (flg) *flg = flag;
19419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19449566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
19469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
19479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
1948f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1949f3b1f45cSBarry Smith }
1950f3b1f45cSBarry Smith 
1951f3b1f45cSBarry Smith /*@C
19520c0fd78eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
1953e51e0e81SBarry Smith 
19543f9fe445SBarry Smith    Logically Collective on Mat
1955fee21e36SBarry Smith 
1956c7fcc2eaSBarry Smith     Input Parameters:
1957c7fcc2eaSBarry Smith +   mat - the shell matrix
1958c7fcc2eaSBarry Smith .   op - the name of the operation
1959789d8953SBarry Smith -   g - the function that provides the operation.
1960c7fcc2eaSBarry Smith 
196115091d37SBarry Smith    Level: advanced
196215091d37SBarry Smith 
1963fae171e0SBarry Smith     Usage:
1964e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
1965b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
1966b77ba244SStefano Zampini $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
19670b627109SLois Curfman McInnes 
1968a62d957aSLois Curfman McInnes     Notes:
1969e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
19701c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
1971a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
19721c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
1973a62d957aSLois Curfman McInnes 
1974a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
1975deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
1976deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
1977deebb3c3SLois Curfman McInnes     routines, e.g.,
1978a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
1979a62d957aSLois Curfman McInnes 
19804aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
19814aa34b0aSBarry Smith     nonzero on failure.
19824aa34b0aSBarry Smith 
1983a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
1984a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
1985a62d957aSLois Curfman McInnes     set by MatCreateShell().
1986a62d957aSLois Curfman McInnes 
1987b77ba244SStefano Zampini     Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation()
1988b77ba244SStefano Zampini 
198995452b02SPatrick Sanan     Fortran Notes:
199095452b02SPatrick Sanan     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
1991c4762a1bSJed Brown        generate a matrix. See src/mat/tests/ex120f.F
1992501d9185SBarry Smith 
1993db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1994e51e0e81SBarry Smith @*/
1995789d8953SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void))
1996e51e0e81SBarry Smith {
19973a40ed3dSBarry Smith   PetscFunctionBegin;
19980700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1999cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g));
20003a40ed3dSBarry Smith   PetscFunctionReturn(0);
2001e51e0e81SBarry Smith }
2002f0479e8cSBarry Smith 
2003d4bb536fSBarry Smith /*@C
2004d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
2005d4bb536fSBarry Smith 
2006c7fcc2eaSBarry Smith     Not Collective
2007c7fcc2eaSBarry Smith 
2008d4bb536fSBarry Smith     Input Parameters:
2009c7fcc2eaSBarry Smith +   mat - the shell matrix
2010c7fcc2eaSBarry Smith -   op - the name of the operation
2011d4bb536fSBarry Smith 
2012d4bb536fSBarry Smith     Output Parameter:
2013789d8953SBarry Smith .   g - the function that provides the operation.
2014d4bb536fSBarry Smith 
201515091d37SBarry Smith     Level: advanced
201615091d37SBarry Smith 
2017d4bb536fSBarry Smith     Notes:
2018e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
2019d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
2020d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
2021d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
2022d4bb536fSBarry Smith 
2023d4bb536fSBarry Smith     All user-provided functions have the same calling
2024d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
2025d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
2026d4bb536fSBarry Smith     routines, e.g.,
2027d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2028d4bb536fSBarry Smith 
2029d4bb536fSBarry Smith     Within each user-defined routine, the user should call
2030d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
2031d4bb536fSBarry Smith     set by MatCreateShell().
2032d4bb536fSBarry Smith 
2033db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2034d4bb536fSBarry Smith @*/
2035789d8953SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void))
2036d4bb536fSBarry Smith {
20373a40ed3dSBarry Smith   PetscFunctionBegin;
20380700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2039cac4c232SBarry Smith   PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g));
20403a40ed3dSBarry Smith   PetscFunctionReturn(0);
2041d4bb536fSBarry Smith }
2042b77ba244SStefano Zampini 
2043b77ba244SStefano Zampini /*@
2044b77ba244SStefano Zampini     MatIsShell - Inquires if a matrix is derived from MATSHELL
2045b77ba244SStefano Zampini 
2046b77ba244SStefano Zampini     Input Parameter:
2047b77ba244SStefano Zampini .   mat - the matrix
2048b77ba244SStefano Zampini 
2049b77ba244SStefano Zampini     Output Parameter:
2050b77ba244SStefano Zampini .   flg - the boolean value
2051b77ba244SStefano Zampini 
2052b77ba244SStefano Zampini     Level: developer
2053b77ba244SStefano Zampini 
2054b77ba244SStefano Zampini     Notes: in the future, we should allow the object type name to be changed still using the MatShell data structure for other matrices (i.e. MATTRANSPOSEMAT, MATSCHURCOMPLEMENT etc)
2055b77ba244SStefano Zampini 
2056db781477SPatrick Sanan .seealso: `MatCreateShell()`
2057b77ba244SStefano Zampini @*/
2058b77ba244SStefano Zampini PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2059b77ba244SStefano Zampini {
2060b77ba244SStefano Zampini   PetscFunctionBegin;
2061b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2062dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(flg,2);
2063b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
2064b77ba244SStefano Zampini   PetscFunctionReturn(0);
2065b77ba244SStefano Zampini }
2066