xref: /petsc/src/mat/impls/shell/shell.c (revision 2e956fe4fc852fabc23b437482e1fb7b77fddb0d)
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;
13945960306SStefano Zampini   if (shell->zcols) {
1409566063dSJacob Faibussowitsch     PetscCall(VecISSet(x,shell->zcols,0.0));
14145960306SStefano Zampini   }
14245960306SStefano Zampini   if (shell->zrows) {
1439566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE));
1449566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE));
14545960306SStefano Zampini   }
14645960306SStefano Zampini   PetscFunctionReturn(0);
14745960306SStefano Zampini }
14845960306SStefano Zampini 
1498fe8eb27SJed Brown /*
1500c0fd78eSBarry Smith       xx = diag(left)*x
1518fe8eb27SJed Brown */
1528fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
1538fe8eb27SJed Brown {
1548fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1558fe8eb27SJed Brown 
1568fe8eb27SJed Brown   PetscFunctionBegin;
1570298fd71SBarry Smith   *xx = NULL;
1588fe8eb27SJed Brown   if (!shell->left) {
1598fe8eb27SJed Brown     *xx = x;
1608fe8eb27SJed Brown   } else {
1619566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left,&shell->left_work));
1629566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->left_work,x,shell->left));
1638fe8eb27SJed Brown     *xx  = shell->left_work;
1648fe8eb27SJed Brown   }
1658fe8eb27SJed Brown   PetscFunctionReturn(0);
1668fe8eb27SJed Brown }
1678fe8eb27SJed Brown 
1680c0fd78eSBarry Smith /*
1690c0fd78eSBarry Smith      xx = diag(right)*x
1700c0fd78eSBarry Smith */
1718fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1728fe8eb27SJed Brown {
1738fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1748fe8eb27SJed Brown 
1758fe8eb27SJed Brown   PetscFunctionBegin;
1760298fd71SBarry Smith   *xx = NULL;
1778fe8eb27SJed Brown   if (!shell->right) {
1788fe8eb27SJed Brown     *xx = x;
1798fe8eb27SJed Brown   } else {
1809566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right,&shell->right_work));
1819566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work,x,shell->right));
1828fe8eb27SJed Brown     *xx  = shell->right_work;
1838fe8eb27SJed Brown   }
1848fe8eb27SJed Brown   PetscFunctionReturn(0);
1858fe8eb27SJed Brown }
1868fe8eb27SJed Brown 
1870c0fd78eSBarry Smith /*
1880c0fd78eSBarry Smith     x = diag(left)*x
1890c0fd78eSBarry Smith */
1908fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1918fe8eb27SJed Brown {
1928fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1938fe8eb27SJed Brown 
1948fe8eb27SJed Brown   PetscFunctionBegin;
1959566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x,x,shell->left));
1968fe8eb27SJed Brown   PetscFunctionReturn(0);
1978fe8eb27SJed Brown }
1988fe8eb27SJed Brown 
1990c0fd78eSBarry Smith /*
2000c0fd78eSBarry Smith     x = diag(right)*x
2010c0fd78eSBarry Smith */
2028fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
2038fe8eb27SJed Brown {
2048fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2058fe8eb27SJed Brown 
2068fe8eb27SJed Brown   PetscFunctionBegin;
2079566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(x,x,shell->right));
2088fe8eb27SJed Brown   PetscFunctionReturn(0);
2098fe8eb27SJed Brown }
2108fe8eb27SJed Brown 
2110c0fd78eSBarry Smith /*
2120c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2130c0fd78eSBarry Smith 
2140c0fd78eSBarry Smith          On input Y already contains A*x
2150c0fd78eSBarry Smith */
2168fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
2178fe8eb27SJed Brown {
2188fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2198fe8eb27SJed Brown 
2208fe8eb27SJed Brown   PetscFunctionBegin;
2218fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
2228fe8eb27SJed Brown     PetscInt          i,m;
2238fe8eb27SJed Brown     const PetscScalar *x,*d;
2248fe8eb27SJed Brown     PetscScalar       *y;
2259566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X,&m));
2269566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift,&d));
2279566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X,&x));
2289566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y,&y));
2298fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
2309566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift,&d));
2319566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X,&x));
2329566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y,&y));
2330c0fd78eSBarry Smith   } else {
2349566063dSJacob Faibussowitsch     PetscCall(VecScale(Y,shell->vscale));
2358fe8eb27SJed Brown   }
2369566063dSJacob Faibussowitsch   if (shell->vshift != 0.0) PetscCall(VecAXPY(Y,shell->vshift,X)); /* if test is for non-square matrices */
2378fe8eb27SJed Brown   PetscFunctionReturn(0);
2388fe8eb27SJed Brown }
239e51e0e81SBarry Smith 
240789d8953SBarry Smith PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx)
241789d8953SBarry Smith {
242789d8953SBarry Smith   PetscFunctionBegin;
243789d8953SBarry Smith   *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
244789d8953SBarry Smith   PetscFunctionReturn(0);
245789d8953SBarry Smith }
246789d8953SBarry Smith 
2479d225801SJed Brown /*@
248a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
249b4fd4287SBarry Smith 
250c7fcc2eaSBarry Smith     Not Collective
251c7fcc2eaSBarry Smith 
252b4fd4287SBarry Smith     Input Parameter:
253b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
254b4fd4287SBarry Smith 
255b4fd4287SBarry Smith     Output Parameter:
256b4fd4287SBarry Smith .   ctx - the user provided context
257b4fd4287SBarry Smith 
25815091d37SBarry Smith     Level: advanced
25915091d37SBarry Smith 
26095452b02SPatrick Sanan    Fortran Notes:
26195452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
262daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
263a62d957aSLois Curfman McInnes 
264db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2650bc0a719SBarry Smith @*/
2668fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
267b4fd4287SBarry Smith {
2683a40ed3dSBarry Smith   PetscFunctionBegin;
2690700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2704482741eSBarry Smith   PetscValidPointer(ctx,2);
271cac4c232SBarry Smith   PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx));
2723a40ed3dSBarry Smith   PetscFunctionReturn(0);
273b4fd4287SBarry Smith }
274b4fd4287SBarry Smith 
27545960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)
27645960306SStefano Zampini {
27745960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
27845960306SStefano Zampini   Vec            x = NULL,b = NULL;
27945960306SStefano Zampini   IS             is1, is2;
28045960306SStefano Zampini   const PetscInt *ridxs;
28145960306SStefano Zampini   PetscInt       *idxs,*gidxs;
28245960306SStefano Zampini   PetscInt       cum,rst,cst,i;
28345960306SStefano Zampini 
28445960306SStefano Zampini   PetscFunctionBegin;
28545960306SStefano Zampini   if (!shell->zvals) {
2869566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,NULL,&shell->zvals));
28745960306SStefano Zampini   }
28845960306SStefano Zampini   if (!shell->zvals_w) {
2899566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shell->zvals,&shell->zvals_w));
29045960306SStefano Zampini   }
2919566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat,&rst,NULL));
2929566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat,&cst,NULL));
29345960306SStefano Zampini 
29445960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&idxs));
29645960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
2979566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1));
2989566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2999566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals,is1,diag));
30045960306SStefano Zampini   if (shell->zrows) {
3019566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows,is1,&is2));
3029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
3039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
30445960306SStefano Zampini     shell->zrows = is2;
30545960306SStefano Zampini   } else shell->zrows = is1;
30645960306SStefano Zampini 
30745960306SStefano Zampini   /* Create scatters for diagonal values communications */
3089566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
3099566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
31045960306SStefano Zampini 
31145960306SStefano Zampini   /* row scatter: from/to left vector */
3129566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat,&x,&b));
3139566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r));
31445960306SStefano Zampini 
31545960306SStefano Zampini   /* col scatter: from right vector to left vector */
3169566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows,&ridxs));
3179566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows,&nr));
3189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&gidxs));
31945960306SStefano Zampini   for (i = 0, cum  = 0; i < nr; i++) {
32045960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
32145960306SStefano Zampini     gidxs[cum] = ridxs[i];
32245960306SStefano Zampini     cum++;
32345960306SStefano Zampini   }
3249566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1));
3259566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c));
3269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
3279566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
3289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
32945960306SStefano Zampini 
33045960306SStefano Zampini   /* Expand/create index set of zeroed columns */
33145960306SStefano Zampini   if (rc) {
3329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc,&idxs));
33345960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3349566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1));
3359566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
33645960306SStefano Zampini     if (shell->zcols) {
3379566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols,is1,&is2));
3389566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3399566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
34045960306SStefano Zampini       shell->zcols = is2;
34145960306SStefano Zampini     } else shell->zcols = is1;
34245960306SStefano Zampini   }
34345960306SStefano Zampini   PetscFunctionReturn(0);
34445960306SStefano Zampini }
34545960306SStefano Zampini 
34645960306SStefano Zampini static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
34745960306SStefano Zampini {
348ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
34945960306SStefano Zampini   PetscInt       nr, *lrows;
35045960306SStefano Zampini 
35145960306SStefano Zampini   PetscFunctionBegin;
35245960306SStefano Zampini   if (x && b) {
35345960306SStefano Zampini     Vec          xt;
35445960306SStefano Zampini     PetscScalar *vals;
35545960306SStefano Zampini     PetscInt    *gcols,i,st,nl,nc;
35645960306SStefano Zampini 
3579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n,&gcols));
35845960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
35945960306SStefano Zampini 
3609566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&xt,NULL));
3619566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,xt));
3629566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc,&vals));
3639566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */
3649566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3659566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3669566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3679566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt,-1.0,x));                           /* xt = [0, x2] */
36845960306SStefano Zampini 
3699566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt,&st,NULL));
3709566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt,&nl));
3719566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt,&vals));
37245960306SStefano Zampini     for (i = 0; i < nl; i++) {
37345960306SStefano Zampini       PetscInt g = i + st;
37445960306SStefano Zampini       if (g > mat->rmap->N) continue;
37545960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3769566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b,g,diag*vals[i],INSERT_VALUES));
37745960306SStefano Zampini     }
3789566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt,&vals));
3799566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3809566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b));                            /* b  = [b1, x2 * diag] */
3819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3829566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
38345960306SStefano Zampini   }
3849566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL));
3859566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE));
386ef5c7bd2SStefano Zampini   if (shell->axpy) {
3879566063dSJacob Faibussowitsch     PetscCall(MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL));
388ef5c7bd2SStefano Zampini   }
3899566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
39045960306SStefano Zampini   PetscFunctionReturn(0);
39145960306SStefano Zampini }
39245960306SStefano Zampini 
39345960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)
39445960306SStefano Zampini {
395ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
39645960306SStefano Zampini   PetscInt       *lrows, *lcols;
39745960306SStefano Zampini   PetscInt       nr, nc;
39845960306SStefano Zampini   PetscBool      congruent;
39945960306SStefano Zampini 
40045960306SStefano Zampini   PetscFunctionBegin;
40145960306SStefano Zampini   if (x && b) {
40245960306SStefano Zampini     Vec          xt, bt;
40345960306SStefano Zampini     PetscScalar *vals;
40445960306SStefano Zampini     PetscInt    *grows,*gcols,i,st,nl;
40545960306SStefano Zampini 
4069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n,&grows,n,&gcols));
40745960306SStefano Zampini     for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
40845960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
4099566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n,&vals));
41045960306SStefano Zampini 
4119566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat,&xt,&bt));
4129566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,xt));
4139566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */
4149566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
4159566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
4169566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt,-1.0,x));                           /* xt = [0, -x2] */
4179566063dSJacob Faibussowitsch     PetscCall(MatMult(mat,xt,bt));                           /* bt = [-A12*x2,-A22*x2] */
4189566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* bt = [-A12*x2,0] */
4199566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4209566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4219566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b,1.0,bt));                            /* b  = [b1 - A12*x2, b2] */
4229566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
4239566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4249566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4259566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
42645960306SStefano Zampini 
4279566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt,&st,NULL));
4289566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt,&nl));
4299566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt,&vals));
43045960306SStefano Zampini     for (i = 0; i < nl; i++) {
43145960306SStefano Zampini       PetscInt g = i + st;
43245960306SStefano Zampini       if (g > mat->rmap->N) continue;
43345960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4349566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b,g,-diag*vals[i],INSERT_VALUES));
43545960306SStefano Zampini     }
4369566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt,&vals));
4379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4389566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b));                            /* b  = [b1 - A12*x2, x2 * diag] */
4399566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4409566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4419566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows,gcols));
44245960306SStefano Zampini   }
4439566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL));
4449566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat,&congruent));
44545960306SStefano Zampini   if (congruent) {
44645960306SStefano Zampini     nc    = nr;
44745960306SStefano Zampini     lcols = lrows;
44845960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
44945960306SStefano Zampini     PetscInt i,nt,*t;
45045960306SStefano Zampini 
4519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n,&t));
45245960306SStefano Zampini     for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4539566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL));
4549566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
45545960306SStefano Zampini   }
4569566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE));
45745960306SStefano Zampini   if (!congruent) {
4589566063dSJacob Faibussowitsch     PetscCall(PetscFree(lcols));
45945960306SStefano Zampini   }
4609566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
461ef5c7bd2SStefano Zampini   if (shell->axpy) {
4629566063dSJacob Faibussowitsch     PetscCall(MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL));
463ef5c7bd2SStefano Zampini   }
46445960306SStefano Zampini   PetscFunctionReturn(0);
46545960306SStefano Zampini }
46645960306SStefano Zampini 
467dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
468e51e0e81SBarry Smith {
469bf0cc555SLisandro Dalcin   Mat_Shell               *shell = (Mat_Shell*)mat->data;
470b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
471ed3cc1f0SBarry Smith 
4723a40ed3dSBarry Smith   PetscFunctionBegin;
47328f357e3SAlex Fikl   if (shell->ops->destroy) {
4749566063dSJacob Faibussowitsch     PetscCall((*shell->ops->destroy)(mat));
475bf0cc555SLisandro Dalcin   }
4769566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops,sizeof(struct _MatShellOps)));
4779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4869566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4889566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4899566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4909566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4929566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
493b77ba244SStefano Zampini 
494b77ba244SStefano Zampini   matmat = shell->matmat;
495b77ba244SStefano Zampini   while (matmat) {
496b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
497b77ba244SStefano Zampini 
4989566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL));
4999566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
5009566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
5019566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
502b77ba244SStefano Zampini     matmat = next;
503b77ba244SStefano Zampini   }
5049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL));
5059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL));
5069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL));
5079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL));
5089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL));
5099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL));
5109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL));
5119566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
512b77ba244SStefano Zampini   PetscFunctionReturn(0);
513b77ba244SStefano Zampini }
514b77ba244SStefano Zampini 
515b77ba244SStefano Zampini typedef struct {
516b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat,Mat,Mat,void*);
517b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void*);
518b77ba244SStefano Zampini   void           *userdata;
519b77ba244SStefano Zampini   Mat            B;
520b77ba244SStefano Zampini   Mat            Bt;
521b77ba244SStefano Zampini   Mat            axpy;
522b77ba244SStefano Zampini } MatMatDataShell;
523b77ba244SStefano Zampini 
524b77ba244SStefano Zampini static PetscErrorCode DestroyMatMatDataShell(void *data)
525b77ba244SStefano Zampini {
526b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
527b77ba244SStefano Zampini 
528b77ba244SStefano Zampini   PetscFunctionBegin;
529b77ba244SStefano Zampini   if (mmdata->destroy) {
5309566063dSJacob Faibussowitsch     PetscCall((*mmdata->destroy)(mmdata->userdata));
531b77ba244SStefano Zampini   }
5329566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5359566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
536b77ba244SStefano Zampini   PetscFunctionReturn(0);
537b77ba244SStefano Zampini }
538b77ba244SStefano Zampini 
539b77ba244SStefano Zampini static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
540b77ba244SStefano Zampini {
541b77ba244SStefano Zampini   Mat_Product     *product;
542b77ba244SStefano Zampini   Mat             A, B;
543b77ba244SStefano Zampini   MatMatDataShell *mdata;
544b77ba244SStefano Zampini   PetscScalar     zero = 0.0;
545b77ba244SStefano Zampini 
546b77ba244SStefano Zampini   PetscFunctionBegin;
547b77ba244SStefano Zampini   MatCheckProduct(D,1);
548b77ba244SStefano Zampini   product = D->product;
54928b400f6SJacob Faibussowitsch   PetscCheck(product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty");
550b77ba244SStefano Zampini   A = product->A;
551b77ba244SStefano Zampini   B = product->B;
552b77ba244SStefano Zampini   mdata = (MatMatDataShell*)product->data;
553b77ba244SStefano Zampini   if (mdata->numeric) {
554b77ba244SStefano Zampini     Mat_Shell      *shell = (Mat_Shell*)A->data;
555b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
556b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
557b77ba244SStefano Zampini     PetscBool      useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
558b77ba244SStefano Zampini 
559b77ba244SStefano Zampini     if (shell->managescalingshifts) {
56008401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns");
561b77ba244SStefano Zampini       if (shell->right || shell->left) {
562b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
563b77ba244SStefano Zampini         if (!mdata->B) {
5649566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B));
565b77ba244SStefano Zampini         } else {
566b77ba244SStefano Zampini           newB = PETSC_FALSE;
567b77ba244SStefano Zampini         }
5689566063dSJacob Faibussowitsch         PetscCall(MatCopy(B,mdata->B,SAME_NONZERO_PATTERN));
569b77ba244SStefano Zampini       }
570b77ba244SStefano Zampini       switch (product->type) {
571b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
572b77ba244SStefano Zampini         if (shell->right) {
5739566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL));
574b77ba244SStefano Zampini         }
575b77ba244SStefano Zampini         break;
576b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
577b77ba244SStefano Zampini         if (shell->left) {
5789566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B,shell->left,NULL));
579b77ba244SStefano Zampini         }
580b77ba244SStefano Zampini         break;
581b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
582b77ba244SStefano Zampini         if (shell->right) {
5839566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right));
584b77ba244SStefano Zampini         }
585b77ba244SStefano Zampini         break;
586b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
587b77ba244SStefano Zampini         if (shell->right && shell->left) {
588b77ba244SStefano Zampini           PetscBool flg;
589b77ba244SStefano Zampini 
5909566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right,shell->left,&flg));
59128b400f6SJacob 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);
592b77ba244SStefano Zampini         }
593b77ba244SStefano Zampini         if (shell->right) {
5949566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right));
595b77ba244SStefano Zampini         }
596b77ba244SStefano Zampini         break;
597b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
598b77ba244SStefano Zampini         if (shell->right && shell->left) {
599b77ba244SStefano Zampini           PetscBool flg;
600b77ba244SStefano Zampini 
6019566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right,shell->left,&flg));
60228b400f6SJacob 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);
603b77ba244SStefano Zampini         }
604b77ba244SStefano Zampini         if (shell->right) {
6059566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL));
606b77ba244SStefano Zampini         }
607b77ba244SStefano Zampini         break;
60898921bdaSJacob 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);
609b77ba244SStefano Zampini       }
610b77ba244SStefano Zampini     }
611b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
612b77ba244SStefano Zampini     D->product = NULL;
613b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
614b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
615b77ba244SStefano Zampini 
6169566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata));
617b77ba244SStefano Zampini 
618b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
6199566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
620b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
621b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
622b77ba244SStefano Zampini     D->product = product;
623b77ba244SStefano Zampini 
624b77ba244SStefano Zampini     if (shell->managescalingshifts) {
6259566063dSJacob Faibussowitsch       PetscCall(MatScale(D,shell->vscale));
626b77ba244SStefano Zampini       switch (product->type) {
627b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
628b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
629b77ba244SStefano Zampini         if (shell->left) {
6309566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D,shell->left,NULL));
631b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
6329566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A,NULL,&shell->left_work));
633b77ba244SStefano Zampini             if (shell->dshift) {
6349566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift,shell->left_work));
6359566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work,shell->vshift));
6369566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work,shell->left_work,shell->left));
637b77ba244SStefano Zampini             } else {
6389566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work,shell->vshift));
639b77ba244SStefano Zampini             }
640b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
641b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
642b77ba244SStefano Zampini               MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
643b77ba244SStefano Zampini 
6449566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B,reuse,&mdata->Bt));
6459566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt,shell->left_work,NULL));
6469566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D,1.0,mdata->Bt,str));
647b77ba244SStefano Zampini             } else {
648b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
649b77ba244SStefano Zampini 
6509566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B,shell->left_work,NULL));
6519566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D,1.0,mdata->B,str));
652b77ba244SStefano Zampini             }
653b77ba244SStefano Zampini           }
654b77ba244SStefano Zampini         }
655b77ba244SStefano Zampini         break;
656b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
657b77ba244SStefano Zampini         if (shell->right) {
6589566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D,shell->right,NULL));
659b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
660b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
661b77ba244SStefano Zampini 
6629566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A,&shell->right_work,NULL));
663b77ba244SStefano Zampini             if (shell->dshift) {
6649566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift,shell->right_work));
6659566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work,shell->vshift));
6669566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work,shell->right_work,shell->right));
667b77ba244SStefano Zampini             } else {
6689566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work,shell->vshift));
669b77ba244SStefano Zampini             }
6709566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B,shell->right_work,NULL));
6719566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D,1.0,mdata->B,str));
672b77ba244SStefano Zampini           }
673b77ba244SStefano Zampini         }
674b77ba244SStefano Zampini         break;
675b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
676b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
677aed4548fSBarry 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);
678b77ba244SStefano Zampini         break;
67998921bdaSJacob 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);
680b77ba244SStefano Zampini       }
681b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
682b77ba244SStefano Zampini         Mat              X;
683b77ba244SStefano Zampini         PetscObjectState axpy_state;
684b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
685b77ba244SStefano Zampini 
6869566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy,&X));
6879566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
68808401ef6SPierre 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,...)");
689b77ba244SStefano Zampini         if (!mdata->axpy) {
690b77ba244SStefano Zampini           str  = DIFFERENT_NONZERO_PATTERN;
6919566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy,B,NULL,&mdata->axpy));
6929566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy,product->type));
6939566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6949566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
695b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
696b77ba244SStefano Zampini           PetscBool flg;
697b77ba244SStefano Zampini 
6989566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy));
6999566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg));
700b77ba244SStefano Zampini           if (!flg) {
701b77ba244SStefano Zampini             str  = DIFFERENT_NONZERO_PATTERN;
7029566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
7039566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
704b77ba244SStefano Zampini           }
705b77ba244SStefano Zampini         }
7069566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
7079566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D,shell->axpy_vscale,mdata->axpy,str));
708b77ba244SStefano Zampini       }
709b77ba244SStefano Zampini     }
710b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation");
711b77ba244SStefano Zampini   PetscFunctionReturn(0);
712b77ba244SStefano Zampini }
713b77ba244SStefano Zampini 
714b77ba244SStefano Zampini static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
715b77ba244SStefano Zampini {
716b77ba244SStefano Zampini   Mat_Product             *product;
717b77ba244SStefano Zampini   Mat                     A,B;
718b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
719b77ba244SStefano Zampini   Mat_Shell               *shell;
720b77ba244SStefano Zampini   PetscBool               flg;
721b77ba244SStefano Zampini   char                    composedname[256];
722b77ba244SStefano Zampini   MatMatDataShell         *mdata;
723b77ba244SStefano Zampini 
724b77ba244SStefano Zampini   PetscFunctionBegin;
725b77ba244SStefano Zampini   MatCheckProduct(D,1);
726b77ba244SStefano Zampini   product = D->product;
72728b400f6SJacob Faibussowitsch   PetscCheck(!product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty");
728b77ba244SStefano Zampini   A = product->A;
729b77ba244SStefano Zampini   B = product->B;
730b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
731b77ba244SStefano Zampini   matmat = shell->matmat;
7329566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name));
733b77ba244SStefano Zampini   while (matmat) {
7349566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg));
735b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
736b77ba244SStefano Zampini     if (flg) break;
737b77ba244SStefano Zampini     matmat = matmat->next;
738b77ba244SStefano Zampini   }
73928b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]);
740b77ba244SStefano Zampini   switch (product->type) {
741b77ba244SStefano Zampini   case MATPRODUCT_AB:
7429566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N));
743b77ba244SStefano Zampini     break;
744b77ba244SStefano Zampini   case MATPRODUCT_AtB:
7459566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N));
746b77ba244SStefano Zampini     break;
747b77ba244SStefano Zampini   case MATPRODUCT_ABt:
7489566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N));
749b77ba244SStefano Zampini     break;
750b77ba244SStefano Zampini   case MATPRODUCT_RARt:
7519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N));
752b77ba244SStefano Zampini     break;
753b77ba244SStefano Zampini   case MATPRODUCT_PtAP:
7549566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N));
755b77ba244SStefano Zampini     break;
75698921bdaSJacob 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);
757b77ba244SStefano Zampini   }
758b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
759b77ba244SStefano Zampini   if (matmat->resultname) {
7609566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg));
761b77ba244SStefano Zampini     if (!flg) {
7629566063dSJacob Faibussowitsch       PetscCall(MatSetType(D,matmat->resultname));
763b77ba244SStefano Zampini     }
764b77ba244SStefano Zampini   }
765b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
766b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
767b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
768b77ba244SStefano Zampini   /* attach product data */
7699566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
770b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
771b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
772b77ba244SStefano Zampini   if (matmat->symbolic) {
7739566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A,B,D,&mdata->userdata));
774b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7759566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
776b77ba244SStefano Zampini   }
77728b400f6SJacob Faibussowitsch   PetscCheck(D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase");
77828b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase");
779b77ba244SStefano Zampini   D->product->data = mdata;
780b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
781b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
782b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
783b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
784b77ba244SStefano Zampini   PetscFunctionReturn(0);
785b77ba244SStefano Zampini }
786b77ba244SStefano Zampini 
787b77ba244SStefano Zampini static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
788b77ba244SStefano Zampini {
789b77ba244SStefano Zampini   Mat_Product             *product;
790b77ba244SStefano Zampini   Mat                     A,B;
791b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
792b77ba244SStefano Zampini   Mat_Shell               *shell;
793b77ba244SStefano Zampini   PetscBool               flg;
794b77ba244SStefano Zampini   char                    composedname[256];
795b77ba244SStefano Zampini 
796b77ba244SStefano Zampini   PetscFunctionBegin;
797b77ba244SStefano Zampini   MatCheckProduct(D,1);
798b77ba244SStefano Zampini   product = D->product;
799b77ba244SStefano Zampini   A = product->A;
800b77ba244SStefano Zampini   B = product->B;
8019566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A,&flg));
802b77ba244SStefano Zampini   if (!flg) PetscFunctionReturn(0);
803b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
804b77ba244SStefano Zampini   matmat = shell->matmat;
8059566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name));
806b77ba244SStefano Zampini   while (matmat) {
8079566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg));
808b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
809b77ba244SStefano Zampini     if (flg) break;
810b77ba244SStefano Zampini     matmat = matmat->next;
811b77ba244SStefano Zampini   }
812b77ba244SStefano Zampini   if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; }
8139566063dSJacob Faibussowitsch   else PetscCall(PetscInfo(D,"  symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type]));
814b77ba244SStefano Zampini   PetscFunctionReturn(0);
815b77ba244SStefano Zampini }
816b77ba244SStefano Zampini 
817b77ba244SStefano 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)
818b77ba244SStefano Zampini {
819b77ba244SStefano Zampini   PetscBool               flg;
820b77ba244SStefano Zampini   Mat_Shell               *shell;
821b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
822b77ba244SStefano Zampini 
823b77ba244SStefano Zampini   PetscFunctionBegin;
82428b400f6SJacob Faibussowitsch   PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine");
82528b400f6SJacob Faibussowitsch   PetscCheck(composedname,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name");
826b77ba244SStefano Zampini 
827b77ba244SStefano Zampini   /* add product callback */
828b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
829b77ba244SStefano Zampini   matmat = shell->matmat;
830b77ba244SStefano Zampini   if (!matmat) {
8319566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
832b77ba244SStefano Zampini     matmat = shell->matmat;
833b77ba244SStefano Zampini   } else {
834b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
835b77ba244SStefano Zampini     while (entry) {
8369566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname,entry->composedname,&flg));
837b77ba244SStefano Zampini       flg  = (PetscBool)(flg && (entry->ptype == ptype));
838b77ba244SStefano Zampini       matmat = entry;
839*2e956fe4SStefano Zampini       if (flg) goto set;
840b77ba244SStefano Zampini       entry = entry->next;
841b77ba244SStefano Zampini     }
8429566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
843b77ba244SStefano Zampini     matmat = matmat->next;
844b77ba244SStefano Zampini   }
845b77ba244SStefano Zampini 
846843d480fSStefano Zampini set:
847b77ba244SStefano Zampini   matmat->symbolic = symbolic;
848b77ba244SStefano Zampini   matmat->numeric  = numeric;
849b77ba244SStefano Zampini   matmat->destroy  = destroy;
850b77ba244SStefano Zampini   matmat->ptype    = ptype;
8519566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8529566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8539566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname,&matmat->composedname));
8549566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname,&matmat->resultname));
8559566063dSJacob 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"));
8569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X));
857b77ba244SStefano Zampini   PetscFunctionReturn(0);
858b77ba244SStefano Zampini }
859b77ba244SStefano Zampini 
860b77ba244SStefano Zampini /*@C
861b77ba244SStefano Zampini     MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix.
862b77ba244SStefano Zampini 
863b77ba244SStefano Zampini    Logically Collective on Mat
864b77ba244SStefano Zampini 
865b77ba244SStefano Zampini     Input Parameters:
866b77ba244SStefano Zampini +   A - the shell matrix
867b77ba244SStefano Zampini .   ptype - the product type
868b77ba244SStefano Zampini .   symbolic - the function for the symbolic phase (can be NULL)
869b77ba244SStefano Zampini .   numeric - the function for the numerical phase
870b77ba244SStefano Zampini .   destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL)
871b77ba244SStefano Zampini .   Btype - the matrix type for the matrix to be multiplied against
872b77ba244SStefano Zampini -   Ctype - the matrix type for the result (can be NULL)
873b77ba244SStefano Zampini 
874b77ba244SStefano Zampini    Level: advanced
875b77ba244SStefano Zampini 
876b77ba244SStefano Zampini     Usage:
877b77ba244SStefano Zampini $      extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**);
878b77ba244SStefano Zampini $      extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*);
879b77ba244SStefano Zampini $      extern PetscErrorCode userdestroy(void*);
880b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
881b77ba244SStefano Zampini $      MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE);
882b77ba244SStefano Zampini $      [ create B of type SEQAIJ etc..]
883b77ba244SStefano Zampini $      MatProductCreate(A,B,NULL,&C);
884b77ba244SStefano Zampini $      MatProductSetType(C,MATPRODUCT_AB);
885b77ba244SStefano Zampini $      MatProductSetFromOptions(C);
886b77ba244SStefano Zampini $      MatProductSymbolic(C); -> actually runs the user defined symbolic operation
887b77ba244SStefano Zampini $      MatProductNumeric(C); -> actually runs the user defined numeric operation
888b77ba244SStefano Zampini $      [ use C = A*B ]
889b77ba244SStefano Zampini 
890b77ba244SStefano Zampini     Notes:
891b77ba244SStefano Zampini     MATPRODUCT_ABC is not supported yet. Not supported in Fortran.
892b77ba244SStefano 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.
893b77ba244SStefano Zampini     Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
894b77ba244SStefano Zampini     PETSc will take care of calling the user-defined callbacks.
895b77ba244SStefano Zampini     It is allowed to specify the same callbacks for different Btype matrix types.
896b77ba244SStefano Zampini     The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence.
897b77ba244SStefano Zampini 
898db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
899b77ba244SStefano Zampini @*/
900b77ba244SStefano 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)
901b77ba244SStefano Zampini {
902b77ba244SStefano Zampini   PetscFunctionBegin;
903b77ba244SStefano Zampini   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
904b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A,ptype,2);
90508401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]);
90628b400f6SJacob Faibussowitsch   PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4");
907dadcf809SJacob Faibussowitsch   PetscValidCharPointer(Btype,6);
908dadcf809SJacob Faibussowitsch   if (Ctype) PetscValidCharPointer(Ctype,7);
909cac4c232SBarry 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));
910b77ba244SStefano Zampini   PetscFunctionReturn(0);
911b77ba244SStefano Zampini }
912b77ba244SStefano Zampini 
913b77ba244SStefano 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)
914b77ba244SStefano Zampini {
915b77ba244SStefano Zampini   PetscBool      flg;
916b77ba244SStefano Zampini   char           composedname[256];
917b77ba244SStefano Zampini   MatRootName    Bnames = MatRootNameList, Cnames = MatRootNameList;
918b77ba244SStefano Zampini   PetscMPIInt    size;
919b77ba244SStefano Zampini 
920b77ba244SStefano Zampini   PetscFunctionBegin;
921b77ba244SStefano Zampini   PetscValidType(A,1);
922b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9239566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype,Bnames->rname,&flg));
924b77ba244SStefano Zampini     if (flg) break;
925b77ba244SStefano Zampini     Bnames = Bnames->next;
926b77ba244SStefano Zampini   }
927b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9289566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype,Cnames->rname,&flg));
929b77ba244SStefano Zampini     if (flg) break;
930b77ba244SStefano Zampini     Cnames = Cnames->next;
931b77ba244SStefano Zampini   }
9329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size));
933b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
934b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9359566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype));
9369566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype));
9373a40ed3dSBarry Smith   PetscFunctionReturn(0);
938e51e0e81SBarry Smith }
939e51e0e81SBarry Smith 
9407fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
9417fabda3fSAlex Fikl {
94228f357e3SAlex Fikl   Mat_Shell               *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
943cb8c8a77SBarry Smith   PetscBool               matflg;
944b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9457fabda3fSAlex Fikl 
9467fabda3fSAlex Fikl   PetscFunctionBegin;
9479566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B,&matflg));
94828b400f6SJacob Faibussowitsch   PetscCheck(matflg,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name);
9497fabda3fSAlex Fikl 
9509566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps)));
9519566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps)));
9527fabda3fSAlex Fikl 
953cb8c8a77SBarry Smith   if (shellA->ops->copy) {
9549566063dSJacob Faibussowitsch     PetscCall((*shellA->ops->copy)(A,B,str));
955cb8c8a77SBarry Smith   }
9567fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9577fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9580c0fd78eSBarry Smith   if (shellA->dshift) {
9590c0fd78eSBarry Smith     if (!shellB->dshift) {
9609566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->dshift,&shellB->dshift));
9617fabda3fSAlex Fikl     }
9629566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift,shellB->dshift));
9637fabda3fSAlex Fikl   } else {
9649566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9657fabda3fSAlex Fikl   }
9660c0fd78eSBarry Smith   if (shellA->left) {
9670c0fd78eSBarry Smith     if (!shellB->left) {
9689566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->left,&shellB->left));
9697fabda3fSAlex Fikl     }
9709566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left,shellB->left));
9717fabda3fSAlex Fikl   } else {
9729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9737fabda3fSAlex Fikl   }
9740c0fd78eSBarry Smith   if (shellA->right) {
9750c0fd78eSBarry Smith     if (!shellB->right) {
9769566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shellA->right,&shellB->right));
9777fabda3fSAlex Fikl     }
9789566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right,shellB->right));
9797fabda3fSAlex Fikl   } else {
9809566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9817fabda3fSAlex Fikl   }
9829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
983ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
984ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
98540e381c3SBarry Smith   if (shellA->axpy) {
9869566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
98740e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
98840e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
989ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
99040e381c3SBarry Smith   }
99145960306SStefano Zampini   if (shellA->zrows) {
9929566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows,&shellB->zrows));
99345960306SStefano Zampini     if (shellA->zcols) {
9949566063dSJacob Faibussowitsch       PetscCall(ISDuplicate(shellA->zcols,&shellB->zcols));
99545960306SStefano Zampini     }
9969566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals,&shellB->zvals));
9979566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals,shellB->zvals));
9989566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w,&shellB->zvals_w));
9999566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
10009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
100145960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
100245960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
100345960306SStefano Zampini   }
1004b77ba244SStefano Zampini 
1005b77ba244SStefano Zampini   matmatA = shellA->matmat;
1006b77ba244SStefano Zampini   if (matmatA) {
1007b77ba244SStefano Zampini     while (matmatA->next) {
10089566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname));
1009b77ba244SStefano Zampini       matmatA = matmatA->next;
1010b77ba244SStefano Zampini     }
1011b77ba244SStefano Zampini   }
10127fabda3fSAlex Fikl   PetscFunctionReturn(0);
10137fabda3fSAlex Fikl }
10147fabda3fSAlex Fikl 
1015cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
1016cb8c8a77SBarry Smith {
1017cb8c8a77SBarry Smith   void           *ctx;
1018cb8c8a77SBarry Smith 
1019cb8c8a77SBarry Smith   PetscFunctionBegin;
10209566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(mat,&ctx));
10219566063dSJacob Faibussowitsch   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M));
10229566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name));
1023a4b1380bSStefano Zampini   if (op != MAT_DO_NOT_COPY_VALUES) {
10249566063dSJacob Faibussowitsch     PetscCall(MatCopy(mat,*M,SAME_NONZERO_PATTERN));
1025a4b1380bSStefano Zampini   }
1026cb8c8a77SBarry Smith   PetscFunctionReturn(0);
1027cb8c8a77SBarry Smith }
1028cb8c8a77SBarry Smith 
1029dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
1030ef66eb69SBarry Smith {
1031ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
103225578ef6SJed Brown   Vec              xx;
1033e3f487b0SBarry Smith   PetscObjectState instate,outstate;
1034ef66eb69SBarry Smith 
1035ef66eb69SBarry Smith   PetscFunctionBegin;
103628b400f6SJacob Faibussowitsch   PetscCheck(shell->ops->mult,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
10379566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A,x,&xx));
10389566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A,xx,&xx));
10399566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10409566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A,xx,y));
10419566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1042e3f487b0SBarry Smith   if (instate == outstate) {
1043e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10449566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1045e3f487b0SBarry Smith   }
10469566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A,xx,y));
10479566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A,y));
10489566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A,y));
10499f137db4SBarry Smith 
10509f137db4SBarry Smith   if (shell->axpy) {
1051ef5c7bd2SStefano Zampini     Mat              X;
1052ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1053ef5c7bd2SStefano Zampini 
10549566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
10559566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
105608401ef6SPierre 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,...)");
1057b77ba244SStefano Zampini 
10589566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left));
10599566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->axpy_right));
10609566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy,shell->axpy_right,shell->axpy_left));
10619566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_left));
10629f137db4SBarry Smith   }
1063ef66eb69SBarry Smith   PetscFunctionReturn(0);
1064ef66eb69SBarry Smith }
1065ef66eb69SBarry Smith 
10665edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
10675edf6516SJed Brown {
10685edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
10695edf6516SJed Brown 
10705edf6516SJed Brown   PetscFunctionBegin;
10715edf6516SJed Brown   if (y == z) {
10729566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z,&shell->right_add_work));
10739566063dSJacob Faibussowitsch     PetscCall(MatMult(A,x,shell->right_add_work));
10749566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,shell->right_add_work));
10755edf6516SJed Brown   } else {
10769566063dSJacob Faibussowitsch     PetscCall(MatMult(A,x,z));
10779566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,y));
10785edf6516SJed Brown   }
10795edf6516SJed Brown   PetscFunctionReturn(0);
10805edf6516SJed Brown }
10815edf6516SJed Brown 
108218be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
108318be62a5SSatish Balay {
108418be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
108525578ef6SJed Brown   Vec              xx;
1086e3f487b0SBarry Smith   PetscObjectState instate,outstate;
108718be62a5SSatish Balay 
108818be62a5SSatish Balay   PetscFunctionBegin;
108928b400f6SJacob Faibussowitsch   PetscCheck(shell->ops->multtranspose,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
10909566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A,x,&xx));
10919566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleLeft(A,xx,&xx));
10929566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10939566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A,xx,y));
10949566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1095e3f487b0SBarry Smith   if (instate == outstate) {
1096e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10979566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1098e3f487b0SBarry Smith   }
10999566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A,xx,y));
11009566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleRight(A,y));
11019566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A,y));
1102350ec83bSStefano Zampini 
1103350ec83bSStefano Zampini   if (shell->axpy) {
1104ef5c7bd2SStefano Zampini     Mat              X;
1105ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1106ef5c7bd2SStefano Zampini 
11079566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
11089566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
110908401ef6SPierre 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,...)");
11109566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left));
11119566063dSJacob Faibussowitsch     PetscCall(VecCopy(x,shell->axpy_left));
11129566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right));
11139566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_right));
1114350ec83bSStefano Zampini   }
111518be62a5SSatish Balay   PetscFunctionReturn(0);
111618be62a5SSatish Balay }
111718be62a5SSatish Balay 
11185edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
11195edf6516SJed Brown {
11205edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
11215edf6516SJed Brown 
11225edf6516SJed Brown   PetscFunctionBegin;
11235edf6516SJed Brown   if (y == z) {
11249566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z,&shell->left_add_work));
11259566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A,x,shell->left_add_work));
11269566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,shell->left_add_work));
11275edf6516SJed Brown   } else {
11289566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A,x,z));
11299566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z,1.0,y));
11305edf6516SJed Brown   }
11315edf6516SJed Brown   PetscFunctionReturn(0);
11325edf6516SJed Brown }
11335edf6516SJed Brown 
11340c0fd78eSBarry Smith /*
11350c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11360c0fd78eSBarry Smith */
113718be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
113818be62a5SSatish Balay {
113918be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
114018be62a5SSatish Balay 
114118be62a5SSatish Balay   PetscFunctionBegin;
11420c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11439566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A,v));
1144305211d5SBarry 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,...)");
11459566063dSJacob Faibussowitsch   PetscCall(VecScale(v,shell->vscale));
11468fe8eb27SJed Brown   if (shell->dshift) {
11479566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v,1.0,shell->dshift));
114818be62a5SSatish Balay   }
11499566063dSJacob Faibussowitsch   PetscCall(VecShift(v,shell->vshift));
11509566063dSJacob Faibussowitsch   if (shell->left)  PetscCall(VecPointwiseMult(v,v,shell->left));
11519566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v,v,shell->right));
115245960306SStefano Zampini   if (shell->zrows) {
11539566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE));
11549566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE));
115545960306SStefano Zampini   }
115681c02519SBarry Smith   if (shell->axpy) {
1157ef5c7bd2SStefano Zampini     Mat              X;
1158ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1159ef5c7bd2SStefano Zampini 
11609566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy,&X));
11619566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state));
116208401ef6SPierre 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,...)");
11639566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left));
11649566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy,shell->axpy_left));
11659566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v,shell->axpy_vscale,shell->axpy_left));
116681c02519SBarry Smith   }
116718be62a5SSatish Balay   PetscFunctionReturn(0);
116818be62a5SSatish Balay }
116918be62a5SSatish Balay 
1170f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
1171ef66eb69SBarry Smith {
1172ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1173789d8953SBarry Smith   PetscBool      flg;
1174b24ad042SBarry Smith 
1175ef66eb69SBarry Smith   PetscFunctionBegin;
11769566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y,&flg));
117728b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent");
11780c0fd78eSBarry Smith   if (shell->left || shell->right) {
11798fe8eb27SJed Brown     if (!shell->dshift) {
11809566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11819566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift,a));
11820c0fd78eSBarry Smith     } else {
11839566063dSJacob Faibussowitsch       if (shell->left)  PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->left));
11849566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->right));
11859566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift,a));
11860c0fd78eSBarry Smith     }
11879566063dSJacob Faibussowitsch     if (shell->left)  PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->left));
11889566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->right));
11898fe8eb27SJed Brown   } else shell->vshift += a;
119045960306SStefano Zampini   if (shell->zrows) {
11919566063dSJacob Faibussowitsch     PetscCall(VecShift(shell->zvals,a));
119245960306SStefano Zampini   }
1193ef66eb69SBarry Smith   PetscFunctionReturn(0);
1194ef66eb69SBarry Smith }
1195ef66eb69SBarry Smith 
1196b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
11976464bf51SAlex Fikl {
11986464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
11996464bf51SAlex Fikl 
12006464bf51SAlex Fikl   PetscFunctionBegin;
12019566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D,&shell->dshift));
12020c0fd78eSBarry Smith   if (shell->left || shell->right) {
12039566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
12049f137db4SBarry Smith     if (shell->left && shell->right)  {
12059566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left));
12069566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,shell->right_work,shell->right));
12079f137db4SBarry Smith     } else if (shell->left) {
12089566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left));
12099f137db4SBarry Smith     } else {
12109566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work,D,shell->right));
12119f137db4SBarry Smith     }
12129566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift,s,shell->right_work));
12130c0fd78eSBarry Smith   } else {
12149566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift,s,D));
1215b253ae0bS“Marek   }
1216b253ae0bS“Marek   PetscFunctionReturn(0);
1217b253ae0bS“Marek }
1218b253ae0bS“Marek 
1219b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
1220b253ae0bS“Marek {
122145960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
1222b253ae0bS“Marek   Vec            d;
1223789d8953SBarry Smith   PetscBool      flg;
1224b253ae0bS“Marek 
1225b253ae0bS“Marek   PetscFunctionBegin;
12269566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A,&flg));
122728b400f6SJacob Faibussowitsch   PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent");
1228b253ae0bS“Marek   if (ins == INSERT_VALUES) {
122928b400f6SJacob Faibussowitsch     PetscCheck(A->ops->getdiagonal,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
12309566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D,&d));
12319566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A,d));
12329566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,d,-1.));
12339566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,D,1.));
12349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
123545960306SStefano Zampini     if (shell->zrows) {
12369566063dSJacob Faibussowitsch       PetscCall(VecCopy(D,shell->zvals));
123745960306SStefano Zampini     }
1238b253ae0bS“Marek   } else {
12399566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A,D,1.));
124045960306SStefano Zampini     if (shell->zrows) {
12419566063dSJacob Faibussowitsch       PetscCall(VecAXPY(shell->zvals,1.0,D));
124245960306SStefano Zampini     }
12436464bf51SAlex Fikl   }
12446464bf51SAlex Fikl   PetscFunctionReturn(0);
12456464bf51SAlex Fikl }
12466464bf51SAlex Fikl 
1247f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
1248ef66eb69SBarry Smith {
1249ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1250b24ad042SBarry Smith 
1251ef66eb69SBarry Smith   PetscFunctionBegin;
1252f4df32b1SMatthew Knepley   shell->vscale *= a;
12530c0fd78eSBarry Smith   shell->vshift *= a;
12542205254eSKarl Rupp   if (shell->dshift) {
12559566063dSJacob Faibussowitsch     PetscCall(VecScale(shell->dshift,a));
12560c0fd78eSBarry Smith   }
125781c02519SBarry Smith   shell->axpy_vscale *= a;
125845960306SStefano Zampini   if (shell->zrows) {
12599566063dSJacob Faibussowitsch     PetscCall(VecScale(shell->zvals,a));
126045960306SStefano Zampini   }
12618fe8eb27SJed Brown   PetscFunctionReturn(0);
126218be62a5SSatish Balay }
12638fe8eb27SJed Brown 
12648fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
12658fe8eb27SJed Brown {
12668fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12678fe8eb27SJed Brown 
12688fe8eb27SJed Brown   PetscFunctionBegin;
12698fe8eb27SJed Brown   if (left) {
12700c0fd78eSBarry Smith     if (!shell->left) {
12719566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left,&shell->left));
12729566063dSJacob Faibussowitsch       PetscCall(VecCopy(left,shell->left));
12730c0fd78eSBarry Smith     } else {
12749566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left,shell->left,left));
127518be62a5SSatish Balay     }
127645960306SStefano Zampini     if (shell->zrows) {
12779566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,left));
127845960306SStefano Zampini     }
1279ef66eb69SBarry Smith   }
12808fe8eb27SJed Brown   if (right) {
12810c0fd78eSBarry Smith     if (!shell->right) {
12829566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right,&shell->right));
12839566063dSJacob Faibussowitsch       PetscCall(VecCopy(right,shell->right));
12840c0fd78eSBarry Smith     } else {
12859566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right,shell->right,right));
12868fe8eb27SJed Brown     }
128745960306SStefano Zampini     if (shell->zrows) {
128845960306SStefano Zampini       if (!shell->left_work) {
12899566063dSJacob Faibussowitsch         PetscCall(MatCreateVecs(Y,NULL,&shell->left_work));
129045960306SStefano Zampini       }
12919566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w,1.0));
12929566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
12939566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD));
12949566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w));
129545960306SStefano Zampini     }
12968fe8eb27SJed Brown   }
1297ef5c7bd2SStefano Zampini   if (shell->axpy) {
12989566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(shell->axpy,left,right));
1299ef5c7bd2SStefano Zampini   }
1300ef66eb69SBarry Smith   PetscFunctionReturn(0);
1301ef66eb69SBarry Smith }
1302ef66eb69SBarry Smith 
1303dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
1304ef66eb69SBarry Smith {
1305ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
1306ef66eb69SBarry Smith 
1307ef66eb69SBarry Smith   PetscFunctionBegin;
13088fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1309ef66eb69SBarry Smith     shell->vshift = 0.0;
1310ef66eb69SBarry Smith     shell->vscale = 1.0;
1311ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1312ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
13149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
13159566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
13169566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
13179566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
13189566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
13199566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
13209566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
13219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
13229566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1323ef66eb69SBarry Smith   }
1324ef66eb69SBarry Smith   PetscFunctionReturn(0);
1325ef66eb69SBarry Smith }
1326ef66eb69SBarry Smith 
13273b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d)
13283b49f96aSBarry Smith {
13293b49f96aSBarry Smith   PetscFunctionBegin;
13303b49f96aSBarry Smith   *missing = PETSC_FALSE;
13313b49f96aSBarry Smith   PetscFunctionReturn(0);
13323b49f96aSBarry Smith }
13333b49f96aSBarry Smith 
13349f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
13359f137db4SBarry Smith {
13369f137db4SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13379f137db4SBarry Smith 
13389f137db4SBarry Smith   PetscFunctionBegin;
1339ef5c7bd2SStefano Zampini   if (X == Y) {
13409566063dSJacob Faibussowitsch     PetscCall(MatScale(Y,1.0 + a));
1341ef5c7bd2SStefano Zampini     PetscFunctionReturn(0);
1342ef5c7bd2SStefano Zampini   }
1343ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13449566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy));
13459f137db4SBarry Smith     shell->axpy_vscale = a;
13469566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X,&shell->axpy_state));
1347ef5c7bd2SStefano Zampini   } else {
13489566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str));
1349ef5c7bd2SStefano Zampini   }
13509f137db4SBarry Smith   PetscFunctionReturn(0);
13519f137db4SBarry Smith }
13529f137db4SBarry Smith 
1353f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1354f4259b30SLisandro Dalcin                                        NULL,
1355f4259b30SLisandro Dalcin                                        NULL,
1356f4259b30SLisandro Dalcin                                        NULL,
13570c0fd78eSBarry Smith                                 /* 4*/ MatMultAdd_Shell,
1358f4259b30SLisandro Dalcin                                        NULL,
13590c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1360f4259b30SLisandro Dalcin                                        NULL,
1361f4259b30SLisandro Dalcin                                        NULL,
1362f4259b30SLisandro Dalcin                                        NULL,
1363f4259b30SLisandro Dalcin                                 /*10*/ NULL,
1364f4259b30SLisandro Dalcin                                        NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
1368f4259b30SLisandro Dalcin                                 /*15*/ NULL,
1369f4259b30SLisandro Dalcin                                        NULL,
1370f4259b30SLisandro Dalcin                                        NULL,
13718fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                 /*20*/ NULL,
1374ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1375f4259b30SLisandro Dalcin                                        NULL,
1376f4259b30SLisandro Dalcin                                        NULL,
137745960306SStefano Zampini                                 /*24*/ MatZeroRows_Shell,
1378f4259b30SLisandro Dalcin                                        NULL,
1379f4259b30SLisandro Dalcin                                        NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381f4259b30SLisandro Dalcin                                        NULL,
1382f4259b30SLisandro Dalcin                                 /*29*/ NULL,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                        NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386f4259b30SLisandro Dalcin                                        NULL,
1387cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                        NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
13929f137db4SBarry Smith                                 /*39*/ MatAXPY_Shell,
1393f4259b30SLisandro Dalcin                                        NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396cb8c8a77SBarry Smith                                        MatCopy_Shell,
1397f4259b30SLisandro Dalcin                                 /*44*/ NULL,
1398ef66eb69SBarry Smith                                        MatScale_Shell,
1399ef66eb69SBarry Smith                                        MatShift_Shell,
14006464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
140145960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1402f4259b30SLisandro Dalcin                                 /*49*/ NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                 /*54*/ NULL,
1408f4259b30SLisandro Dalcin                                        NULL,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        NULL,
1412f4259b30SLisandro Dalcin                                 /*59*/ NULL,
1413b9b97703SBarry Smith                                        MatDestroy_Shell,
1414f4259b30SLisandro Dalcin                                        NULL,
1415251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                 /*64*/ NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                 /*69*/ NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427f4259b30SLisandro Dalcin                                 /*74*/ NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                 /*79*/ NULL,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                        NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        NULL,
1437f4259b30SLisandro Dalcin                                 /*84*/ NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                 /*89*/ NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                 /*94*/ NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451f4259b30SLisandro Dalcin                                        NULL,
1452f4259b30SLisandro Dalcin                                 /*99*/ NULL,
1453f4259b30SLisandro Dalcin                                        NULL,
1454f4259b30SLisandro Dalcin                                        NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456f4259b30SLisandro Dalcin                                        NULL,
1457f4259b30SLisandro Dalcin                                /*104*/ NULL,
1458f4259b30SLisandro Dalcin                                        NULL,
1459f4259b30SLisandro Dalcin                                        NULL,
1460f4259b30SLisandro Dalcin                                        NULL,
1461f4259b30SLisandro Dalcin                                        NULL,
1462f4259b30SLisandro Dalcin                                /*109*/ NULL,
1463f4259b30SLisandro Dalcin                                        NULL,
1464f4259b30SLisandro Dalcin                                        NULL,
1465f4259b30SLisandro Dalcin                                        NULL,
14663b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1467f4259b30SLisandro Dalcin                                /*114*/ NULL,
1468f4259b30SLisandro Dalcin                                        NULL,
1469f4259b30SLisandro Dalcin                                        NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        NULL,
1472f4259b30SLisandro Dalcin                                /*119*/ NULL,
1473f4259b30SLisandro Dalcin                                        NULL,
1474f4259b30SLisandro Dalcin                                        NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
1476f4259b30SLisandro Dalcin                                        NULL,
1477f4259b30SLisandro Dalcin                                /*124*/ NULL,
1478f4259b30SLisandro Dalcin                                        NULL,
1479f4259b30SLisandro Dalcin                                        NULL,
1480f4259b30SLisandro Dalcin                                        NULL,
1481f4259b30SLisandro Dalcin                                        NULL,
1482f4259b30SLisandro Dalcin                                /*129*/ NULL,
1483f4259b30SLisandro Dalcin                                        NULL,
1484f4259b30SLisandro Dalcin                                        NULL,
1485f4259b30SLisandro Dalcin                                        NULL,
1486f4259b30SLisandro Dalcin                                        NULL,
1487f4259b30SLisandro Dalcin                                /*134*/ NULL,
1488f4259b30SLisandro Dalcin                                        NULL,
1489f4259b30SLisandro Dalcin                                        NULL,
1490f4259b30SLisandro Dalcin                                        NULL,
1491f4259b30SLisandro Dalcin                                        NULL,
1492f4259b30SLisandro Dalcin                                /*139*/ NULL,
1493f4259b30SLisandro Dalcin                                        NULL,
1494d70f29a3SPierre Jolivet                                        NULL,
1495d70f29a3SPierre Jolivet                                        NULL,
1496d70f29a3SPierre Jolivet                                        NULL,
1497d70f29a3SPierre Jolivet                                /*144*/ NULL,
1498d70f29a3SPierre Jolivet                                        NULL,
1499d70f29a3SPierre Jolivet                                        NULL,
1500f4259b30SLisandro Dalcin                                        NULL
15013964eb88SJed Brown };
1502273d9f13SBarry Smith 
1503789d8953SBarry Smith PetscErrorCode  MatShellSetContext_Shell(Mat mat,void *ctx)
1504789d8953SBarry Smith {
1505789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell*)mat->data;
1506789d8953SBarry Smith 
1507789d8953SBarry Smith   PetscFunctionBegin;
1508789d8953SBarry Smith   shell->ctx = ctx;
1509789d8953SBarry Smith   PetscFunctionReturn(0);
1510789d8953SBarry Smith }
1511789d8953SBarry Smith 
1512db77db73SJeremy L Thompson static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype)
1513db77db73SJeremy L Thompson {
1514db77db73SJeremy L Thompson   PetscFunctionBegin;
15159566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
15169566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype,(char**)&mat->defaultvectype));
1517db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1518db77db73SJeremy L Thompson }
1519db77db73SJeremy L Thompson 
1520789d8953SBarry Smith PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1521789d8953SBarry Smith {
1522789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
1523789d8953SBarry Smith 
1524789d8953SBarry Smith   PetscFunctionBegin;
1525789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1526789d8953SBarry Smith   A->ops->diagonalset   = NULL;
1527789d8953SBarry Smith   A->ops->diagonalscale = NULL;
1528789d8953SBarry Smith   A->ops->scale         = NULL;
1529789d8953SBarry Smith   A->ops->shift         = NULL;
1530789d8953SBarry Smith   A->ops->axpy          = NULL;
1531789d8953SBarry Smith   PetscFunctionReturn(0);
1532789d8953SBarry Smith }
1533789d8953SBarry Smith 
1534789d8953SBarry Smith PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void))
1535789d8953SBarry Smith {
1536feb237baSPierre Jolivet   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1537789d8953SBarry Smith 
1538789d8953SBarry Smith   PetscFunctionBegin;
1539789d8953SBarry Smith   switch (op) {
1540789d8953SBarry Smith   case MATOP_DESTROY:
1541789d8953SBarry Smith     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1542789d8953SBarry Smith     break;
1543789d8953SBarry Smith   case MATOP_VIEW:
1544789d8953SBarry Smith     if (!mat->ops->viewnative) {
1545789d8953SBarry Smith       mat->ops->viewnative = mat->ops->view;
1546789d8953SBarry Smith     }
1547789d8953SBarry Smith     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1548789d8953SBarry Smith     break;
1549789d8953SBarry Smith   case MATOP_COPY:
1550789d8953SBarry Smith     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1551789d8953SBarry Smith     break;
1552789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1553789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1554789d8953SBarry Smith   case MATOP_SHIFT:
1555789d8953SBarry Smith   case MATOP_SCALE:
1556789d8953SBarry Smith   case MATOP_AXPY:
1557789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1558789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
155928b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1560789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1561789d8953SBarry Smith     break;
1562789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1563789d8953SBarry Smith     if (shell->managescalingshifts) {
1564789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1565789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1566789d8953SBarry Smith     } else {
1567789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1568789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
1569789d8953SBarry Smith     }
1570789d8953SBarry Smith     break;
1571789d8953SBarry Smith   case MATOP_MULT:
1572789d8953SBarry Smith     if (shell->managescalingshifts) {
1573789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1574789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1575789d8953SBarry Smith     } else {
1576789d8953SBarry Smith       shell->ops->mult = NULL;
1577789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1578789d8953SBarry Smith     }
1579789d8953SBarry Smith     break;
1580789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1581789d8953SBarry Smith     if (shell->managescalingshifts) {
1582789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1583789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1584789d8953SBarry Smith     } else {
1585789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1586789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1587789d8953SBarry Smith     }
1588789d8953SBarry Smith     break;
1589789d8953SBarry Smith   default:
1590789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1591789d8953SBarry Smith     break;
1592789d8953SBarry Smith   }
1593789d8953SBarry Smith   PetscFunctionReturn(0);
1594789d8953SBarry Smith }
1595789d8953SBarry Smith 
1596789d8953SBarry Smith PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void))
1597789d8953SBarry Smith {
1598789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1599789d8953SBarry Smith 
1600789d8953SBarry Smith   PetscFunctionBegin;
1601789d8953SBarry Smith   switch (op) {
1602789d8953SBarry Smith   case MATOP_DESTROY:
1603789d8953SBarry Smith     *f = (void (*)(void))shell->ops->destroy;
1604789d8953SBarry Smith     break;
1605789d8953SBarry Smith   case MATOP_VIEW:
1606789d8953SBarry Smith     *f = (void (*)(void))mat->ops->view;
1607789d8953SBarry Smith     break;
1608789d8953SBarry Smith   case MATOP_COPY:
1609789d8953SBarry Smith     *f = (void (*)(void))shell->ops->copy;
1610789d8953SBarry Smith     break;
1611789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1612789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1613789d8953SBarry Smith   case MATOP_SHIFT:
1614789d8953SBarry Smith   case MATOP_SCALE:
1615789d8953SBarry Smith   case MATOP_AXPY:
1616789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1617789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1618789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1619789d8953SBarry Smith     break;
1620789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1621789d8953SBarry Smith     if (shell->ops->getdiagonal)
1622789d8953SBarry Smith       *f = (void (*)(void))shell->ops->getdiagonal;
1623789d8953SBarry Smith     else
1624789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1625789d8953SBarry Smith     break;
1626789d8953SBarry Smith   case MATOP_MULT:
1627789d8953SBarry Smith     if (shell->ops->mult)
1628789d8953SBarry Smith       *f = (void (*)(void))shell->ops->mult;
1629789d8953SBarry Smith     else
1630789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1631789d8953SBarry Smith     break;
1632789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1633789d8953SBarry Smith     if (shell->ops->multtranspose)
1634789d8953SBarry Smith       *f = (void (*)(void))shell->ops->multtranspose;
1635789d8953SBarry Smith     else
1636789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1637789d8953SBarry Smith     break;
1638789d8953SBarry Smith   default:
1639789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1640789d8953SBarry Smith   }
1641789d8953SBarry Smith   PetscFunctionReturn(0);
1642789d8953SBarry Smith }
1643789d8953SBarry Smith 
16440bad9183SKris Buschelman /*MC
1645fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16460bad9183SKris Buschelman 
16470bad9183SKris Buschelman   Level: advanced
16480bad9183SKris Buschelman 
1649db781477SPatrick Sanan .seealso: `MatCreateShell()`
16500bad9183SKris Buschelman M*/
16510bad9183SKris Buschelman 
16528cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1653273d9f13SBarry Smith {
1654273d9f13SBarry Smith   Mat_Shell      *b;
1655273d9f13SBarry Smith 
1656273d9f13SBarry Smith   PetscFunctionBegin;
16579566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps)));
1658273d9f13SBarry Smith 
16599566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A,&b));
1660273d9f13SBarry Smith   A->data = (void*)b;
1661273d9f13SBarry Smith 
1662f4259b30SLisandro Dalcin   b->ctx                 = NULL;
1663ef66eb69SBarry Smith   b->vshift              = 0.0;
1664ef66eb69SBarry Smith   b->vscale              = 1.0;
16650c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1666273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1667210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
16682205254eSKarl Rupp 
16699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell));
16709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell));
16719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell));
16729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell));
16739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell));
16749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell));
16759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell));
16769566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATSHELL));
1677273d9f13SBarry Smith   PetscFunctionReturn(0);
1678273d9f13SBarry Smith }
1679e51e0e81SBarry Smith 
16804b828684SBarry Smith /*@C
1681052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
1682ff756334SLois Curfman McInnes    private data storage format.
1683e51e0e81SBarry Smith 
1684d083f849SBarry Smith   Collective
1685c7fcc2eaSBarry Smith 
1686e51e0e81SBarry Smith    Input Parameters:
1687c7fcc2eaSBarry Smith +  comm - MPI communicator
1688c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
1689c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
1690c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
1691c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
1692c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
1693e51e0e81SBarry Smith 
1694ff756334SLois Curfman McInnes    Output Parameter:
169544cd7ae7SLois Curfman McInnes .  A - the matrix
1696e51e0e81SBarry Smith 
1697ff2fd236SBarry Smith    Level: advanced
1698ff2fd236SBarry Smith 
1699f39d1f56SLois Curfman McInnes   Usage:
17005bd1e576SStefano Zampini $    extern PetscErrorCode mult(Mat,Vec,Vec);
1701f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
1702c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1703f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
1704f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
1705f39d1f56SLois Curfman McInnes 
1706ff756334SLois Curfman McInnes    Notes:
1707ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
1708ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
1709ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
1710e51e0e81SBarry Smith 
171195452b02SPatrick Sanan    Fortran Notes:
171295452b02SPatrick Sanan     To use this from Fortran with a ctx you must write an interface definition for this
1713daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
1714daf670e6SBarry Smith     in as the ctx argument.
1715f38a8d56SBarry Smith 
1716f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
1717f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
1718645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
1719645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
1720645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
1721645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
1722645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
1723645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
1724645985a0SLois Curfman McInnes    For example,
1725f39d1f56SLois Curfman McInnes 
1726f39d1f56SLois Curfman McInnes $
1727f39d1f56SLois Curfman McInnes $     Vec x, y
17285bd1e576SStefano Zampini $     extern PetscErrorCode mult(Mat,Vec,Vec);
1729645985a0SLois Curfman McInnes $     Mat A
1730f39d1f56SLois Curfman McInnes $
1731c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1732c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1733f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
1734c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
1735c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
1736c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1737645985a0SLois Curfman McInnes $     MatMult(A,x,y);
173845960306SStefano Zampini $     MatDestroy(&A);
173945960306SStefano Zampini $     VecDestroy(&y);
174045960306SStefano Zampini $     VecDestroy(&x);
1741645985a0SLois Curfman McInnes $
1742e51e0e81SBarry Smith 
174345960306SStefano Zampini    MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these
17449b53d762SBarry Smith    operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
17459b53d762SBarry Smith 
17460c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
17470c0fd78eSBarry Smith 
174895452b02SPatrick Sanan     Developers Notes:
174995452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
17500c0fd78eSBarry Smith 
17510c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17520c0fd78eSBarry Smith 
17530c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
17540c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17550c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
17560c0fd78eSBarry Smith 
17570c0fd78eSBarry Smith           A is the user provided function.
17580c0fd78eSBarry Smith 
1759ad2f5c3fSBarry Smith    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
1760ad2f5c3fSBarry Smith    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
1761ad2f5c3fSBarry Smith    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
1762ad2f5c3fSBarry Smith    each time the MATSHELL matrix has changed.
1763ad2f5c3fSBarry Smith 
17647301b172SPierre Jolivet    Matrix product operations (i.e. MatMat, MatTransposeMat etc) can be specified using MatShellSetMatProductOperation()
1765b77ba244SStefano Zampini 
1766ad2f5c3fSBarry Smith    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
1767ad2f5c3fSBarry Smith    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
1768ad2f5c3fSBarry Smith 
1769db781477SPatrick Sanan .seealso: `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MATSHELL`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1770e51e0e81SBarry Smith @*/
17717087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
1772e51e0e81SBarry Smith {
17733a40ed3dSBarry Smith   PetscFunctionBegin;
17749566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm,A));
17759566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A,m,n,M,N));
17769566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A,MATSHELL));
17779566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A,ctx));
17789566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
1779273d9f13SBarry Smith   PetscFunctionReturn(0);
1780c7fcc2eaSBarry Smith }
1781c7fcc2eaSBarry Smith 
1782c6866cfdSSatish Balay /*@
1783273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
1784c7fcc2eaSBarry Smith 
17853f9fe445SBarry Smith    Logically Collective on Mat
1786c7fcc2eaSBarry Smith 
1787273d9f13SBarry Smith     Input Parameters:
1788273d9f13SBarry Smith +   mat - the shell matrix
1789273d9f13SBarry Smith -   ctx - the context
1790273d9f13SBarry Smith 
1791273d9f13SBarry Smith    Level: advanced
1792273d9f13SBarry Smith 
179395452b02SPatrick Sanan    Fortran Notes:
179495452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
1795daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1796273d9f13SBarry Smith 
1797db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
17980bc0a719SBarry Smith @*/
17997087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
1800273d9f13SBarry Smith {
1801273d9f13SBarry Smith   PetscFunctionBegin;
18020700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1803cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx));
18043a40ed3dSBarry Smith   PetscFunctionReturn(0);
1805e51e0e81SBarry Smith }
1806e51e0e81SBarry Smith 
1807db77db73SJeremy L Thompson /*@C
1808db77db73SJeremy L Thompson  MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs()
1809db77db73SJeremy L Thompson 
1810db77db73SJeremy L Thompson  Logically collective
1811db77db73SJeremy L Thompson 
1812db77db73SJeremy L Thompson     Input Parameters:
1813db77db73SJeremy L Thompson +   mat   - the shell matrix
1814db77db73SJeremy L Thompson -   vtype - type to use for creating vectors
1815db77db73SJeremy L Thompson 
1816db77db73SJeremy L Thompson  Notes:
1817db77db73SJeremy L Thompson 
1818db77db73SJeremy L Thompson  Level: advanced
1819db77db73SJeremy L Thompson 
1820db781477SPatrick Sanan .seealso: `MatCreateVecs()`
1821db77db73SJeremy L Thompson @*/
1822db77db73SJeremy L Thompson PetscErrorCode  MatShellSetVecType(Mat mat,VecType vtype)
1823db77db73SJeremy L Thompson {
1824db77db73SJeremy L Thompson   PetscFunctionBegin;
1825cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype));
1826db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1827db77db73SJeremy L Thompson }
1828db77db73SJeremy L Thompson 
18290c0fd78eSBarry Smith /*@
18300c0fd78eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
18310c0fd78eSBarry Smith           after MatCreateShell()
18320c0fd78eSBarry Smith 
18330c0fd78eSBarry Smith    Logically Collective on Mat
18340c0fd78eSBarry Smith 
18350c0fd78eSBarry Smith     Input Parameter:
18360c0fd78eSBarry Smith .   mat - the shell matrix
18370c0fd78eSBarry Smith 
18380c0fd78eSBarry Smith   Level: advanced
18390c0fd78eSBarry Smith 
1840db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
18410c0fd78eSBarry Smith @*/
18420c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A)
18430c0fd78eSBarry Smith {
18440c0fd78eSBarry Smith   PetscFunctionBegin;
18450c0fd78eSBarry Smith   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1846cac4c232SBarry Smith   PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A));
18470c0fd78eSBarry Smith   PetscFunctionReturn(0);
18480c0fd78eSBarry Smith }
18490c0fd78eSBarry Smith 
1850c16cb8f2SBarry Smith /*@C
1851f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
1852f3b1f45cSBarry Smith 
1853f3b1f45cSBarry Smith    Logically Collective on Mat
1854f3b1f45cSBarry Smith 
1855f3b1f45cSBarry Smith     Input Parameters:
1856f3b1f45cSBarry Smith +   mat - the shell matrix
1857f3b1f45cSBarry Smith .   f - the function
1858f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1859f3b1f45cSBarry Smith -   ctx - an optional context for the function
1860f3b1f45cSBarry Smith 
1861f3b1f45cSBarry Smith    Output Parameter:
1862f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1863f3b1f45cSBarry Smith 
1864f3b1f45cSBarry Smith    Options Database:
1865f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1866f3b1f45cSBarry Smith 
1867f3b1f45cSBarry Smith    Level: advanced
1868f3b1f45cSBarry Smith 
186995452b02SPatrick Sanan    Fortran Notes:
187095452b02SPatrick Sanan     Not supported from Fortran
1871f3b1f45cSBarry Smith 
1872db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1873f3b1f45cSBarry Smith @*/
1874f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1875f3b1f45cSBarry Smith {
1876f3b1f45cSBarry Smith   PetscInt       m,n;
1877f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1878f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
187974e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1880f3b1f45cSBarry Smith 
1881f3b1f45cSBarry Smith   PetscFunctionBegin;
1882f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
18839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v));
18849566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat,&m,&n));
18859566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf));
18869566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf,f,ctx));
18879566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf,base,NULL));
1888f3b1f45cSBarry Smith 
18899566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf));
18909566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat,MATAIJ,&Dmat));
1891f3b1f45cSBarry Smith 
18929566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff));
18939566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN));
18949566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm));
18959566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm));
1896f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1897f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1898f3b1f45cSBarry Smith     if (v) {
18999566063dSJacob 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)));
19009566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view"));
19019566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view"));
19029566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view"));
1903f3b1f45cSBarry Smith     }
1904f3b1f45cSBarry Smith   } else if (v) {
19059566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n"));
1906f3b1f45cSBarry Smith   }
1907f3b1f45cSBarry Smith   if (flg) *flg = flag;
19089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19109566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
1912f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1913f3b1f45cSBarry Smith }
1914f3b1f45cSBarry Smith 
1915f3b1f45cSBarry Smith /*@C
19167301b172SPierre Jolivet     MatShellTestMultTranspose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
1917f3b1f45cSBarry Smith 
1918f3b1f45cSBarry Smith    Logically Collective on Mat
1919f3b1f45cSBarry Smith 
1920f3b1f45cSBarry Smith     Input Parameters:
1921f3b1f45cSBarry Smith +   mat - the shell matrix
1922f3b1f45cSBarry Smith .   f - the function
1923f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1924f3b1f45cSBarry Smith -   ctx - an optional context for the function
1925f3b1f45cSBarry Smith 
1926f3b1f45cSBarry Smith    Output Parameter:
1927f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1928f3b1f45cSBarry Smith 
1929f3b1f45cSBarry Smith    Options Database:
1930f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1931f3b1f45cSBarry Smith 
1932f3b1f45cSBarry Smith    Level: advanced
1933f3b1f45cSBarry Smith 
193495452b02SPatrick Sanan    Fortran Notes:
193595452b02SPatrick Sanan     Not supported from Fortran
1936f3b1f45cSBarry Smith 
1937db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1938f3b1f45cSBarry Smith @*/
1939f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1940f3b1f45cSBarry Smith {
1941f3b1f45cSBarry Smith   Vec            x,y,z;
1942f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
1943f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1944f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
194574e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1946f3b1f45cSBarry Smith 
1947f3b1f45cSBarry Smith   PetscFunctionBegin;
1948f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
19499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v));
19509566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat,&x,&y));
19519566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y,&z));
19529566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat,&m,&n));
19539566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat,&M,&N));
19549566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf));
19559566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf,f,ctx));
19569566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf,base,NULL));
19579566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf));
19589566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf));
19599566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat,MATAIJ,&Dmat));
1960f3b1f45cSBarry Smith 
19619566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff));
19629566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN));
19639566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm));
19649566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm));
1965f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1966f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1967f3b1f45cSBarry Smith     if (v) {
19689566063dSJacob 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)));
19699566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
19709566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
19719566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view"));
1972f3b1f45cSBarry Smith     }
1973f3b1f45cSBarry Smith   } else if (v) {
19749566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n"));
1975f3b1f45cSBarry Smith   }
1976f3b1f45cSBarry Smith   if (flg) *flg = flag;
19779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19809566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
19829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
19839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
1984f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1985f3b1f45cSBarry Smith }
1986f3b1f45cSBarry Smith 
1987f3b1f45cSBarry Smith /*@C
19880c0fd78eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
1989e51e0e81SBarry Smith 
19903f9fe445SBarry Smith    Logically Collective on Mat
1991fee21e36SBarry Smith 
1992c7fcc2eaSBarry Smith     Input Parameters:
1993c7fcc2eaSBarry Smith +   mat - the shell matrix
1994c7fcc2eaSBarry Smith .   op - the name of the operation
1995789d8953SBarry Smith -   g - the function that provides the operation.
1996c7fcc2eaSBarry Smith 
199715091d37SBarry Smith    Level: advanced
199815091d37SBarry Smith 
1999fae171e0SBarry Smith     Usage:
2000e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
2001b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
2002b77ba244SStefano Zampini $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
20030b627109SLois Curfman McInnes 
2004a62d957aSLois Curfman McInnes     Notes:
2005e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
20061c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
2007a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
20081c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
2009a62d957aSLois Curfman McInnes 
2010a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
2011deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
2012deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
2013deebb3c3SLois Curfman McInnes     routines, e.g.,
2014a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2015a62d957aSLois Curfman McInnes 
20164aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
20174aa34b0aSBarry Smith     nonzero on failure.
20184aa34b0aSBarry Smith 
2019a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
2020a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
2021a62d957aSLois Curfman McInnes     set by MatCreateShell().
2022a62d957aSLois Curfman McInnes 
2023b77ba244SStefano Zampini     Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation()
2024b77ba244SStefano Zampini 
202595452b02SPatrick Sanan     Fortran Notes:
202695452b02SPatrick Sanan     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
2027c4762a1bSJed Brown        generate a matrix. See src/mat/tests/ex120f.F
2028501d9185SBarry Smith 
2029db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2030e51e0e81SBarry Smith @*/
2031789d8953SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void))
2032e51e0e81SBarry Smith {
20333a40ed3dSBarry Smith   PetscFunctionBegin;
20340700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2035cac4c232SBarry Smith   PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g));
20363a40ed3dSBarry Smith   PetscFunctionReturn(0);
2037e51e0e81SBarry Smith }
2038f0479e8cSBarry Smith 
2039d4bb536fSBarry Smith /*@C
2040d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
2041d4bb536fSBarry Smith 
2042c7fcc2eaSBarry Smith     Not Collective
2043c7fcc2eaSBarry Smith 
2044d4bb536fSBarry Smith     Input Parameters:
2045c7fcc2eaSBarry Smith +   mat - the shell matrix
2046c7fcc2eaSBarry Smith -   op - the name of the operation
2047d4bb536fSBarry Smith 
2048d4bb536fSBarry Smith     Output Parameter:
2049789d8953SBarry Smith .   g - the function that provides the operation.
2050d4bb536fSBarry Smith 
205115091d37SBarry Smith     Level: advanced
205215091d37SBarry Smith 
2053d4bb536fSBarry Smith     Notes:
2054e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
2055d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
2056d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
2057d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
2058d4bb536fSBarry Smith 
2059d4bb536fSBarry Smith     All user-provided functions have the same calling
2060d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
2061d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
2062d4bb536fSBarry Smith     routines, e.g.,
2063d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2064d4bb536fSBarry Smith 
2065d4bb536fSBarry Smith     Within each user-defined routine, the user should call
2066d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
2067d4bb536fSBarry Smith     set by MatCreateShell().
2068d4bb536fSBarry Smith 
2069db781477SPatrick Sanan .seealso: `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2070d4bb536fSBarry Smith @*/
2071789d8953SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void))
2072d4bb536fSBarry Smith {
20733a40ed3dSBarry Smith   PetscFunctionBegin;
20740700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2075cac4c232SBarry Smith   PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g));
20763a40ed3dSBarry Smith   PetscFunctionReturn(0);
2077d4bb536fSBarry Smith }
2078b77ba244SStefano Zampini 
2079b77ba244SStefano Zampini /*@
2080b77ba244SStefano Zampini     MatIsShell - Inquires if a matrix is derived from MATSHELL
2081b77ba244SStefano Zampini 
2082b77ba244SStefano Zampini     Input Parameter:
2083b77ba244SStefano Zampini .   mat - the matrix
2084b77ba244SStefano Zampini 
2085b77ba244SStefano Zampini     Output Parameter:
2086b77ba244SStefano Zampini .   flg - the boolean value
2087b77ba244SStefano Zampini 
2088b77ba244SStefano Zampini     Level: developer
2089b77ba244SStefano Zampini 
2090b77ba244SStefano 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)
2091b77ba244SStefano Zampini 
2092db781477SPatrick Sanan .seealso: `MatCreateShell()`
2093b77ba244SStefano Zampini @*/
2094b77ba244SStefano Zampini PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2095b77ba244SStefano Zampini {
2096b77ba244SStefano Zampini   PetscFunctionBegin;
2097b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2098dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(flg,2);
2099b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
2100b77ba244SStefano Zampini   PetscFunctionReturn(0);
2101b77ba244SStefano Zampini }
2102