xref: /petsc/src/mat/impls/shell/shell.c (revision 27430b45d0a5eedd7547ed99d6048b6750b3fa8a)
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 */
62800f99ffSJeremy L Thompson   PetscContainer ctxcontainer;
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 */
69d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx)
70d71ae5a4SJacob Faibussowitsch {
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) {
8248a46eb9SPierre Jolivet     if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
839566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->right_work));
849566063dSJacob Faibussowitsch     PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0));
8545960306SStefano Zampini     *xx = shell->right_work;
8645960306SStefano Zampini   }
873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8845960306SStefano Zampini }
8945960306SStefano Zampini 
9045960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
91d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x)
92d71ae5a4SJacob Faibussowitsch {
9345960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
9445960306SStefano Zampini 
9545960306SStefano Zampini   PetscFunctionBegin;
9645960306SStefano Zampini   if (shell->zrows) {
979566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
989566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
9945960306SStefano Zampini   }
1003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10145960306SStefano Zampini }
10245960306SStefano Zampini 
10345960306SStefano Zampini /*
10445960306SStefano Zampini      Store and scale values on zeroed rows
10545960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
10645960306SStefano Zampini */
107d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx)
108d71ae5a4SJacob Faibussowitsch {
10945960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
11045960306SStefano Zampini 
11145960306SStefano Zampini   PetscFunctionBegin;
11245960306SStefano Zampini   *xx = NULL;
11345960306SStefano Zampini   if (!shell->zrows) {
11445960306SStefano Zampini     *xx = x;
11545960306SStefano Zampini   } else {
11648a46eb9SPierre Jolivet     if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
1179566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->left_work));
1189566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
1199566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1209566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1219566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1229566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1239566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
12445960306SStefano Zampini     *xx = shell->left_work;
12545960306SStefano Zampini   }
1263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12745960306SStefano Zampini }
12845960306SStefano Zampini 
12945960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
130d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x)
131d71ae5a4SJacob Faibussowitsch {
13245960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
13345960306SStefano Zampini 
13445960306SStefano Zampini   PetscFunctionBegin;
1351baa6e33SBarry Smith   if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0));
13645960306SStefano Zampini   if (shell->zrows) {
1379566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
1389566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
13945960306SStefano Zampini   }
1403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14145960306SStefano Zampini }
14245960306SStefano Zampini 
1438fe8eb27SJed Brown /*
1440c0fd78eSBarry Smith       xx = diag(left)*x
1458fe8eb27SJed Brown */
146d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx)
147d71ae5a4SJacob Faibussowitsch {
1488fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1498fe8eb27SJed Brown 
1508fe8eb27SJed Brown   PetscFunctionBegin;
1510298fd71SBarry Smith   *xx = NULL;
1528fe8eb27SJed Brown   if (!shell->left) {
1538fe8eb27SJed Brown     *xx = x;
1548fe8eb27SJed Brown   } else {
1559566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work));
1569566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->left_work, x, shell->left));
1578fe8eb27SJed Brown     *xx = shell->left_work;
1588fe8eb27SJed Brown   }
1593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1608fe8eb27SJed Brown }
1618fe8eb27SJed Brown 
1620c0fd78eSBarry Smith /*
1630c0fd78eSBarry Smith      xx = diag(right)*x
1640c0fd78eSBarry Smith */
165d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx)
166d71ae5a4SJacob Faibussowitsch {
1678fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1688fe8eb27SJed Brown 
1698fe8eb27SJed Brown   PetscFunctionBegin;
1700298fd71SBarry Smith   *xx = NULL;
1718fe8eb27SJed Brown   if (!shell->right) {
1728fe8eb27SJed Brown     *xx = x;
1738fe8eb27SJed Brown   } else {
1749566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work));
1759566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work, x, shell->right));
1768fe8eb27SJed Brown     *xx = shell->right_work;
1778fe8eb27SJed Brown   }
1783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1798fe8eb27SJed Brown }
1808fe8eb27SJed Brown 
1810c0fd78eSBarry Smith /*
1820c0fd78eSBarry Smith     x = diag(left)*x
1830c0fd78eSBarry Smith */
184d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x)
185d71ae5a4SJacob Faibussowitsch {
1868fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1878fe8eb27SJed Brown 
1888fe8eb27SJed Brown   PetscFunctionBegin;
1899566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left));
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1918fe8eb27SJed Brown }
1928fe8eb27SJed Brown 
1930c0fd78eSBarry Smith /*
1940c0fd78eSBarry Smith     x = diag(right)*x
1950c0fd78eSBarry Smith */
196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x)
197d71ae5a4SJacob Faibussowitsch {
1988fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1998fe8eb27SJed Brown 
2008fe8eb27SJed Brown   PetscFunctionBegin;
2019566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(x, x, shell->right));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2038fe8eb27SJed Brown }
2048fe8eb27SJed Brown 
2050c0fd78eSBarry Smith /*
2060c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2070c0fd78eSBarry Smith 
2080c0fd78eSBarry Smith          On input Y already contains A*x
2090c0fd78eSBarry Smith */
210d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y)
211d71ae5a4SJacob Faibussowitsch {
2128fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
2138fe8eb27SJed Brown 
2148fe8eb27SJed Brown   PetscFunctionBegin;
2158fe8eb27SJed Brown   if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */
2168fe8eb27SJed Brown     PetscInt           i, m;
2178fe8eb27SJed Brown     const PetscScalar *x, *d;
2188fe8eb27SJed Brown     PetscScalar       *y;
2199566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X, &m));
2209566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift, &d));
2219566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X, &x));
2229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y, &y));
2238fe8eb27SJed Brown     for (i = 0; i < m; i++) y[i] = shell->vscale * y[i] + d[i] * x[i];
2249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift, &d));
2259566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X, &x));
2269566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y, &y));
2270c0fd78eSBarry Smith   } else {
2289566063dSJacob Faibussowitsch     PetscCall(VecScale(Y, shell->vscale));
2298fe8eb27SJed Brown   }
2309566063dSJacob Faibussowitsch   if (shell->vshift != 0.0) PetscCall(VecAXPY(Y, shell->vshift, X)); /* if test is for non-square matrices */
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2328fe8eb27SJed Brown }
233e51e0e81SBarry Smith 
234d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx)
235d71ae5a4SJacob Faibussowitsch {
236800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
237800f99ffSJeremy L Thompson 
238789d8953SBarry Smith   PetscFunctionBegin;
239800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx));
240800f99ffSJeremy L Thompson   else *(void **)ctx = NULL;
2413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
242789d8953SBarry Smith }
243789d8953SBarry Smith 
2449d225801SJed Brown /*@
24511a5261eSBarry Smith     MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix.
246b4fd4287SBarry Smith 
247c7fcc2eaSBarry Smith     Not Collective
248c7fcc2eaSBarry Smith 
249b4fd4287SBarry Smith     Input Parameter:
25011a5261eSBarry Smith .   mat - the matrix, should have been created with `MatCreateShell()`
251b4fd4287SBarry Smith 
252b4fd4287SBarry Smith     Output Parameter:
253b4fd4287SBarry Smith .   ctx - the user provided context
254b4fd4287SBarry Smith 
25515091d37SBarry Smith     Level: advanced
25615091d37SBarry Smith 
25711a5261eSBarry Smith    Fortran Note:
258*27430b45SBarry Smith     You must write a Fortran interface definition for this
259daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
260a62d957aSLois Curfman McInnes 
26111a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2620bc0a719SBarry Smith @*/
263d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx)
264d71ae5a4SJacob Faibussowitsch {
2653a40ed3dSBarry Smith   PetscFunctionBegin;
2660700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2674482741eSBarry Smith   PetscValidPointer(ctx, 2);
268cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx));
2693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
270b4fd4287SBarry Smith }
271b4fd4287SBarry Smith 
272d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc)
273d71ae5a4SJacob Faibussowitsch {
27445960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell *)mat->data;
27545960306SStefano Zampini   Vec             x = NULL, b = NULL;
27645960306SStefano Zampini   IS              is1, is2;
27745960306SStefano Zampini   const PetscInt *ridxs;
27845960306SStefano Zampini   PetscInt       *idxs, *gidxs;
27945960306SStefano Zampini   PetscInt        cum, rst, cst, i;
28045960306SStefano Zampini 
28145960306SStefano Zampini   PetscFunctionBegin;
28248a46eb9SPierre Jolivet   if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals));
28348a46eb9SPierre Jolivet   if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w));
2849566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat, &rst, NULL));
2859566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL));
28645960306SStefano Zampini 
28745960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &idxs));
28945960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
2909566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1));
2919566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2929566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals, is1, diag));
29345960306SStefano Zampini   if (shell->zrows) {
2949566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows, is1, &is2));
2959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
2969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
29745960306SStefano Zampini     shell->zrows = is2;
29845960306SStefano Zampini   } else shell->zrows = is1;
29945960306SStefano Zampini 
30045960306SStefano Zampini   /* Create scatters for diagonal values communications */
3019566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
3029566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
30345960306SStefano Zampini 
30445960306SStefano Zampini   /* row scatter: from/to left vector */
3059566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &b));
3069566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r));
30745960306SStefano Zampini 
30845960306SStefano Zampini   /* col scatter: from right vector to left vector */
3099566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows, &ridxs));
3109566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows, &nr));
3119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &gidxs));
31245960306SStefano Zampini   for (i = 0, cum = 0; i < nr; i++) {
31345960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
31445960306SStefano Zampini     gidxs[cum] = ridxs[i];
31545960306SStefano Zampini     cum++;
31645960306SStefano Zampini   }
3179566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1));
3189566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c));
3199566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
3209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
3219566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
32245960306SStefano Zampini 
32345960306SStefano Zampini   /* Expand/create index set of zeroed columns */
32445960306SStefano Zampini   if (rc) {
3259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc, &idxs));
32645960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3279566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1));
3289566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
32945960306SStefano Zampini     if (shell->zcols) {
3309566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols, is1, &is2));
3319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
33345960306SStefano Zampini       shell->zcols = is2;
33445960306SStefano Zampini     } else shell->zcols = is1;
33545960306SStefano Zampini   }
3363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33745960306SStefano Zampini }
33845960306SStefano Zampini 
339d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
340d71ae5a4SJacob Faibussowitsch {
341ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
34245960306SStefano Zampini   PetscInt   nr, *lrows;
34345960306SStefano Zampini 
34445960306SStefano Zampini   PetscFunctionBegin;
34545960306SStefano Zampini   if (x && b) {
34645960306SStefano Zampini     Vec          xt;
34745960306SStefano Zampini     PetscScalar *vals;
34845960306SStefano Zampini     PetscInt    *gcols, i, st, nl, nc;
34945960306SStefano Zampini 
3509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &gcols));
3519371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3529371c9d4SSatish Balay       if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
35345960306SStefano Zampini 
3549566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, NULL));
3559566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3569566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc, &vals));
3579566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3589566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3599566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3609566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3619566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */
36245960306SStefano Zampini 
3639566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3649566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3659566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
36645960306SStefano Zampini     for (i = 0; i < nl; i++) {
36745960306SStefano Zampini       PetscInt g = i + st;
36845960306SStefano Zampini       if (g > mat->rmap->N) continue;
36945960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3709566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES));
37145960306SStefano Zampini     }
3729566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
3739566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3749566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1, x2 * diag] */
3759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3769566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
37745960306SStefano Zampini   }
3789566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL));
3799566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE));
3801baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL));
3819566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
3823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38345960306SStefano Zampini }
38445960306SStefano Zampini 
385d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b)
386d71ae5a4SJacob Faibussowitsch {
387ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
38845960306SStefano Zampini   PetscInt  *lrows, *lcols;
38945960306SStefano Zampini   PetscInt   nr, nc;
39045960306SStefano Zampini   PetscBool  congruent;
39145960306SStefano Zampini 
39245960306SStefano Zampini   PetscFunctionBegin;
39345960306SStefano Zampini   if (x && b) {
39445960306SStefano Zampini     Vec          xt, bt;
39545960306SStefano Zampini     PetscScalar *vals;
39645960306SStefano Zampini     PetscInt    *grows, *gcols, i, st, nl;
39745960306SStefano Zampini 
3989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n, &grows, n, &gcols));
3999371c9d4SSatish Balay     for (i = 0, nr = 0; i < n; i++)
4009371c9d4SSatish Balay       if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
4019371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
4029371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
4039566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &vals));
40445960306SStefano Zampini 
4059566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, &bt));
4069566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
4079566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
4089566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
4099566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
4109566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt, -1.0, x));                             /* xt = [0, -x2] */
4119566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, xt, bt));                             /* bt = [-A12*x2,-A22*x2] */
4129566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */
4139566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4149566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4159566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b, 1.0, bt));                              /* b  = [b1 - A12*x2, b2] */
4169566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
4179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4189566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4199566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
42045960306SStefano Zampini 
4219566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
4229566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
4239566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
42445960306SStefano Zampini     for (i = 0; i < nl; i++) {
42545960306SStefano Zampini       PetscInt g = i + st;
42645960306SStefano Zampini       if (g > mat->rmap->N) continue;
42745960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4289566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES));
42945960306SStefano Zampini     }
4309566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4319566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4329566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1 - A12*x2, x2 * diag] */
4339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4359566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows, gcols));
43645960306SStefano Zampini   }
4379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL));
4389566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat, &congruent));
43945960306SStefano Zampini   if (congruent) {
44045960306SStefano Zampini     nc    = nr;
44145960306SStefano Zampini     lcols = lrows;
44245960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
44345960306SStefano Zampini     PetscInt i, nt, *t;
44445960306SStefano Zampini 
4459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &t));
4469371c9d4SSatish Balay     for (i = 0, nt = 0; i < n; i++)
4479371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4489566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL));
4499566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
45045960306SStefano Zampini   }
4519566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE));
45248a46eb9SPierre Jolivet   if (!congruent) PetscCall(PetscFree(lcols));
4539566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4541baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL));
4553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45645960306SStefano Zampini }
45745960306SStefano Zampini 
458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat)
459d71ae5a4SJacob Faibussowitsch {
460bf0cc555SLisandro Dalcin   Mat_Shell              *shell = (Mat_Shell *)mat->data;
461b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
462ed3cc1f0SBarry Smith 
4633a40ed3dSBarry Smith   PetscFunctionBegin;
4641baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4659566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps)));
4669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4689566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4789566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4799566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
482b77ba244SStefano Zampini 
483b77ba244SStefano Zampini   matmat = shell->matmat;
484b77ba244SStefano Zampini   while (matmat) {
485b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
486b77ba244SStefano Zampini 
4879566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL));
4889566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
4899566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
4909566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
491b77ba244SStefano Zampini     matmat = next;
492b77ba244SStefano Zampini   }
493800f99ffSJeremy L Thompson   PetscCall(MatShellSetContext(mat, NULL));
4949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL));
4959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL));
496800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL));
4979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL));
4989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL));
4999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
5009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
5019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
5029566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504b77ba244SStefano Zampini }
505b77ba244SStefano Zampini 
506b77ba244SStefano Zampini typedef struct {
507b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
508b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
509b77ba244SStefano Zampini   void *userdata;
510b77ba244SStefano Zampini   Mat   B;
511b77ba244SStefano Zampini   Mat   Bt;
512b77ba244SStefano Zampini   Mat   axpy;
513b77ba244SStefano Zampini } MatMatDataShell;
514b77ba244SStefano Zampini 
515d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data)
516d71ae5a4SJacob Faibussowitsch {
517b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
518b77ba244SStefano Zampini 
519b77ba244SStefano Zampini   PetscFunctionBegin;
5201baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
5219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5249566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
526b77ba244SStefano Zampini }
527b77ba244SStefano Zampini 
528d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
529d71ae5a4SJacob Faibussowitsch {
530b77ba244SStefano Zampini   Mat_Product     *product;
531b77ba244SStefano Zampini   Mat              A, B;
532b77ba244SStefano Zampini   MatMatDataShell *mdata;
533b77ba244SStefano Zampini   PetscScalar      zero = 0.0;
534b77ba244SStefano Zampini 
535b77ba244SStefano Zampini   PetscFunctionBegin;
536b77ba244SStefano Zampini   MatCheckProduct(D, 1);
537b77ba244SStefano Zampini   product = D->product;
53828b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
539b77ba244SStefano Zampini   A     = product->A;
540b77ba244SStefano Zampini   B     = product->B;
541b77ba244SStefano Zampini   mdata = (MatMatDataShell *)product->data;
542b77ba244SStefano Zampini   if (mdata->numeric) {
543b77ba244SStefano Zampini     Mat_Shell *shell                = (Mat_Shell *)A->data;
544b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
545b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
546b77ba244SStefano Zampini     PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
547b77ba244SStefano Zampini 
548b77ba244SStefano Zampini     if (shell->managescalingshifts) {
54908401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
550b77ba244SStefano Zampini       if (shell->right || shell->left) {
551b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
552b77ba244SStefano Zampini         if (!mdata->B) {
5539566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
554b77ba244SStefano Zampini         } else {
555b77ba244SStefano Zampini           newB = PETSC_FALSE;
556b77ba244SStefano Zampini         }
5579566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
558b77ba244SStefano Zampini       }
559b77ba244SStefano Zampini       switch (product->type) {
560b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5611baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
562b77ba244SStefano Zampini         break;
563b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5641baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
565b77ba244SStefano Zampini         break;
566b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5671baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
568b77ba244SStefano Zampini         break;
569b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
570b77ba244SStefano Zampini         if (shell->right && shell->left) {
571b77ba244SStefano Zampini           PetscBool flg;
572b77ba244SStefano Zampini 
5739566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5749371c9d4SSatish Balay           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,
5759371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
576b77ba244SStefano Zampini         }
5771baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
578b77ba244SStefano Zampini         break;
579b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
580b77ba244SStefano Zampini         if (shell->right && shell->left) {
581b77ba244SStefano Zampini           PetscBool flg;
582b77ba244SStefano Zampini 
5839566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5849371c9d4SSatish Balay           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,
5859371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
586b77ba244SStefano Zampini         }
5871baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
588b77ba244SStefano Zampini         break;
589d71ae5a4SJacob Faibussowitsch       default:
590d71ae5a4SJacob Faibussowitsch         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);
591b77ba244SStefano Zampini       }
592b77ba244SStefano Zampini     }
593b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
594b77ba244SStefano Zampini     D->product              = NULL;
595b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
596b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
597b77ba244SStefano Zampini 
5989566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata));
599b77ba244SStefano Zampini 
600b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
6019566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
602b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
603b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
604b77ba244SStefano Zampini     D->product              = product;
605b77ba244SStefano Zampini 
606b77ba244SStefano Zampini     if (shell->managescalingshifts) {
6079566063dSJacob Faibussowitsch       PetscCall(MatScale(D, shell->vscale));
608b77ba244SStefano Zampini       switch (product->type) {
609b77ba244SStefano Zampini       case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
610b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
611b77ba244SStefano Zampini         if (shell->left) {
6129566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->left, NULL));
613b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
6149566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
615b77ba244SStefano Zampini             if (shell->dshift) {
6169566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->left_work));
6179566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work, shell->vshift));
6189566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
619b77ba244SStefano Zampini             } else {
6209566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work, shell->vshift));
621b77ba244SStefano Zampini             }
622b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
623b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
624b77ba244SStefano Zampini               MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
625b77ba244SStefano Zampini 
6269566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6279566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6289566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
629b77ba244SStefano Zampini             } else {
630b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
631b77ba244SStefano Zampini 
6329566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6339566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->B, str));
634b77ba244SStefano Zampini             }
635b77ba244SStefano Zampini           }
636b77ba244SStefano Zampini         }
637b77ba244SStefano Zampini         break;
638b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
639b77ba244SStefano Zampini         if (shell->right) {
6409566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->right, NULL));
641b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
642b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
643b77ba244SStefano Zampini 
6449566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
645b77ba244SStefano Zampini             if (shell->dshift) {
6469566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->right_work));
6479566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work, shell->vshift));
6489566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
649b77ba244SStefano Zampini             } else {
6509566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work, shell->vshift));
651b77ba244SStefano Zampini             }
6529566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6539566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
654b77ba244SStefano Zampini           }
655b77ba244SStefano Zampini         }
656b77ba244SStefano Zampini         break;
657b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
658b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6599371c9d4SSatish Balay         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,
6609371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
661b77ba244SStefano Zampini         break;
662d71ae5a4SJacob Faibussowitsch       default:
663d71ae5a4SJacob Faibussowitsch         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);
664b77ba244SStefano Zampini       }
665b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
666b77ba244SStefano Zampini         Mat              X;
667b77ba244SStefano Zampini         PetscObjectState axpy_state;
668b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
669b77ba244SStefano Zampini 
6709566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy, &X));
6719566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
67208401ef6SPierre 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,...)");
673b77ba244SStefano Zampini         if (!mdata->axpy) {
674b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
6759566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
6769566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy, product->type));
6779566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6789566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
679b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
680b77ba244SStefano Zampini           PetscBool flg;
681b77ba244SStefano Zampini 
6829566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
6839566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
684b77ba244SStefano Zampini           if (!flg) {
685b77ba244SStefano Zampini             str = DIFFERENT_NONZERO_PATTERN;
6869566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
6879566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
688b77ba244SStefano Zampini           }
689b77ba244SStefano Zampini         }
6909566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
6919566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
692b77ba244SStefano Zampini       }
693b77ba244SStefano Zampini     }
694b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
6953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
696b77ba244SStefano Zampini }
697b77ba244SStefano Zampini 
698d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
699d71ae5a4SJacob Faibussowitsch {
700b77ba244SStefano Zampini   Mat_Product            *product;
701b77ba244SStefano Zampini   Mat                     A, B;
702b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
703b77ba244SStefano Zampini   Mat_Shell              *shell;
704b77ba244SStefano Zampini   PetscBool               flg;
705b77ba244SStefano Zampini   char                    composedname[256];
706b77ba244SStefano Zampini   MatMatDataShell        *mdata;
707b77ba244SStefano Zampini 
708b77ba244SStefano Zampini   PetscFunctionBegin;
709b77ba244SStefano Zampini   MatCheckProduct(D, 1);
710b77ba244SStefano Zampini   product = D->product;
71128b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
712b77ba244SStefano Zampini   A      = product->A;
713b77ba244SStefano Zampini   B      = product->B;
714b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
715b77ba244SStefano Zampini   matmat = shell->matmat;
7169566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
717b77ba244SStefano Zampini   while (matmat) {
7189566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
719b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
720b77ba244SStefano Zampini     if (flg) break;
721b77ba244SStefano Zampini     matmat = matmat->next;
722b77ba244SStefano Zampini   }
72328b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
724b77ba244SStefano Zampini   switch (product->type) {
725d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
726d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
727d71ae5a4SJacob Faibussowitsch     break;
728d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
729d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
730d71ae5a4SJacob Faibussowitsch     break;
731d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
732d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
733d71ae5a4SJacob Faibussowitsch     break;
734d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
735d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
736d71ae5a4SJacob Faibussowitsch     break;
737d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
738d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
739d71ae5a4SJacob Faibussowitsch     break;
740d71ae5a4SJacob Faibussowitsch   default:
741d71ae5a4SJacob Faibussowitsch     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);
742b77ba244SStefano Zampini   }
743b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
744b77ba244SStefano Zampini   if (matmat->resultname) {
7459566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
74648a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
747b77ba244SStefano Zampini   }
748b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
749b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
750b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
751b77ba244SStefano Zampini   /* attach product data */
7529566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
753b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
754b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
755b77ba244SStefano Zampini   if (matmat->symbolic) {
7569566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata));
757b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7589566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
759b77ba244SStefano Zampini   }
76028b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
76128b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
762b77ba244SStefano Zampini   D->product->data    = mdata;
763b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
764b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
765b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
766b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
768b77ba244SStefano Zampini }
769b77ba244SStefano Zampini 
770d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
771d71ae5a4SJacob Faibussowitsch {
772b77ba244SStefano Zampini   Mat_Product            *product;
773b77ba244SStefano Zampini   Mat                     A, B;
774b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
775b77ba244SStefano Zampini   Mat_Shell              *shell;
776b77ba244SStefano Zampini   PetscBool               flg;
777b77ba244SStefano Zampini   char                    composedname[256];
778b77ba244SStefano Zampini 
779b77ba244SStefano Zampini   PetscFunctionBegin;
780b77ba244SStefano Zampini   MatCheckProduct(D, 1);
781b77ba244SStefano Zampini   product = D->product;
782b77ba244SStefano Zampini   A       = product->A;
783b77ba244SStefano Zampini   B       = product->B;
7849566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
7853ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
786b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
787b77ba244SStefano Zampini   matmat = shell->matmat;
7889566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
789b77ba244SStefano Zampini   while (matmat) {
7909566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
791b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
792b77ba244SStefano Zampini     if (flg) break;
793b77ba244SStefano Zampini     matmat = matmat->next;
794b77ba244SStefano Zampini   }
7959371c9d4SSatish Balay   if (flg) {
7969371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
7979371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
799b77ba244SStefano Zampini }
800b77ba244SStefano Zampini 
801d71ae5a4SJacob Faibussowitsch 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)
802d71ae5a4SJacob Faibussowitsch {
803b77ba244SStefano Zampini   PetscBool               flg;
804b77ba244SStefano Zampini   Mat_Shell              *shell;
805b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
806b77ba244SStefano Zampini 
807b77ba244SStefano Zampini   PetscFunctionBegin;
80828b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
80928b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
810b77ba244SStefano Zampini 
811b77ba244SStefano Zampini   /* add product callback */
812b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
813b77ba244SStefano Zampini   matmat = shell->matmat;
814b77ba244SStefano Zampini   if (!matmat) {
8159566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
816b77ba244SStefano Zampini     matmat = shell->matmat;
817b77ba244SStefano Zampini   } else {
818b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
819b77ba244SStefano Zampini     while (entry) {
8209566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
821b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
822b77ba244SStefano Zampini       matmat = entry;
8232e956fe4SStefano Zampini       if (flg) goto set;
824b77ba244SStefano Zampini       entry = entry->next;
825b77ba244SStefano Zampini     }
8269566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
827b77ba244SStefano Zampini     matmat = matmat->next;
828b77ba244SStefano Zampini   }
829b77ba244SStefano Zampini 
830843d480fSStefano Zampini set:
831b77ba244SStefano Zampini   matmat->symbolic = symbolic;
832b77ba244SStefano Zampini   matmat->numeric  = numeric;
833b77ba244SStefano Zampini   matmat->destroy  = destroy;
834b77ba244SStefano Zampini   matmat->ptype    = ptype;
8359566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8369566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8379566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8389566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8399566063dSJacob 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"));
8409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
842b77ba244SStefano Zampini }
843b77ba244SStefano Zampini 
844b77ba244SStefano Zampini /*@C
84511a5261eSBarry Smith     MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
846b77ba244SStefano Zampini 
847*27430b45SBarry Smith    Logically Collective; No Fortran Support
848b77ba244SStefano Zampini 
849b77ba244SStefano Zampini     Input Parameters:
85011a5261eSBarry Smith +   A - the `MATSHELL` shell matrix
851b77ba244SStefano Zampini .   ptype - the product type
852b77ba244SStefano Zampini .   symbolic - the function for the symbolic phase (can be NULL)
853b77ba244SStefano Zampini .   numeric - the function for the numerical phase
854b77ba244SStefano Zampini .   destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL)
855b77ba244SStefano Zampini .   Btype - the matrix type for the matrix to be multiplied against
856b77ba244SStefano Zampini -   Ctype - the matrix type for the result (can be NULL)
857b77ba244SStefano Zampini 
858b77ba244SStefano Zampini    Level: advanced
859b77ba244SStefano Zampini 
860b77ba244SStefano Zampini     Usage:
861cf53795eSBarry Smith .vb
862cf53795eSBarry Smith       extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**);
863cf53795eSBarry Smith       extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*);
864cf53795eSBarry Smith       extern PetscErrorCode userdestroy(void*);
865cf53795eSBarry Smith       MatCreateShell(comm,m,n,M,N,ctx,&A);
866cf53795eSBarry Smith       MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE);
867cf53795eSBarry Smith       [ create B of type SEQAIJ etc..]
868cf53795eSBarry Smith       MatProductCreate(A,B,NULL,&C);
869cf53795eSBarry Smith       MatProductSetType(C,MATPRODUCT_AB);
870cf53795eSBarry Smith       MatProductSetFromOptions(C);
871cf53795eSBarry Smith       MatProductSymbolic(C); -> actually runs the user defined symbolic operation
872cf53795eSBarry Smith       MatProductNumeric(C); -> actually runs the user defined numeric operation
873cf53795eSBarry Smith       [ use C = A*B ]
874cf53795eSBarry Smith .ve
875b77ba244SStefano Zampini 
876b77ba244SStefano Zampini     Notes:
877cf53795eSBarry Smith     `MATPRODUCT_ABC` is not supported yet.
87811a5261eSBarry Smith 
87911a5261eSBarry Smith     If the symbolic phase is not specified, `MatSetUp()` is called on the result matrix that must have its type set if Ctype is NULL.
88011a5261eSBarry Smith 
881b77ba244SStefano Zampini     Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
882b77ba244SStefano Zampini     PETSc will take care of calling the user-defined callbacks.
883b77ba244SStefano Zampini     It is allowed to specify the same callbacks for different Btype matrix types.
884*27430b45SBarry Smith     The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
885b77ba244SStefano Zampini 
88611a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
887b77ba244SStefano Zampini @*/
888d71ae5a4SJacob Faibussowitsch 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)
889d71ae5a4SJacob Faibussowitsch {
890b77ba244SStefano Zampini   PetscFunctionBegin;
891b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
892b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
89308401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
89428b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
895dadcf809SJacob Faibussowitsch   PetscValidCharPointer(Btype, 6);
896dadcf809SJacob Faibussowitsch   if (Ctype) PetscValidCharPointer(Ctype, 7);
897cac4c232SBarry 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));
8983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
899b77ba244SStefano Zampini }
900b77ba244SStefano Zampini 
901d71ae5a4SJacob Faibussowitsch static 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)
902d71ae5a4SJacob Faibussowitsch {
903b77ba244SStefano Zampini   PetscBool   flg;
904b77ba244SStefano Zampini   char        composedname[256];
905b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
906b77ba244SStefano Zampini   PetscMPIInt size;
907b77ba244SStefano Zampini 
908b77ba244SStefano Zampini   PetscFunctionBegin;
909b77ba244SStefano Zampini   PetscValidType(A, 1);
910b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9119566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
912b77ba244SStefano Zampini     if (flg) break;
913b77ba244SStefano Zampini     Bnames = Bnames->next;
914b77ba244SStefano Zampini   }
915b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9169566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
917b77ba244SStefano Zampini     if (flg) break;
918b77ba244SStefano Zampini     Cnames = Cnames->next;
919b77ba244SStefano Zampini   }
9209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
921b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
922b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9239566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9249566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
926e51e0e81SBarry Smith }
927e51e0e81SBarry Smith 
928d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
929d71ae5a4SJacob Faibussowitsch {
93028f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
931cb8c8a77SBarry Smith   PetscBool               matflg;
932b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9337fabda3fSAlex Fikl 
9347fabda3fSAlex Fikl   PetscFunctionBegin;
9359566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
93628b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9377fabda3fSAlex Fikl 
9389566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(B->ops, A->ops, sizeof(struct _MatOps)));
9399566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(shellB->ops, shellA->ops, sizeof(struct _MatShellOps)));
9407fabda3fSAlex Fikl 
9411baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9427fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9437fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9440c0fd78eSBarry Smith   if (shellA->dshift) {
94548a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9469566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9477fabda3fSAlex Fikl   } else {
9489566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9497fabda3fSAlex Fikl   }
9500c0fd78eSBarry Smith   if (shellA->left) {
95148a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9529566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9537fabda3fSAlex Fikl   } else {
9549566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9557fabda3fSAlex Fikl   }
9560c0fd78eSBarry Smith   if (shellA->right) {
95748a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9589566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9597fabda3fSAlex Fikl   } else {
9609566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9617fabda3fSAlex Fikl   }
9629566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
963ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
964ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
96540e381c3SBarry Smith   if (shellA->axpy) {
9669566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
96740e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
96840e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
969ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
97040e381c3SBarry Smith   }
97145960306SStefano Zampini   if (shellA->zrows) {
9729566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
97348a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9749566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9759566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9769566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9779566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9789566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
97945960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
98045960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
98145960306SStefano Zampini   }
982b77ba244SStefano Zampini 
983b77ba244SStefano Zampini   matmatA = shellA->matmat;
984b77ba244SStefano Zampini   if (matmatA) {
985b77ba244SStefano Zampini     while (matmatA->next) {
9869566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
987b77ba244SStefano Zampini       matmatA = matmatA->next;
988b77ba244SStefano Zampini     }
989b77ba244SStefano Zampini   }
9903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9917fabda3fSAlex Fikl }
9927fabda3fSAlex Fikl 
993d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
994d71ae5a4SJacob Faibussowitsch {
995cb8c8a77SBarry Smith   PetscFunctionBegin;
996800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
997800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
998800f99ffSJeremy L Thompson   PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
9999566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name));
100048a46eb9SPierre Jolivet   if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
10013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1002cb8c8a77SBarry Smith }
1003cb8c8a77SBarry Smith 
1004d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
1005d71ae5a4SJacob Faibussowitsch {
1006ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
100725578ef6SJed Brown   Vec              xx;
1008e3f487b0SBarry Smith   PetscObjectState instate, outstate;
1009ef66eb69SBarry Smith 
1010ef66eb69SBarry Smith   PetscFunctionBegin;
10119566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
10129566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
10139566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10149566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
10159566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1016e3f487b0SBarry Smith   if (instate == outstate) {
1017e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10189566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1019e3f487b0SBarry Smith   }
10209566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10219566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10229566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10239f137db4SBarry Smith 
10249f137db4SBarry Smith   if (shell->axpy) {
1025ef5c7bd2SStefano Zampini     Mat              X;
1026ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1027ef5c7bd2SStefano Zampini 
10289566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10299566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
103008401ef6SPierre 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,...)");
1031b77ba244SStefano Zampini 
10329566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10339566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10349566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10359566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10369f137db4SBarry Smith   }
10373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1038ef66eb69SBarry Smith }
1039ef66eb69SBarry Smith 
1040d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1041d71ae5a4SJacob Faibussowitsch {
10425edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10435edf6516SJed Brown 
10445edf6516SJed Brown   PetscFunctionBegin;
10455edf6516SJed Brown   if (y == z) {
10469566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10479566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10489566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10495edf6516SJed Brown   } else {
10509566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10519566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10525edf6516SJed Brown   }
10533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10545edf6516SJed Brown }
10555edf6516SJed Brown 
1056d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1057d71ae5a4SJacob Faibussowitsch {
105818be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
105925578ef6SJed Brown   Vec              xx;
1060e3f487b0SBarry Smith   PetscObjectState instate, outstate;
106118be62a5SSatish Balay 
106218be62a5SSatish Balay   PetscFunctionBegin;
10639566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
10649566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleLeft(A, xx, &xx));
10659566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10669566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10679566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1068e3f487b0SBarry Smith   if (instate == outstate) {
1069e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10709566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1071e3f487b0SBarry Smith   }
10729566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10739566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleRight(A, y));
10749566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1075350ec83bSStefano Zampini 
1076350ec83bSStefano Zampini   if (shell->axpy) {
1077ef5c7bd2SStefano Zampini     Mat              X;
1078ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1079ef5c7bd2SStefano Zampini 
10809566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10819566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
108208401ef6SPierre 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,...)");
10839566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10849566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10859566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10869566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1087350ec83bSStefano Zampini   }
10883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
108918be62a5SSatish Balay }
109018be62a5SSatish Balay 
1091d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1092d71ae5a4SJacob Faibussowitsch {
10935edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10945edf6516SJed Brown 
10955edf6516SJed Brown   PetscFunctionBegin;
10965edf6516SJed Brown   if (y == z) {
10979566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
10989566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
10999566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11005edf6516SJed Brown   } else {
11019566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11029566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11035edf6516SJed Brown   }
11043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11055edf6516SJed Brown }
11065edf6516SJed Brown 
11070c0fd78eSBarry Smith /*
11080c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11090c0fd78eSBarry Smith */
1110d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1111d71ae5a4SJacob Faibussowitsch {
111218be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
111318be62a5SSatish Balay 
111418be62a5SSatish Balay   PetscFunctionBegin;
11150c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11169566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1117305211d5SBarry 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,...)");
11189566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
11191baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
11209566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
11219566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
11229566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
112345960306SStefano Zampini   if (shell->zrows) {
11249566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
11259566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
112645960306SStefano Zampini   }
112781c02519SBarry Smith   if (shell->axpy) {
1128ef5c7bd2SStefano Zampini     Mat              X;
1129ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1130ef5c7bd2SStefano Zampini 
11319566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11329566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
113308401ef6SPierre 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,...)");
11349566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
11359566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
11369566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
113781c02519SBarry Smith   }
11383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
113918be62a5SSatish Balay }
114018be62a5SSatish Balay 
1141d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1142d71ae5a4SJacob Faibussowitsch {
1143ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1144789d8953SBarry Smith   PetscBool  flg;
1145b24ad042SBarry Smith 
1146ef66eb69SBarry Smith   PetscFunctionBegin;
11479566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
114828b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
11490c0fd78eSBarry Smith   if (shell->left || shell->right) {
11508fe8eb27SJed Brown     if (!shell->dshift) {
11519566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11529566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
11530c0fd78eSBarry Smith     } else {
11549566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
11559566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
11569566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
11570c0fd78eSBarry Smith     }
11589566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
11599566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
11608fe8eb27SJed Brown   } else shell->vshift += a;
11611baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
11623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1163ef66eb69SBarry Smith }
1164ef66eb69SBarry Smith 
1165d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1166d71ae5a4SJacob Faibussowitsch {
11676464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
11686464bf51SAlex Fikl 
11696464bf51SAlex Fikl   PetscFunctionBegin;
11709566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
11710c0fd78eSBarry Smith   if (shell->left || shell->right) {
11729566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
11739f137db4SBarry Smith     if (shell->left && shell->right) {
11749566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11759566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
11769f137db4SBarry Smith     } else if (shell->left) {
11779566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11789f137db4SBarry Smith     } else {
11799566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
11809f137db4SBarry Smith     }
11819566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
11820c0fd78eSBarry Smith   } else {
11839566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1184b253ae0bS“Marek   }
11853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1186b253ae0bS“Marek }
1187b253ae0bS“Marek 
1188d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1189d71ae5a4SJacob Faibussowitsch {
119045960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1191b253ae0bS“Marek   Vec        d;
1192789d8953SBarry Smith   PetscBool  flg;
1193b253ae0bS“Marek 
1194b253ae0bS“Marek   PetscFunctionBegin;
11959566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
119628b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1197b253ae0bS“Marek   if (ins == INSERT_VALUES) {
11989566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
11999566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12009566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12019566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12031baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1204b253ae0bS“Marek   } else {
12059566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12061baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12076464bf51SAlex Fikl   }
12083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12096464bf51SAlex Fikl }
12106464bf51SAlex Fikl 
1211d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1212d71ae5a4SJacob Faibussowitsch {
1213ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1214b24ad042SBarry Smith 
1215ef66eb69SBarry Smith   PetscFunctionBegin;
1216f4df32b1SMatthew Knepley   shell->vscale *= a;
12170c0fd78eSBarry Smith   shell->vshift *= a;
12181baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
121981c02519SBarry Smith   shell->axpy_vscale *= a;
12201baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122218be62a5SSatish Balay }
12238fe8eb27SJed Brown 
1224d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1225d71ae5a4SJacob Faibussowitsch {
12268fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12278fe8eb27SJed Brown 
12288fe8eb27SJed Brown   PetscFunctionBegin;
12298fe8eb27SJed Brown   if (left) {
12300c0fd78eSBarry Smith     if (!shell->left) {
12319566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12329566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12330c0fd78eSBarry Smith     } else {
12349566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
123518be62a5SSatish Balay     }
12361baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1237ef66eb69SBarry Smith   }
12388fe8eb27SJed Brown   if (right) {
12390c0fd78eSBarry Smith     if (!shell->right) {
12409566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
12419566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
12420c0fd78eSBarry Smith     } else {
12439566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
12448fe8eb27SJed Brown     }
124545960306SStefano Zampini     if (shell->zrows) {
124648a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
12479566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
12489566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12499566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12509566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
125145960306SStefano Zampini     }
12528fe8eb27SJed Brown   }
12531baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
12543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1255ef66eb69SBarry Smith }
1256ef66eb69SBarry Smith 
1257d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1258d71ae5a4SJacob Faibussowitsch {
1259ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1260ef66eb69SBarry Smith 
1261ef66eb69SBarry Smith   PetscFunctionBegin;
12628fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1263ef66eb69SBarry Smith     shell->vshift      = 0.0;
1264ef66eb69SBarry Smith     shell->vscale      = 1.0;
1265ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1266ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
12679566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
12689566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
12699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
12709566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
12719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
12729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
12739566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
12749566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
12759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
12769566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1277ef66eb69SBarry Smith   }
12783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1279ef66eb69SBarry Smith }
1280ef66eb69SBarry Smith 
1281d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1282d71ae5a4SJacob Faibussowitsch {
12833b49f96aSBarry Smith   PetscFunctionBegin;
12843b49f96aSBarry Smith   *missing = PETSC_FALSE;
12853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12863b49f96aSBarry Smith }
12873b49f96aSBarry Smith 
1288d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1289d71ae5a4SJacob Faibussowitsch {
12909f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
12919f137db4SBarry Smith 
12929f137db4SBarry Smith   PetscFunctionBegin;
1293ef5c7bd2SStefano Zampini   if (X == Y) {
12949566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
12953ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1296ef5c7bd2SStefano Zampini   }
1297ef5c7bd2SStefano Zampini   if (!shell->axpy) {
12989566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
12999f137db4SBarry Smith     shell->axpy_vscale = a;
13009566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1301ef5c7bd2SStefano Zampini   } else {
13029566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1303ef5c7bd2SStefano Zampini   }
13043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13059f137db4SBarry Smith }
13069f137db4SBarry Smith 
1307f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1308f4259b30SLisandro Dalcin                                        NULL,
1309f4259b30SLisandro Dalcin                                        NULL,
1310f4259b30SLisandro Dalcin                                        NULL,
13110c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1312f4259b30SLisandro Dalcin                                        NULL,
13130c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1314f4259b30SLisandro Dalcin                                        NULL,
1315f4259b30SLisandro Dalcin                                        NULL,
1316f4259b30SLisandro Dalcin                                        NULL,
1317f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1318f4259b30SLisandro Dalcin                                        NULL,
1319f4259b30SLisandro Dalcin                                        NULL,
1320f4259b30SLisandro Dalcin                                        NULL,
1321f4259b30SLisandro Dalcin                                        NULL,
1322f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1323f4259b30SLisandro Dalcin                                        NULL,
1324f4259b30SLisandro Dalcin                                        NULL,
13258fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1326f4259b30SLisandro Dalcin                                        NULL,
1327f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1328ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1329f4259b30SLisandro Dalcin                                        NULL,
1330f4259b30SLisandro Dalcin                                        NULL,
133145960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1332f4259b30SLisandro Dalcin                                        NULL,
1333f4259b30SLisandro Dalcin                                        NULL,
1334f4259b30SLisandro Dalcin                                        NULL,
1335f4259b30SLisandro Dalcin                                        NULL,
1336f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1337f4259b30SLisandro Dalcin                                        NULL,
1338f4259b30SLisandro Dalcin                                        NULL,
1339f4259b30SLisandro Dalcin                                        NULL,
1340f4259b30SLisandro Dalcin                                        NULL,
1341cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1342f4259b30SLisandro Dalcin                                        NULL,
1343f4259b30SLisandro Dalcin                                        NULL,
1344f4259b30SLisandro Dalcin                                        NULL,
1345f4259b30SLisandro Dalcin                                        NULL,
13469f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1347f4259b30SLisandro Dalcin                                        NULL,
1348f4259b30SLisandro Dalcin                                        NULL,
1349f4259b30SLisandro Dalcin                                        NULL,
1350cb8c8a77SBarry Smith                                        MatCopy_Shell,
1351f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1352ef66eb69SBarry Smith                                        MatScale_Shell,
1353ef66eb69SBarry Smith                                        MatShift_Shell,
13546464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
135545960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1356f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1357f4259b30SLisandro Dalcin                                        NULL,
1358f4259b30SLisandro Dalcin                                        NULL,
1359f4259b30SLisandro Dalcin                                        NULL,
1360f4259b30SLisandro Dalcin                                        NULL,
1361f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1362f4259b30SLisandro Dalcin                                        NULL,
1363f4259b30SLisandro Dalcin                                        NULL,
1364f4259b30SLisandro Dalcin                                        NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1367b9b97703SBarry Smith                                        MatDestroy_Shell,
1368f4259b30SLisandro Dalcin                                        NULL,
1369251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1370f4259b30SLisandro Dalcin                                        NULL,
1371f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                        NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
1376f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1377f4259b30SLisandro Dalcin                                        NULL,
1378c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1379f4259b30SLisandro Dalcin                                        NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1382f4259b30SLisandro Dalcin                                        NULL,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                        NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1387f4259b30SLisandro Dalcin                                        NULL,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                        NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        NULL,
1399f4259b30SLisandro Dalcin                                        NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        NULL,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
1414f4259b30SLisandro Dalcin                                        NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
14203b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1421f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424f4259b30SLisandro Dalcin                                        NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                        NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448d70f29a3SPierre Jolivet                                        NULL,
1449d70f29a3SPierre Jolivet                                        NULL,
1450d70f29a3SPierre Jolivet                                        NULL,
1451d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1452d70f29a3SPierre Jolivet                                        NULL,
1453d70f29a3SPierre Jolivet                                        NULL,
145499a7f59eSMark Adams                                        NULL,
145599a7f59eSMark Adams                                        NULL,
14567fb60732SBarry Smith                                        NULL,
1457dec0b466SHong Zhang                                        /*150*/ NULL,
1458dec0b466SHong Zhang                                        NULL};
1459273d9f13SBarry Smith 
1460d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1461d71ae5a4SJacob Faibussowitsch {
1462789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1463789d8953SBarry Smith 
1464789d8953SBarry Smith   PetscFunctionBegin;
1465800f99ffSJeremy L Thompson   if (ctx) {
1466800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1467800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1468800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1469800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1470800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1471800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1472800f99ffSJeremy L Thompson   } else {
1473800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1474800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1475800f99ffSJeremy L Thompson   }
1476800f99ffSJeremy L Thompson 
14773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1478800f99ffSJeremy L Thompson }
1479800f99ffSJeremy L Thompson 
1480d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1481d71ae5a4SJacob Faibussowitsch {
1482800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1483800f99ffSJeremy L Thompson 
1484800f99ffSJeremy L Thompson   PetscFunctionBegin;
1485800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
14863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1487789d8953SBarry Smith }
1488789d8953SBarry Smith 
1489d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1490d71ae5a4SJacob Faibussowitsch {
1491db77db73SJeremy L Thompson   PetscFunctionBegin;
14929566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
14939566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
14943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1495db77db73SJeremy L Thompson }
1496db77db73SJeremy L Thompson 
1497d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1498d71ae5a4SJacob Faibussowitsch {
1499789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1500789d8953SBarry Smith 
1501789d8953SBarry Smith   PetscFunctionBegin;
1502789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1503789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1504789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1505789d8953SBarry Smith   A->ops->scale              = NULL;
1506789d8953SBarry Smith   A->ops->shift              = NULL;
1507789d8953SBarry Smith   A->ops->axpy               = NULL;
15083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1509789d8953SBarry Smith }
1510789d8953SBarry Smith 
1511d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1512d71ae5a4SJacob Faibussowitsch {
1513feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1514789d8953SBarry Smith 
1515789d8953SBarry Smith   PetscFunctionBegin;
1516789d8953SBarry Smith   switch (op) {
1517d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1518d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1519d71ae5a4SJacob Faibussowitsch     break;
1520789d8953SBarry Smith   case MATOP_VIEW:
1521ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1522789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1523789d8953SBarry Smith     break;
1524d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1525d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1526d71ae5a4SJacob Faibussowitsch     break;
1527789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1528789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1529789d8953SBarry Smith   case MATOP_SHIFT:
1530789d8953SBarry Smith   case MATOP_SCALE:
1531789d8953SBarry Smith   case MATOP_AXPY:
1532789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1533789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
153428b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1535789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1536789d8953SBarry Smith     break;
1537789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1538789d8953SBarry Smith     if (shell->managescalingshifts) {
1539789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1540789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1541789d8953SBarry Smith     } else {
1542789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1543789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1544789d8953SBarry Smith     }
1545789d8953SBarry Smith     break;
1546789d8953SBarry Smith   case MATOP_MULT:
1547789d8953SBarry Smith     if (shell->managescalingshifts) {
1548789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1549789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1550789d8953SBarry Smith     } else {
1551789d8953SBarry Smith       shell->ops->mult = NULL;
1552789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1553789d8953SBarry Smith     }
1554789d8953SBarry Smith     break;
1555789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1556789d8953SBarry Smith     if (shell->managescalingshifts) {
1557789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1558789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1559789d8953SBarry Smith     } else {
1560789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1561789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1562789d8953SBarry Smith     }
1563789d8953SBarry Smith     break;
1564d71ae5a4SJacob Faibussowitsch   default:
1565d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1566d71ae5a4SJacob Faibussowitsch     break;
1567789d8953SBarry Smith   }
15683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1569789d8953SBarry Smith }
1570789d8953SBarry Smith 
1571d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1572d71ae5a4SJacob Faibussowitsch {
1573789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1574789d8953SBarry Smith 
1575789d8953SBarry Smith   PetscFunctionBegin;
1576789d8953SBarry Smith   switch (op) {
1577d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1578d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1579d71ae5a4SJacob Faibussowitsch     break;
1580d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1581d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1582d71ae5a4SJacob Faibussowitsch     break;
1583d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1584d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1585d71ae5a4SJacob Faibussowitsch     break;
1586789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1587789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1588789d8953SBarry Smith   case MATOP_SHIFT:
1589789d8953SBarry Smith   case MATOP_SCALE:
1590789d8953SBarry Smith   case MATOP_AXPY:
1591789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1592d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1593d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1594d71ae5a4SJacob Faibussowitsch     break;
1595789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
15969371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
15979371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1598789d8953SBarry Smith     break;
1599789d8953SBarry Smith   case MATOP_MULT:
16009371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
16019371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1602789d8953SBarry Smith     break;
1603789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
16049371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
16059371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1606789d8953SBarry Smith     break;
1607d71ae5a4SJacob Faibussowitsch   default:
1608d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1609789d8953SBarry Smith   }
16103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1611789d8953SBarry Smith }
1612789d8953SBarry Smith 
16130bad9183SKris Buschelman /*MC
1614fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16150bad9183SKris Buschelman 
16160bad9183SKris Buschelman   Level: advanced
16170bad9183SKris Buschelman 
161811a5261eSBarry Smith .seealso: `Mat`, `MatCreateShell()`
16190bad9183SKris Buschelman M*/
16200bad9183SKris Buschelman 
1621d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1622d71ae5a4SJacob Faibussowitsch {
1623273d9f13SBarry Smith   Mat_Shell *b;
1624273d9f13SBarry Smith 
1625273d9f13SBarry Smith   PetscFunctionBegin;
16269566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
1627273d9f13SBarry Smith 
16284dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1629273d9f13SBarry Smith   A->data = (void *)b;
1630273d9f13SBarry Smith 
1631800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1632ef66eb69SBarry Smith   b->vshift              = 0.0;
1633ef66eb69SBarry Smith   b->vscale              = 1.0;
16340c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1635273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1636210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
16372205254eSKarl Rupp 
16389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
16399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1640800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
16419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
16429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
16439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
16449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
16459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
16469566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
16473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1648273d9f13SBarry Smith }
1649e51e0e81SBarry Smith 
16504b828684SBarry Smith /*@C
165111a5261eSBarry Smith    MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1652ff756334SLois Curfman McInnes    private data storage format.
1653e51e0e81SBarry Smith 
1654d083f849SBarry Smith   Collective
1655c7fcc2eaSBarry Smith 
1656e51e0e81SBarry Smith    Input Parameters:
1657c7fcc2eaSBarry Smith +  comm - MPI communicator
1658c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
1659c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
1660c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
1661c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
1662c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
1663e51e0e81SBarry Smith 
1664ff756334SLois Curfman McInnes    Output Parameter:
166544cd7ae7SLois Curfman McInnes .  A - the matrix
1666e51e0e81SBarry Smith 
1667ff2fd236SBarry Smith    Level: advanced
1668ff2fd236SBarry Smith 
1669f39d1f56SLois Curfman McInnes   Usage:
1670*27430b45SBarry Smith .vb
1671*27430b45SBarry Smith     extern PetscErrorCode mult(Mat,Vec,Vec);
1672*27430b45SBarry Smith     MatCreateShell(comm,m,n,M,N,ctx,&mat);
1673*27430b45SBarry Smith     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1674*27430b45SBarry Smith     [ Use matrix for operations that have been set ]
1675*27430b45SBarry Smith     MatDestroy(mat);
1676*27430b45SBarry Smith .ve
1677f39d1f56SLois Curfman McInnes 
1678ff756334SLois Curfman McInnes    Notes:
1679ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
168011a5261eSBarry Smith    with `KSP` (such as, for use with matrix-free methods). You should not
1681ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
1682e51e0e81SBarry Smith 
1683f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
1684f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
1685645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
168611a5261eSBarry Smith    products using `MatMult`(A,x,y) the user should set the number
1687645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
1688645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
1689645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
1690645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
1691645985a0SLois Curfman McInnes    For example,
1692f39d1f56SLois Curfman McInnes 
1693*27430b45SBarry Smith .vb
1694*27430b45SBarry Smith      Vec x, y
1695*27430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
1696*27430b45SBarry Smith      Mat A
1697*27430b45SBarry Smith 
1698*27430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1699*27430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1700*27430b45SBarry Smith      VecGetLocalSize(y,&m);
1701*27430b45SBarry Smith      VecGetLocalSize(x,&n);
1702*27430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
1703*27430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1704*27430b45SBarry Smith      MatMult(A,x,y);
1705*27430b45SBarry Smith      MatDestroy(&A);
1706*27430b45SBarry Smith      VecDestroy(&y);
1707*27430b45SBarry Smith      VecDestroy(&x);
1708*27430b45SBarry Smith .ve
1709e51e0e81SBarry Smith 
171011a5261eSBarry Smith    `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` internally, so these
171111a5261eSBarry Smith    operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
17129b53d762SBarry Smith 
17130c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
17140c0fd78eSBarry Smith 
1715*27430b45SBarry Smith     Developer Notes:
171695452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
17170c0fd78eSBarry Smith 
17180c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17190c0fd78eSBarry Smith 
17200c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
17210c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17220c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
17230c0fd78eSBarry Smith 
17240c0fd78eSBarry Smith           A is the user provided function.
17250c0fd78eSBarry Smith 
1726*27430b45SBarry Smith    `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1727c5dec841SPierre Jolivet    for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
172811a5261eSBarry Smith    an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
172911a5261eSBarry Smith    each time the `MATSHELL` matrix has changed.
1730ad2f5c3fSBarry Smith 
173111a5261eSBarry Smith    Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1732b77ba244SStefano Zampini 
173311a5261eSBarry Smith    Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
173411a5261eSBarry Smith    with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1735ad2f5c3fSBarry Smith 
173611a5261eSBarry Smith    Fortran Note:
173711a5261eSBarry Smith     To use this from Fortran with a ctx you must write an interface definition for this
173811a5261eSBarry Smith     function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
173911a5261eSBarry Smith     in as the ctx argument.
174011a5261eSBarry Smith 
174111a5261eSBarry Smith .seealso: `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MATSHELL`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1742e51e0e81SBarry Smith @*/
1743d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1744d71ae5a4SJacob Faibussowitsch {
17453a40ed3dSBarry Smith   PetscFunctionBegin;
17469566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
17479566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
17489566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
17499566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
17509566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
17513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1752c7fcc2eaSBarry Smith }
1753c7fcc2eaSBarry Smith 
1754c6866cfdSSatish Balay /*@
175511a5261eSBarry Smith     MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1756c7fcc2eaSBarry Smith 
1757c3339decSBarry Smith    Logically Collective
1758c7fcc2eaSBarry Smith 
1759273d9f13SBarry Smith     Input Parameters:
176011a5261eSBarry Smith +   mat - the `MATSHELL` shell matrix
1761273d9f13SBarry Smith -   ctx - the context
1762273d9f13SBarry Smith 
1763273d9f13SBarry Smith    Level: advanced
1764273d9f13SBarry Smith 
176511a5261eSBarry Smith    Fortran Note:
1766*27430b45SBarry Smith     You must write a Fortran interface definition for this
1767daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1768273d9f13SBarry Smith 
176911a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
17700bc0a719SBarry Smith @*/
1771d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1772d71ae5a4SJacob Faibussowitsch {
1773273d9f13SBarry Smith   PetscFunctionBegin;
17740700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1775cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
17763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1777e51e0e81SBarry Smith }
1778e51e0e81SBarry Smith 
1779800f99ffSJeremy L Thompson /*@
178011a5261eSBarry Smith     MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1781800f99ffSJeremy L Thompson 
1782c3339decSBarry Smith    Logically Collective
1783800f99ffSJeremy L Thompson 
1784800f99ffSJeremy L Thompson     Input Parameters:
1785800f99ffSJeremy L Thompson +   mat - the shell matrix
1786800f99ffSJeremy L Thompson -   f - the context destroy function
1787800f99ffSJeremy L Thompson 
1788*27430b45SBarry Smith    Level: advanced
1789*27430b45SBarry Smith 
1790800f99ffSJeremy L Thompson     Note:
1791800f99ffSJeremy L Thompson     If the `MatShell` is never duplicated, the behavior of this function is equivalent
179211a5261eSBarry Smith     to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1793800f99ffSJeremy L Thompson     ensures proper reference counting for the user provided context data in the case that
179411a5261eSBarry Smith     the `MATSHELL` is duplicated.
1795800f99ffSJeremy L Thompson 
179611a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1797800f99ffSJeremy L Thompson @*/
1798d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1799d71ae5a4SJacob Faibussowitsch {
1800800f99ffSJeremy L Thompson   PetscFunctionBegin;
1801800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1802800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
18033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1804800f99ffSJeremy L Thompson }
1805800f99ffSJeremy L Thompson 
1806db77db73SJeremy L Thompson /*@C
180711a5261eSBarry Smith  MatShellSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1808db77db73SJeremy L Thompson 
1809db77db73SJeremy L Thompson  Logically collective
1810db77db73SJeremy L Thompson 
1811db77db73SJeremy L Thompson     Input Parameters:
181211a5261eSBarry Smith +   mat   - the `MATSHELL` shell matrix
1813db77db73SJeremy L Thompson -   vtype - type to use for creating vectors
1814db77db73SJeremy L Thompson 
1815db77db73SJeremy L Thompson  Level: advanced
1816db77db73SJeremy L Thompson 
181711a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateVecs()`
1818db77db73SJeremy L Thompson @*/
1819d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1820d71ae5a4SJacob Faibussowitsch {
1821db77db73SJeremy L Thompson   PetscFunctionBegin;
1822cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
18233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1824db77db73SJeremy L Thompson }
1825db77db73SJeremy L Thompson 
18260c0fd78eSBarry Smith /*@
182711a5261eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
182811a5261eSBarry Smith           after `MatCreateShell()`
18290c0fd78eSBarry Smith 
1830*27430b45SBarry Smith    Logically Collective
18310c0fd78eSBarry Smith 
18320c0fd78eSBarry Smith     Input Parameter:
183311a5261eSBarry Smith .   mat - the `MATSHELL` shell matrix
18340c0fd78eSBarry Smith 
18350c0fd78eSBarry Smith   Level: advanced
18360c0fd78eSBarry Smith 
183711a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
18380c0fd78eSBarry Smith @*/
1839d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1840d71ae5a4SJacob Faibussowitsch {
18410c0fd78eSBarry Smith   PetscFunctionBegin;
18420c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1843cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
18443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18450c0fd78eSBarry Smith }
18460c0fd78eSBarry Smith 
1847c16cb8f2SBarry Smith /*@C
184811a5261eSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
1849f3b1f45cSBarry Smith 
1850cf53795eSBarry Smith    Logically Collective; No Fortran Support
1851f3b1f45cSBarry Smith 
1852f3b1f45cSBarry Smith     Input Parameters:
185311a5261eSBarry Smith +   mat - the `MATSHELL` shell matrix
1854f3b1f45cSBarry Smith .   f - the function
185511a5261eSBarry Smith .   base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1856f3b1f45cSBarry Smith -   ctx - an optional context for the function
1857f3b1f45cSBarry Smith 
1858f3b1f45cSBarry Smith    Output Parameter:
185911a5261eSBarry Smith .   flg - `PETSC_TRUE` if the multiply is likely correct
1860f3b1f45cSBarry Smith 
18613c7db156SBarry Smith    Options Database Key:
1862f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1863f3b1f45cSBarry Smith 
1864f3b1f45cSBarry Smith    Level: advanced
1865f3b1f45cSBarry Smith 
186611a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1867f3b1f45cSBarry Smith @*/
1868d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1869d71ae5a4SJacob Faibussowitsch {
1870f3b1f45cSBarry Smith   PetscInt  m, n;
1871f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1872f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
187374e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1874f3b1f45cSBarry Smith 
1875f3b1f45cSBarry Smith   PetscFunctionBegin;
1876f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
18779566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
18789566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
18799566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
18809566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
18819566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
1882f3b1f45cSBarry Smith 
18839566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
18849566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
1885f3b1f45cSBarry Smith 
18869566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
18879566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
18889566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
18899566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1890f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1891f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1892f3b1f45cSBarry Smith     if (v) {
18939566063dSJacob 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)));
18949566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
18959566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
18969566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
1897f3b1f45cSBarry Smith     }
1898f3b1f45cSBarry Smith   } else if (v) {
18999566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix free multiple appear to produce the same results\n"));
1900f3b1f45cSBarry Smith   }
1901f3b1f45cSBarry Smith   if (flg) *flg = flag;
19029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19039566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1907f3b1f45cSBarry Smith }
1908f3b1f45cSBarry Smith 
1909f3b1f45cSBarry Smith /*@C
191011a5261eSBarry Smith     MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
1911f3b1f45cSBarry Smith 
1912cf53795eSBarry Smith    Logically Collective; No Fortran Support
1913f3b1f45cSBarry Smith 
1914f3b1f45cSBarry Smith     Input Parameters:
191511a5261eSBarry Smith +   mat - the `MATSHELL` shell matrix
1916f3b1f45cSBarry Smith .   f - the function
191711a5261eSBarry Smith .   base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1918f3b1f45cSBarry Smith -   ctx - an optional context for the function
1919f3b1f45cSBarry Smith 
1920f3b1f45cSBarry Smith    Output Parameter:
192111a5261eSBarry Smith .   flg - `PETSC_TRUE` if the multiply is likely correct
1922f3b1f45cSBarry Smith 
19233c7db156SBarry Smith    Options Database Key:
1924f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1925f3b1f45cSBarry Smith 
1926f3b1f45cSBarry Smith    Level: advanced
1927f3b1f45cSBarry Smith 
192811a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1929f3b1f45cSBarry Smith @*/
1930d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1931d71ae5a4SJacob Faibussowitsch {
1932f3b1f45cSBarry Smith   Vec       x, y, z;
1933f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
1934f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1935f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
193674e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1937f3b1f45cSBarry Smith 
1938f3b1f45cSBarry Smith   PetscFunctionBegin;
1939f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
19409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
19419566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
19429566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
19439566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
19449566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
19459566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
19469566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
19479566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
19489566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
19499566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
19509566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
1951f3b1f45cSBarry Smith 
19529566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
19539566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
19549566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
19559566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1956f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1957f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1958f3b1f45cSBarry Smith     if (v) {
19599566063dSJacob 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)));
19609566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19619566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19629566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
1963f3b1f45cSBarry Smith     }
1964f3b1f45cSBarry Smith   } else if (v) {
19659566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix free multiple appear to produce the same results\n"));
1966f3b1f45cSBarry Smith   }
1967f3b1f45cSBarry Smith   if (flg) *flg = flag;
19689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
19739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
19749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
19753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1976f3b1f45cSBarry Smith }
1977f3b1f45cSBarry Smith 
1978f3b1f45cSBarry Smith /*@C
197911a5261eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
1980e51e0e81SBarry Smith 
1981c3339decSBarry Smith    Logically Collective
1982fee21e36SBarry Smith 
1983c7fcc2eaSBarry Smith     Input Parameters:
198411a5261eSBarry Smith +   mat - the `MATSHELL` shell matrix
1985c7fcc2eaSBarry Smith .   op - the name of the operation
1986789d8953SBarry Smith -   g - the function that provides the operation.
1987c7fcc2eaSBarry Smith 
198815091d37SBarry Smith    Level: advanced
198915091d37SBarry Smith 
1990fae171e0SBarry Smith     Usage:
1991c3339decSBarry Smith .vb
1992c3339decSBarry Smith       extern PetscErrorCode usermult(Mat,Vec,Vec);
1993c3339decSBarry Smith       MatCreateShell(comm,m,n,M,N,ctx,&A);
1994c3339decSBarry Smith       MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
1995c3339decSBarry Smith .ve
19960b627109SLois Curfman McInnes 
1997a62d957aSLois Curfman McInnes     Notes:
1998e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
19991c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
2000a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
200111a5261eSBarry Smith     user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2002a62d957aSLois Curfman McInnes 
200311a5261eSBarry Smith     All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2004deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
2005deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
2006deebb3c3SLois Curfman McInnes     routines, e.g.,
2007a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2008a62d957aSLois Curfman McInnes 
20094aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
20104aa34b0aSBarry Smith     nonzero on failure.
20114aa34b0aSBarry Smith 
2012a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
201311a5261eSBarry Smith     `MatShellGetContext()` to obtain the user-defined context that was
201411a5261eSBarry Smith     set by `MatCreateShell()`.
2015a62d957aSLois Curfman McInnes 
201611a5261eSBarry Smith     Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) use `MatShellSetMatProductOperation()`
2017b77ba244SStefano Zampini 
201811a5261eSBarry Smith     Fortran Note:
201911a5261eSBarry Smith     For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2020c4762a1bSJed Brown        generate a matrix. See src/mat/tests/ex120f.F
2021501d9185SBarry Smith 
202211a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2023e51e0e81SBarry Smith @*/
2024d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2025d71ae5a4SJacob Faibussowitsch {
20263a40ed3dSBarry Smith   PetscFunctionBegin;
20270700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2028cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
20293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2030e51e0e81SBarry Smith }
2031f0479e8cSBarry Smith 
2032d4bb536fSBarry Smith /*@C
203311a5261eSBarry Smith     MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2034d4bb536fSBarry Smith 
2035c7fcc2eaSBarry Smith     Not Collective
2036c7fcc2eaSBarry Smith 
2037d4bb536fSBarry Smith     Input Parameters:
203811a5261eSBarry Smith +   mat - the `MATSHELL` shell matrix
2039c7fcc2eaSBarry Smith -   op - the name of the operation
2040d4bb536fSBarry Smith 
2041d4bb536fSBarry Smith     Output Parameter:
2042789d8953SBarry Smith .   g - the function that provides the operation.
2043d4bb536fSBarry Smith 
204415091d37SBarry Smith     Level: advanced
204515091d37SBarry Smith 
2046*27430b45SBarry Smith     Notes:
2047e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
2048d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
2049d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
205011a5261eSBarry Smith     user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2051d4bb536fSBarry Smith 
2052d4bb536fSBarry Smith     All user-provided functions have the same calling
2053d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
2054d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
2055d4bb536fSBarry Smith     routines, e.g.,
2056d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2057d4bb536fSBarry Smith 
2058d4bb536fSBarry Smith     Within each user-defined routine, the user should call
205911a5261eSBarry Smith     `MatShellGetContext()` to obtain the user-defined context that was
206011a5261eSBarry Smith     set by `MatCreateShell()`.
2061d4bb536fSBarry Smith 
206211a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2063d4bb536fSBarry Smith @*/
2064d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2065d71ae5a4SJacob Faibussowitsch {
20663a40ed3dSBarry Smith   PetscFunctionBegin;
20670700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2068cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
20693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2070d4bb536fSBarry Smith }
2071b77ba244SStefano Zampini 
2072b77ba244SStefano Zampini /*@
207311a5261eSBarry Smith     MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2074b77ba244SStefano Zampini 
2075b77ba244SStefano Zampini     Input Parameter:
2076b77ba244SStefano Zampini .   mat - the matrix
2077b77ba244SStefano Zampini 
2078b77ba244SStefano Zampini     Output Parameter:
2079b77ba244SStefano Zampini .   flg - the boolean value
2080b77ba244SStefano Zampini 
2081b77ba244SStefano Zampini     Level: developer
2082b77ba244SStefano Zampini 
208311a5261eSBarry Smith     Developer Note:
2084013e2dc7SBarry Smith     In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc)
2085b77ba244SStefano Zampini 
2086013e2dc7SBarry Smith .seealso: `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2087b77ba244SStefano Zampini @*/
2088d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2089d71ae5a4SJacob Faibussowitsch {
2090b77ba244SStefano Zampini   PetscFunctionBegin;
2091b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2092dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(flg, 2);
2093b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
20943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2095b77ba244SStefano Zampini }
2096