xref: /petsc/src/mat/impls/shell/shell.c (revision 2920cce0f08e88ce102428b9df84f61867de9dc8)
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 
257fe59aa6dSJacob Faibussowitsch   Fortran Notes:
25827430b45SBarry 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 
2611cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `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;
704eae3dc7dSJacob Faibussowitsch   PetscBool               flg = PETSC_FALSE;
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 
84727430b45SBarry 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
8522ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
853b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8542ef1f0ffSBarry Smith . 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
8562ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
857b77ba244SStefano Zampini 
858b77ba244SStefano Zampini   Level: advanced
859b77ba244SStefano Zampini 
860*2920cce0SJacob Faibussowitsch   Example 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*);
865*2920cce0SJacob Faibussowitsch 
866cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
867*2920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
868*2920cce0SJacob Faibussowitsch     A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE
869*2920cce0SJacob Faibussowitsch   );
870*2920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
871*2920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
872cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
873cf53795eSBarry Smith   MatProductSetFromOptions(C);
874*2920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
875*2920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
876*2920cce0SJacob Faibussowitsch   // use C = A * B
877cf53795eSBarry Smith .ve
878b77ba244SStefano Zampini 
879b77ba244SStefano Zampini   Notes:
880cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
88111a5261eSBarry Smith 
8822ef1f0ffSBarry 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`.
88311a5261eSBarry Smith 
884b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
885b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
886b77ba244SStefano Zampini   It is allowed to specify the same callbacks for different Btype matrix types.
88727430b45SBarry Smith   The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
888b77ba244SStefano Zampini 
8891cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
890b77ba244SStefano Zampini @*/
891d71ae5a4SJacob 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)
892d71ae5a4SJacob Faibussowitsch {
893b77ba244SStefano Zampini   PetscFunctionBegin;
894b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
895b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
89608401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
89728b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
898dadcf809SJacob Faibussowitsch   PetscValidCharPointer(Btype, 6);
899dadcf809SJacob Faibussowitsch   if (Ctype) PetscValidCharPointer(Ctype, 7);
900cac4c232SBarry 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));
9013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
902b77ba244SStefano Zampini }
903b77ba244SStefano Zampini 
904d71ae5a4SJacob 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)
905d71ae5a4SJacob Faibussowitsch {
906b77ba244SStefano Zampini   PetscBool   flg;
907b77ba244SStefano Zampini   char        composedname[256];
908b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
909b77ba244SStefano Zampini   PetscMPIInt size;
910b77ba244SStefano Zampini 
911b77ba244SStefano Zampini   PetscFunctionBegin;
912b77ba244SStefano Zampini   PetscValidType(A, 1);
913b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9149566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
915b77ba244SStefano Zampini     if (flg) break;
916b77ba244SStefano Zampini     Bnames = Bnames->next;
917b77ba244SStefano Zampini   }
918b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9199566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
920b77ba244SStefano Zampini     if (flg) break;
921b77ba244SStefano Zampini     Cnames = Cnames->next;
922b77ba244SStefano Zampini   }
9239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
924b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
925b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9269566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9279566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
929e51e0e81SBarry Smith }
930e51e0e81SBarry Smith 
931d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
932d71ae5a4SJacob Faibussowitsch {
93328f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
934cb8c8a77SBarry Smith   PetscBool               matflg;
935b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9367fabda3fSAlex Fikl 
9377fabda3fSAlex Fikl   PetscFunctionBegin;
9389566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
93928b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9407fabda3fSAlex Fikl 
941aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
942aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9437fabda3fSAlex Fikl 
9441baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9457fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9467fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9470c0fd78eSBarry Smith   if (shellA->dshift) {
94848a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9499566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9507fabda3fSAlex Fikl   } else {
9519566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9527fabda3fSAlex Fikl   }
9530c0fd78eSBarry Smith   if (shellA->left) {
95448a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9559566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9567fabda3fSAlex Fikl   } else {
9579566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9587fabda3fSAlex Fikl   }
9590c0fd78eSBarry Smith   if (shellA->right) {
96048a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9619566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9627fabda3fSAlex Fikl   } else {
9639566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9647fabda3fSAlex Fikl   }
9659566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
966ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
967ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
96840e381c3SBarry Smith   if (shellA->axpy) {
9699566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
97040e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
97140e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
972ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
97340e381c3SBarry Smith   }
97445960306SStefano Zampini   if (shellA->zrows) {
9759566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
97648a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9779566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9789566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9799566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9809566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9819566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
98245960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
98345960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
98445960306SStefano Zampini   }
985b77ba244SStefano Zampini 
986b77ba244SStefano Zampini   matmatA = shellA->matmat;
987b77ba244SStefano Zampini   if (matmatA) {
988b77ba244SStefano Zampini     while (matmatA->next) {
9899566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
990b77ba244SStefano Zampini       matmatA = matmatA->next;
991b77ba244SStefano Zampini     }
992b77ba244SStefano Zampini   }
9933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9947fabda3fSAlex Fikl }
9957fabda3fSAlex Fikl 
996d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
997d71ae5a4SJacob Faibussowitsch {
998cb8c8a77SBarry Smith   PetscFunctionBegin;
999800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
1000800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
1001800f99ffSJeremy L Thompson   PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
10029566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name));
100348a46eb9SPierre Jolivet   if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
10043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1005cb8c8a77SBarry Smith }
1006cb8c8a77SBarry Smith 
1007d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
1008d71ae5a4SJacob Faibussowitsch {
1009ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
101025578ef6SJed Brown   Vec              xx;
1011e3f487b0SBarry Smith   PetscObjectState instate, outstate;
1012ef66eb69SBarry Smith 
1013ef66eb69SBarry Smith   PetscFunctionBegin;
10149566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
10159566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
10169566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10179566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
10189566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1019e3f487b0SBarry Smith   if (instate == outstate) {
1020e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10219566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1022e3f487b0SBarry Smith   }
10239566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10249566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10259566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10269f137db4SBarry Smith 
10279f137db4SBarry Smith   if (shell->axpy) {
1028ef5c7bd2SStefano Zampini     Mat              X;
1029ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1030ef5c7bd2SStefano Zampini 
10319566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10329566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
103308401ef6SPierre 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,...)");
1034b77ba244SStefano Zampini 
10359566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10369566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10379566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10389566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10399f137db4SBarry Smith   }
10403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1041ef66eb69SBarry Smith }
1042ef66eb69SBarry Smith 
1043d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1044d71ae5a4SJacob Faibussowitsch {
10455edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10465edf6516SJed Brown 
10475edf6516SJed Brown   PetscFunctionBegin;
10485edf6516SJed Brown   if (y == z) {
10499566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10509566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10519566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10525edf6516SJed Brown   } else {
10539566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10549566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10555edf6516SJed Brown   }
10563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10575edf6516SJed Brown }
10585edf6516SJed Brown 
1059d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1060d71ae5a4SJacob Faibussowitsch {
106118be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
106225578ef6SJed Brown   Vec              xx;
1063e3f487b0SBarry Smith   PetscObjectState instate, outstate;
106418be62a5SSatish Balay 
106518be62a5SSatish Balay   PetscFunctionBegin;
10669566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
10679566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleLeft(A, xx, &xx));
10689566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10699566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10709566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1071e3f487b0SBarry Smith   if (instate == outstate) {
1072e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10739566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1074e3f487b0SBarry Smith   }
10759566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10769566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleRight(A, y));
10779566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1078350ec83bSStefano Zampini 
1079350ec83bSStefano Zampini   if (shell->axpy) {
1080ef5c7bd2SStefano Zampini     Mat              X;
1081ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1082ef5c7bd2SStefano Zampini 
10839566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10849566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
108508401ef6SPierre 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,...)");
10869566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10879566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10889566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10899566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1090350ec83bSStefano Zampini   }
10913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
109218be62a5SSatish Balay }
109318be62a5SSatish Balay 
1094d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1095d71ae5a4SJacob Faibussowitsch {
10965edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10975edf6516SJed Brown 
10985edf6516SJed Brown   PetscFunctionBegin;
10995edf6516SJed Brown   if (y == z) {
11009566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11019566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11029566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11035edf6516SJed Brown   } else {
11049566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11059566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11065edf6516SJed Brown   }
11073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11085edf6516SJed Brown }
11095edf6516SJed Brown 
11100c0fd78eSBarry Smith /*
11110c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11120c0fd78eSBarry Smith */
1113d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1114d71ae5a4SJacob Faibussowitsch {
111518be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
111618be62a5SSatish Balay 
111718be62a5SSatish Balay   PetscFunctionBegin;
11180c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11199566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1120305211d5SBarry 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,...)");
11219566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
11221baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
11239566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
11249566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
11259566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
112645960306SStefano Zampini   if (shell->zrows) {
11279566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
11289566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
112945960306SStefano Zampini   }
113081c02519SBarry Smith   if (shell->axpy) {
1131ef5c7bd2SStefano Zampini     Mat              X;
1132ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1133ef5c7bd2SStefano Zampini 
11349566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11359566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
113608401ef6SPierre 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,...)");
11379566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
11389566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
11399566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
114081c02519SBarry Smith   }
11413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114218be62a5SSatish Balay }
114318be62a5SSatish Balay 
1144d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1145d71ae5a4SJacob Faibussowitsch {
1146ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1147789d8953SBarry Smith   PetscBool  flg;
1148b24ad042SBarry Smith 
1149ef66eb69SBarry Smith   PetscFunctionBegin;
11509566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
115128b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
11520c0fd78eSBarry Smith   if (shell->left || shell->right) {
11538fe8eb27SJed Brown     if (!shell->dshift) {
11549566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11559566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
11560c0fd78eSBarry Smith     } else {
11579566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
11589566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
11599566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
11600c0fd78eSBarry Smith     }
11619566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
11629566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
11638fe8eb27SJed Brown   } else shell->vshift += a;
11641baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
11653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1166ef66eb69SBarry Smith }
1167ef66eb69SBarry Smith 
1168d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1169d71ae5a4SJacob Faibussowitsch {
11706464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
11716464bf51SAlex Fikl 
11726464bf51SAlex Fikl   PetscFunctionBegin;
11739566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
11740c0fd78eSBarry Smith   if (shell->left || shell->right) {
11759566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
11769f137db4SBarry Smith     if (shell->left && shell->right) {
11779566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11789566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
11799f137db4SBarry Smith     } else if (shell->left) {
11809566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11819f137db4SBarry Smith     } else {
11829566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
11839f137db4SBarry Smith     }
11849566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
11850c0fd78eSBarry Smith   } else {
11869566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1187b253ae0bS“Marek   }
11883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1189b253ae0bS“Marek }
1190b253ae0bS“Marek 
1191d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1192d71ae5a4SJacob Faibussowitsch {
119345960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1194b253ae0bS“Marek   Vec        d;
1195789d8953SBarry Smith   PetscBool  flg;
1196b253ae0bS“Marek 
1197b253ae0bS“Marek   PetscFunctionBegin;
11989566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
119928b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1200b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12019566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12029566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12039566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12049566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12059566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12061baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1207b253ae0bS“Marek   } else {
12089566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12091baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12106464bf51SAlex Fikl   }
12113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12126464bf51SAlex Fikl }
12136464bf51SAlex Fikl 
1214d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1215d71ae5a4SJacob Faibussowitsch {
1216ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1217b24ad042SBarry Smith 
1218ef66eb69SBarry Smith   PetscFunctionBegin;
1219f4df32b1SMatthew Knepley   shell->vscale *= a;
12200c0fd78eSBarry Smith   shell->vshift *= a;
12211baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
122281c02519SBarry Smith   shell->axpy_vscale *= a;
12231baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122518be62a5SSatish Balay }
12268fe8eb27SJed Brown 
1227d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1228d71ae5a4SJacob Faibussowitsch {
12298fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12308fe8eb27SJed Brown 
12318fe8eb27SJed Brown   PetscFunctionBegin;
12328fe8eb27SJed Brown   if (left) {
12330c0fd78eSBarry Smith     if (!shell->left) {
12349566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12359566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12360c0fd78eSBarry Smith     } else {
12379566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
123818be62a5SSatish Balay     }
12391baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1240ef66eb69SBarry Smith   }
12418fe8eb27SJed Brown   if (right) {
12420c0fd78eSBarry Smith     if (!shell->right) {
12439566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
12449566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
12450c0fd78eSBarry Smith     } else {
12469566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
12478fe8eb27SJed Brown     }
124845960306SStefano Zampini     if (shell->zrows) {
124948a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
12509566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
12519566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12529566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12539566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
125445960306SStefano Zampini     }
12558fe8eb27SJed Brown   }
12561baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
12573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1258ef66eb69SBarry Smith }
1259ef66eb69SBarry Smith 
1260d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1261d71ae5a4SJacob Faibussowitsch {
1262ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1263ef66eb69SBarry Smith 
1264ef66eb69SBarry Smith   PetscFunctionBegin;
12658fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1266ef66eb69SBarry Smith     shell->vshift      = 0.0;
1267ef66eb69SBarry Smith     shell->vscale      = 1.0;
1268ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1269ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
12709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
12719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
12729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
12739566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
12749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
12759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
12769566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
12779566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
12789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
12799566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1280ef66eb69SBarry Smith   }
12813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1282ef66eb69SBarry Smith }
1283ef66eb69SBarry Smith 
1284d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1285d71ae5a4SJacob Faibussowitsch {
12863b49f96aSBarry Smith   PetscFunctionBegin;
12873b49f96aSBarry Smith   *missing = PETSC_FALSE;
12883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12893b49f96aSBarry Smith }
12903b49f96aSBarry Smith 
1291d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1292d71ae5a4SJacob Faibussowitsch {
12939f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
12949f137db4SBarry Smith 
12959f137db4SBarry Smith   PetscFunctionBegin;
1296ef5c7bd2SStefano Zampini   if (X == Y) {
12979566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
12983ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1299ef5c7bd2SStefano Zampini   }
1300ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13019566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13029f137db4SBarry Smith     shell->axpy_vscale = a;
13039566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1304ef5c7bd2SStefano Zampini   } else {
13059566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1306ef5c7bd2SStefano Zampini   }
13073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13089f137db4SBarry Smith }
13099f137db4SBarry Smith 
1310f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1311f4259b30SLisandro Dalcin                                        NULL,
1312f4259b30SLisandro Dalcin                                        NULL,
1313f4259b30SLisandro Dalcin                                        NULL,
13140c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1315f4259b30SLisandro Dalcin                                        NULL,
13160c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1317f4259b30SLisandro Dalcin                                        NULL,
1318f4259b30SLisandro Dalcin                                        NULL,
1319f4259b30SLisandro Dalcin                                        NULL,
1320f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1321f4259b30SLisandro Dalcin                                        NULL,
1322f4259b30SLisandro Dalcin                                        NULL,
1323f4259b30SLisandro Dalcin                                        NULL,
1324f4259b30SLisandro Dalcin                                        NULL,
1325f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1326f4259b30SLisandro Dalcin                                        NULL,
1327f4259b30SLisandro Dalcin                                        NULL,
13288fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1329f4259b30SLisandro Dalcin                                        NULL,
1330f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1331ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1332f4259b30SLisandro Dalcin                                        NULL,
1333f4259b30SLisandro Dalcin                                        NULL,
133445960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1335f4259b30SLisandro Dalcin                                        NULL,
1336f4259b30SLisandro Dalcin                                        NULL,
1337f4259b30SLisandro Dalcin                                        NULL,
1338f4259b30SLisandro Dalcin                                        NULL,
1339f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1340f4259b30SLisandro Dalcin                                        NULL,
1341f4259b30SLisandro Dalcin                                        NULL,
1342f4259b30SLisandro Dalcin                                        NULL,
1343f4259b30SLisandro Dalcin                                        NULL,
1344cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1345f4259b30SLisandro Dalcin                                        NULL,
1346f4259b30SLisandro Dalcin                                        NULL,
1347f4259b30SLisandro Dalcin                                        NULL,
1348f4259b30SLisandro Dalcin                                        NULL,
13499f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1350f4259b30SLisandro Dalcin                                        NULL,
1351f4259b30SLisandro Dalcin                                        NULL,
1352f4259b30SLisandro Dalcin                                        NULL,
1353cb8c8a77SBarry Smith                                        MatCopy_Shell,
1354f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1355ef66eb69SBarry Smith                                        MatScale_Shell,
1356ef66eb69SBarry Smith                                        MatShift_Shell,
13576464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
135845960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1359f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1360f4259b30SLisandro Dalcin                                        NULL,
1361f4259b30SLisandro Dalcin                                        NULL,
1362f4259b30SLisandro Dalcin                                        NULL,
1363f4259b30SLisandro Dalcin                                        NULL,
1364f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
1368f4259b30SLisandro Dalcin                                        NULL,
1369f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1370b9b97703SBarry Smith                                        MatDestroy_Shell,
1371f4259b30SLisandro Dalcin                                        NULL,
1372251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
1376f4259b30SLisandro Dalcin                                        NULL,
1377f4259b30SLisandro Dalcin                                        NULL,
1378f4259b30SLisandro Dalcin                                        NULL,
1379f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1382f4259b30SLisandro Dalcin                                        NULL,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386f4259b30SLisandro Dalcin                                        NULL,
1387f4259b30SLisandro Dalcin                                        NULL,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        NULL,
1394f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        NULL,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        NULL,
1399f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        NULL,
1409f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        NULL,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
1414f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
14233b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1424f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451d70f29a3SPierre Jolivet                                        NULL,
1452d70f29a3SPierre Jolivet                                        NULL,
1453d70f29a3SPierre Jolivet                                        NULL,
1454d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1455d70f29a3SPierre Jolivet                                        NULL,
1456d70f29a3SPierre Jolivet                                        NULL,
145799a7f59eSMark Adams                                        NULL,
145899a7f59eSMark Adams                                        NULL,
14597fb60732SBarry Smith                                        NULL,
1460dec0b466SHong Zhang                                        /*150*/ NULL,
1461dec0b466SHong Zhang                                        NULL};
1462273d9f13SBarry Smith 
1463d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1464d71ae5a4SJacob Faibussowitsch {
1465789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1466789d8953SBarry Smith 
1467789d8953SBarry Smith   PetscFunctionBegin;
1468800f99ffSJeremy L Thompson   if (ctx) {
1469800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1470800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1471800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1472800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1473800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1474800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1475800f99ffSJeremy L Thompson   } else {
1476800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1477800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1478800f99ffSJeremy L Thompson   }
1479800f99ffSJeremy L Thompson 
14803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1481800f99ffSJeremy L Thompson }
1482800f99ffSJeremy L Thompson 
1483d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1484d71ae5a4SJacob Faibussowitsch {
1485800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1486800f99ffSJeremy L Thompson 
1487800f99ffSJeremy L Thompson   PetscFunctionBegin;
1488800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
14893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1490789d8953SBarry Smith }
1491789d8953SBarry Smith 
1492d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1493d71ae5a4SJacob Faibussowitsch {
1494db77db73SJeremy L Thompson   PetscFunctionBegin;
14959566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
14969566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1498db77db73SJeremy L Thompson }
1499db77db73SJeremy L Thompson 
1500d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1501d71ae5a4SJacob Faibussowitsch {
1502789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1503789d8953SBarry Smith 
1504789d8953SBarry Smith   PetscFunctionBegin;
1505789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1506789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1507789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1508789d8953SBarry Smith   A->ops->scale              = NULL;
1509789d8953SBarry Smith   A->ops->shift              = NULL;
1510789d8953SBarry Smith   A->ops->axpy               = NULL;
15113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1512789d8953SBarry Smith }
1513789d8953SBarry Smith 
1514d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1515d71ae5a4SJacob Faibussowitsch {
1516feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1517789d8953SBarry Smith 
1518789d8953SBarry Smith   PetscFunctionBegin;
1519789d8953SBarry Smith   switch (op) {
1520d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1521d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1522d71ae5a4SJacob Faibussowitsch     break;
1523789d8953SBarry Smith   case MATOP_VIEW:
1524ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1525789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1526789d8953SBarry Smith     break;
1527d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1528d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1529d71ae5a4SJacob Faibussowitsch     break;
1530789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1531789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1532789d8953SBarry Smith   case MATOP_SHIFT:
1533789d8953SBarry Smith   case MATOP_SCALE:
1534789d8953SBarry Smith   case MATOP_AXPY:
1535789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1536789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
153728b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1538789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1539789d8953SBarry Smith     break;
1540789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1541789d8953SBarry Smith     if (shell->managescalingshifts) {
1542789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1543789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1544789d8953SBarry Smith     } else {
1545789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1546789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1547789d8953SBarry Smith     }
1548789d8953SBarry Smith     break;
1549789d8953SBarry Smith   case MATOP_MULT:
1550789d8953SBarry Smith     if (shell->managescalingshifts) {
1551789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1552789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1553789d8953SBarry Smith     } else {
1554789d8953SBarry Smith       shell->ops->mult = NULL;
1555789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1556789d8953SBarry Smith     }
1557789d8953SBarry Smith     break;
1558789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1559789d8953SBarry Smith     if (shell->managescalingshifts) {
1560789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1561789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1562789d8953SBarry Smith     } else {
1563789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1564789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1565789d8953SBarry Smith     }
1566789d8953SBarry Smith     break;
1567d71ae5a4SJacob Faibussowitsch   default:
1568d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1569d71ae5a4SJacob Faibussowitsch     break;
1570789d8953SBarry Smith   }
15713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1572789d8953SBarry Smith }
1573789d8953SBarry Smith 
1574d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1575d71ae5a4SJacob Faibussowitsch {
1576789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1577789d8953SBarry Smith 
1578789d8953SBarry Smith   PetscFunctionBegin;
1579789d8953SBarry Smith   switch (op) {
1580d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1581d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1582d71ae5a4SJacob Faibussowitsch     break;
1583d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1584d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1585d71ae5a4SJacob Faibussowitsch     break;
1586d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1587d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1588d71ae5a4SJacob Faibussowitsch     break;
1589789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1590789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1591789d8953SBarry Smith   case MATOP_SHIFT:
1592789d8953SBarry Smith   case MATOP_SCALE:
1593789d8953SBarry Smith   case MATOP_AXPY:
1594789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1595d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1596d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1597d71ae5a4SJacob Faibussowitsch     break;
1598789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
15999371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
16009371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1601789d8953SBarry Smith     break;
1602789d8953SBarry Smith   case MATOP_MULT:
16039371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
16049371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1605789d8953SBarry Smith     break;
1606789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
16079371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
16089371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1609789d8953SBarry Smith     break;
1610d71ae5a4SJacob Faibussowitsch   default:
1611d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1612789d8953SBarry Smith   }
16133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1614789d8953SBarry Smith }
1615789d8953SBarry Smith 
16160bad9183SKris Buschelman /*MC
1617fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16180bad9183SKris Buschelman 
16190bad9183SKris Buschelman   Level: advanced
16200bad9183SKris Buschelman 
16211cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`
16220bad9183SKris Buschelman M*/
16230bad9183SKris Buschelman 
1624d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1625d71ae5a4SJacob Faibussowitsch {
1626273d9f13SBarry Smith   Mat_Shell *b;
1627273d9f13SBarry Smith 
1628273d9f13SBarry Smith   PetscFunctionBegin;
16294dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1630273d9f13SBarry Smith   A->data   = (void *)b;
1631aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1632273d9f13SBarry Smith 
1633800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1634ef66eb69SBarry Smith   b->vshift              = 0.0;
1635ef66eb69SBarry Smith   b->vscale              = 1.0;
16360c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1637273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1638210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
16392205254eSKarl Rupp 
16409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
16419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1642800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
16439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
16449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
16459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
16469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
16479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
16489566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
16493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1650273d9f13SBarry Smith }
1651e51e0e81SBarry Smith 
16524b828684SBarry Smith /*@C
165311a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1654ff756334SLois Curfman McInnes   private data storage format.
1655e51e0e81SBarry Smith 
1656d083f849SBarry Smith   Collective
1657c7fcc2eaSBarry Smith 
1658e51e0e81SBarry Smith   Input Parameters:
1659c7fcc2eaSBarry Smith + comm - MPI communicator
1660c7fcc2eaSBarry Smith . m    - number of local rows (must be given)
1661c7fcc2eaSBarry Smith . n    - number of local columns (must be given)
16622ef1f0ffSBarry Smith . M    - number of global rows (may be `PETSC_DETERMINE`)
16632ef1f0ffSBarry Smith . N    - number of global columns (may be `PETSC_DETERMINE`)
1664c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1665e51e0e81SBarry Smith 
1666ff756334SLois Curfman McInnes   Output Parameter:
166744cd7ae7SLois Curfman McInnes . A - the matrix
1668e51e0e81SBarry Smith 
1669ff2fd236SBarry Smith   Level: advanced
1670ff2fd236SBarry Smith 
1671*2920cce0SJacob Faibussowitsch   Example Usage:
167227430b45SBarry Smith .vb
167327430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
1674*2920cce0SJacob Faibussowitsch 
167527430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
167627430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
1677*2920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
167827430b45SBarry Smith   MatDestroy(mat);
167927430b45SBarry Smith .ve
1680f39d1f56SLois Curfman McInnes 
1681ff756334SLois Curfman McInnes   Notes:
1682ff756334SLois Curfman McInnes   The shell matrix type is intended to provide a simple class to use
168311a5261eSBarry Smith   with `KSP` (such as, for use with matrix-free methods). You should not
1684ff756334SLois Curfman McInnes   use the shell type if you plan to define a complete matrix class.
1685e51e0e81SBarry Smith 
1686f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1687f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
16882ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
168911a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1690645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1691645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1692645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1693645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1694645985a0SLois Curfman McInnes   For example,
1695f39d1f56SLois Curfman McInnes 
169627430b45SBarry Smith .vb
169727430b45SBarry Smith      Vec x, y
169827430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
169927430b45SBarry Smith      Mat A
170027430b45SBarry Smith 
170127430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
170227430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
170327430b45SBarry Smith      VecGetLocalSize(y,&m);
170427430b45SBarry Smith      VecGetLocalSize(x,&n);
170527430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
170627430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
170727430b45SBarry Smith      MatMult(A,x,y);
170827430b45SBarry Smith      MatDestroy(&A);
170927430b45SBarry Smith      VecDestroy(&y);
171027430b45SBarry Smith      VecDestroy(&x);
171127430b45SBarry Smith .ve
1712e51e0e81SBarry Smith 
17132ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
17142ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
17150c0fd78eSBarry Smith 
171627430b45SBarry Smith   Developer Notes:
17172ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
17182ef1f0ffSBarry Smith 
171995452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
17200c0fd78eSBarry Smith 
17210c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17220c0fd78eSBarry Smith 
17230c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
17240c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17250c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
17260c0fd78eSBarry Smith 
17270c0fd78eSBarry Smith   A is the user provided function.
17280c0fd78eSBarry Smith 
172927430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1730c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
173111a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
173211a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1733ad2f5c3fSBarry Smith 
173411a5261eSBarry Smith   Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1735b77ba244SStefano Zampini 
173611a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
173711a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1738ad2f5c3fSBarry Smith 
1739fe59aa6dSJacob Faibussowitsch   Fortran Notes:
17402ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
174111a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
17422ef1f0ffSBarry Smith   in as the `ctx` argument.
174311a5261eSBarry Smith 
1744fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1745e51e0e81SBarry Smith @*/
1746d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1747d71ae5a4SJacob Faibussowitsch {
17483a40ed3dSBarry Smith   PetscFunctionBegin;
17499566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
17509566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
17519566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
17529566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
17539566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
17543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1755c7fcc2eaSBarry Smith }
1756c7fcc2eaSBarry Smith 
1757c6866cfdSSatish Balay /*@
175811a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1759c7fcc2eaSBarry Smith 
1760c3339decSBarry Smith   Logically Collective
1761c7fcc2eaSBarry Smith 
1762273d9f13SBarry Smith   Input Parameters:
176311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1764273d9f13SBarry Smith - ctx - the context
1765273d9f13SBarry Smith 
1766273d9f13SBarry Smith   Level: advanced
1767273d9f13SBarry Smith 
1768fe59aa6dSJacob Faibussowitsch   Fortran Notes:
176927430b45SBarry Smith   You must write a Fortran interface definition for this
17702ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1771273d9f13SBarry Smith 
17721cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
17730bc0a719SBarry Smith @*/
1774d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1775d71ae5a4SJacob Faibussowitsch {
1776273d9f13SBarry Smith   PetscFunctionBegin;
17770700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1778cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
17793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1780e51e0e81SBarry Smith }
1781e51e0e81SBarry Smith 
1782fe59aa6dSJacob Faibussowitsch /*@C
178311a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1784800f99ffSJeremy L Thompson 
1785c3339decSBarry Smith   Logically Collective
1786800f99ffSJeremy L Thompson 
1787800f99ffSJeremy L Thompson   Input Parameters:
1788800f99ffSJeremy L Thompson + mat - the shell matrix
1789800f99ffSJeremy L Thompson - f   - the context destroy function
1790800f99ffSJeremy L Thompson 
179127430b45SBarry Smith   Level: advanced
179227430b45SBarry Smith 
1793800f99ffSJeremy L Thompson   Note:
1794800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
179511a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1796800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
179711a5261eSBarry Smith   the `MATSHELL` is duplicated.
1798800f99ffSJeremy L Thompson 
17991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1800800f99ffSJeremy L Thompson @*/
1801d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1802d71ae5a4SJacob Faibussowitsch {
1803800f99ffSJeremy L Thompson   PetscFunctionBegin;
1804800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1805800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
18063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1807800f99ffSJeremy L Thompson }
1808800f99ffSJeremy L Thompson 
1809db77db73SJeremy L Thompson /*@C
18102ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1811db77db73SJeremy L Thompson 
18122ef1f0ffSBarry Smith   Logically Collective
1813db77db73SJeremy L Thompson 
1814db77db73SJeremy L Thompson   Input Parameters:
181511a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1816db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1817db77db73SJeremy L Thompson 
1818db77db73SJeremy L Thompson   Level: advanced
1819db77db73SJeremy L Thompson 
18201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1821db77db73SJeremy L Thompson @*/
1822d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1823d71ae5a4SJacob Faibussowitsch {
1824db77db73SJeremy L Thompson   PetscFunctionBegin;
1825cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
18263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1827db77db73SJeremy L Thompson }
1828db77db73SJeremy L Thompson 
18290c0fd78eSBarry Smith /*@
183011a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
183111a5261eSBarry Smith   after `MatCreateShell()`
18320c0fd78eSBarry Smith 
183327430b45SBarry Smith   Logically Collective
18340c0fd78eSBarry Smith 
18350c0fd78eSBarry Smith   Input Parameter:
1836fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
18370c0fd78eSBarry Smith 
18380c0fd78eSBarry Smith   Level: advanced
18390c0fd78eSBarry Smith 
18401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
18410c0fd78eSBarry Smith @*/
1842d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1843d71ae5a4SJacob Faibussowitsch {
18440c0fd78eSBarry Smith   PetscFunctionBegin;
18450c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1846cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
18473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18480c0fd78eSBarry Smith }
18490c0fd78eSBarry Smith 
1850c16cb8f2SBarry Smith /*@C
185111a5261eSBarry Smith   MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
1852f3b1f45cSBarry Smith 
1853cf53795eSBarry Smith   Logically Collective; No Fortran Support
1854f3b1f45cSBarry Smith 
1855f3b1f45cSBarry Smith   Input Parameters:
185611a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1857f3b1f45cSBarry Smith . f    - the function
185811a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1859f3b1f45cSBarry Smith - ctx  - an optional context for the function
1860f3b1f45cSBarry Smith 
1861f3b1f45cSBarry Smith   Output Parameter:
186211a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1863f3b1f45cSBarry Smith 
18643c7db156SBarry Smith   Options Database Key:
1865f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1866f3b1f45cSBarry Smith 
1867f3b1f45cSBarry Smith   Level: advanced
1868f3b1f45cSBarry Smith 
18691cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1870f3b1f45cSBarry Smith @*/
1871d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1872d71ae5a4SJacob Faibussowitsch {
1873f3b1f45cSBarry Smith   PetscInt  m, n;
1874f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1875f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
187674e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1877f3b1f45cSBarry Smith 
1878f3b1f45cSBarry Smith   PetscFunctionBegin;
1879f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
18809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
18819566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
18829566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
18839566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
18849566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
1885f3b1f45cSBarry Smith 
18869566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
18879566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
1888f3b1f45cSBarry Smith 
18899566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
18909566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
18919566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
18929566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1893f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1894f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1895f3b1f45cSBarry Smith     if (v) {
18969566063dSJacob 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)));
18979566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
18989566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
18999566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
1900f3b1f45cSBarry Smith     }
1901f3b1f45cSBarry Smith   } else if (v) {
19029566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix free multiple appear to produce the same results\n"));
1903f3b1f45cSBarry Smith   }
1904f3b1f45cSBarry Smith   if (flg) *flg = flag;
19059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1910f3b1f45cSBarry Smith }
1911f3b1f45cSBarry Smith 
1912f3b1f45cSBarry Smith /*@C
191311a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
1914f3b1f45cSBarry Smith 
1915cf53795eSBarry Smith   Logically Collective; No Fortran Support
1916f3b1f45cSBarry Smith 
1917f3b1f45cSBarry Smith   Input Parameters:
191811a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1919f3b1f45cSBarry Smith . f    - the function
192011a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1921f3b1f45cSBarry Smith - ctx  - an optional context for the function
1922f3b1f45cSBarry Smith 
1923f3b1f45cSBarry Smith   Output Parameter:
192411a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1925f3b1f45cSBarry Smith 
19263c7db156SBarry Smith   Options Database Key:
1927f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1928f3b1f45cSBarry Smith 
1929f3b1f45cSBarry Smith   Level: advanced
1930f3b1f45cSBarry Smith 
19311cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1932f3b1f45cSBarry Smith @*/
1933d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1934d71ae5a4SJacob Faibussowitsch {
1935f3b1f45cSBarry Smith   Vec       x, y, z;
1936f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
1937f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1938f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
193974e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1940f3b1f45cSBarry Smith 
1941f3b1f45cSBarry Smith   PetscFunctionBegin;
1942f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
19439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
19449566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
19459566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
19469566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
19479566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
19489566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
19499566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
19509566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
19519566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
19529566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
19539566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
1954f3b1f45cSBarry Smith 
19559566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
19569566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
19579566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
19589566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1959f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1960f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1961f3b1f45cSBarry Smith     if (v) {
19629566063dSJacob 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)));
19639566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19649566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19659566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
1966f3b1f45cSBarry Smith     }
1967f3b1f45cSBarry Smith   } else if (v) {
19689566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix free multiple appear to produce the same results\n"));
1969f3b1f45cSBarry Smith   }
1970f3b1f45cSBarry Smith   if (flg) *flg = flag;
19719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19749566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
19769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
19779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
19783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1979f3b1f45cSBarry Smith }
1980f3b1f45cSBarry Smith 
1981f3b1f45cSBarry Smith /*@C
198211a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
1983e51e0e81SBarry Smith 
1984c3339decSBarry Smith   Logically Collective
1985fee21e36SBarry Smith 
1986c7fcc2eaSBarry Smith   Input Parameters:
198711a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1988c7fcc2eaSBarry Smith . op  - the name of the operation
1989789d8953SBarry Smith - g   - the function that provides the operation.
1990c7fcc2eaSBarry Smith 
199115091d37SBarry Smith   Level: advanced
199215091d37SBarry Smith 
1993*2920cce0SJacob Faibussowitsch   Example Usage:
1994c3339decSBarry Smith .vb
1995c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
1996*2920cce0SJacob Faibussowitsch 
1997c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
1998c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
1999c3339decSBarry Smith .ve
20000b627109SLois Curfman McInnes 
2001a62d957aSLois Curfman McInnes   Notes:
2002e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
20031c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2004a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
200511a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2006a62d957aSLois Curfman McInnes 
200711a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2008deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2009deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2010deebb3c3SLois Curfman McInnes   routines, e.g.,
2011a62d957aSLois Curfman McInnes $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2012a62d957aSLois Curfman McInnes 
20134aa34b0aSBarry Smith   In particular each function MUST return an error code of 0 on success and
20144aa34b0aSBarry Smith   nonzero on failure.
20154aa34b0aSBarry Smith 
2016a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
201711a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
201811a5261eSBarry Smith   set by `MatCreateShell()`.
2019a62d957aSLois Curfman McInnes 
20202ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
20212ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2022b77ba244SStefano Zampini 
2023fe59aa6dSJacob Faibussowitsch   Fortran Notes:
202411a5261eSBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2025c4762a1bSJed Brown   generate a matrix. See src/mat/tests/ex120f.F
2026501d9185SBarry Smith 
20271cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2028e51e0e81SBarry Smith @*/
2029d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2030d71ae5a4SJacob Faibussowitsch {
20313a40ed3dSBarry Smith   PetscFunctionBegin;
20320700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2033cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
20343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2035e51e0e81SBarry Smith }
2036f0479e8cSBarry Smith 
2037d4bb536fSBarry Smith /*@C
203811a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2039d4bb536fSBarry Smith 
2040c7fcc2eaSBarry Smith   Not Collective
2041c7fcc2eaSBarry Smith 
2042d4bb536fSBarry Smith   Input Parameters:
204311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2044c7fcc2eaSBarry Smith - op  - the name of the operation
2045d4bb536fSBarry Smith 
2046d4bb536fSBarry Smith   Output Parameter:
2047789d8953SBarry Smith . g - the function that provides the operation.
2048d4bb536fSBarry Smith 
204915091d37SBarry Smith   Level: advanced
205015091d37SBarry Smith 
205127430b45SBarry Smith   Notes:
2052e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2053d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2054d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
205511a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2056d4bb536fSBarry Smith 
2057d4bb536fSBarry Smith   All user-provided functions have the same calling
2058d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2059d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2060d4bb536fSBarry Smith   routines, e.g.,
2061d4bb536fSBarry Smith $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2062d4bb536fSBarry Smith 
2063d4bb536fSBarry Smith   Within each user-defined routine, the user should call
206411a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
206511a5261eSBarry Smith   set by `MatCreateShell()`.
2066d4bb536fSBarry Smith 
20671cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2068d4bb536fSBarry Smith @*/
2069d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2070d71ae5a4SJacob Faibussowitsch {
20713a40ed3dSBarry Smith   PetscFunctionBegin;
20720700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2073cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
20743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2075d4bb536fSBarry Smith }
2076b77ba244SStefano Zampini 
2077b77ba244SStefano Zampini /*@
207811a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2079b77ba244SStefano Zampini 
2080b77ba244SStefano Zampini   Input Parameter:
2081b77ba244SStefano Zampini . mat - the matrix
2082b77ba244SStefano Zampini 
2083b77ba244SStefano Zampini   Output Parameter:
2084b77ba244SStefano Zampini . flg - the boolean value
2085b77ba244SStefano Zampini 
2086b77ba244SStefano Zampini   Level: developer
2087b77ba244SStefano Zampini 
2088fe59aa6dSJacob Faibussowitsch   Developer Notes:
20892ef1f0ffSBarry Smith   In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices
20902ef1f0ffSBarry Smith   (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc)
2091b77ba244SStefano Zampini 
20921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2093b77ba244SStefano Zampini @*/
2094d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2095d71ae5a4SJacob Faibussowitsch {
2096b77ba244SStefano Zampini   PetscFunctionBegin;
2097b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2098dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(flg, 2);
2099b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
21003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2101b77ba244SStefano Zampini }
2102