xref: /petsc/src/mat/impls/shell/shell.c (revision 45f401eb5c8b451c515c36b571e4a1bfda06ff69)
1e51e0e81SBarry Smith /*
220563c6bSBarry Smith    This provides a simple shell for Fortran (and C programmers) to
320563c6bSBarry Smith   create a very simple matrix class for use with KSP without coding
4ed3cc1f0SBarry Smith   much of anything.
5e51e0e81SBarry Smith */
6e51e0e81SBarry Smith 
7af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
845960306SStefano Zampini #include <petsc/private/vecimpl.h>
9e51e0e81SBarry Smith 
1028f357e3SAlex Fikl struct _MatShellOps {
11976e8c5aSLisandro Dalcin   /*  3 */ PetscErrorCode (*mult)(Mat, Vec, Vec);
12976e8c5aSLisandro Dalcin   /*  5 */ PetscErrorCode (*multtranspose)(Mat, Vec, Vec);
13976e8c5aSLisandro Dalcin   /* 17 */ PetscErrorCode (*getdiagonal)(Mat, Vec);
14976e8c5aSLisandro Dalcin   /* 43 */ PetscErrorCode (*copy)(Mat, Mat, MatStructure);
15976e8c5aSLisandro Dalcin   /* 60 */ PetscErrorCode (*destroy)(Mat);
1628f357e3SAlex Fikl };
1728f357e3SAlex Fikl 
18b77ba244SStefano Zampini struct _n_MatShellMatFunctionList {
19b77ba244SStefano Zampini   PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **);
20b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
21b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
22b77ba244SStefano Zampini   MatProductType ptype;
23b77ba244SStefano Zampini   char          *composedname; /* string to identify routine with double dispatch */
24b77ba244SStefano Zampini   char          *resultname;   /* result matrix type */
25b77ba244SStefano Zampini 
26b77ba244SStefano Zampini   struct _n_MatShellMatFunctionList *next;
27b77ba244SStefano Zampini };
28b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList;
29b77ba244SStefano Zampini 
3028f357e3SAlex Fikl typedef struct {
3128f357e3SAlex Fikl   struct _MatShellOps ops[1];
322205254eSKarl Rupp 
33b77ba244SStefano Zampini   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
34b77ba244SStefano Zampini   PetscBool managescalingshifts;
35b77ba244SStefano Zampini 
36b77ba244SStefano Zampini   /* support for MatScale, MatShift and MatMultAdd */
37ef66eb69SBarry Smith   PetscScalar vscale, vshift;
388fe8eb27SJed Brown   Vec         dshift;
398fe8eb27SJed Brown   Vec         left, right;
408fe8eb27SJed Brown   Vec         left_work, right_work;
415edf6516SJed Brown   Vec         left_add_work, right_add_work;
42b77ba244SStefano Zampini 
43ef5c7bd2SStefano Zampini   /* support for MatAXPY */
449f137db4SBarry Smith   Mat              axpy;
459f137db4SBarry Smith   PetscScalar      axpy_vscale;
46b77ba244SStefano Zampini   Vec              axpy_left, axpy_right;
47ef5c7bd2SStefano Zampini   PetscObjectState axpy_state;
48b77ba244SStefano Zampini 
4945960306SStefano Zampini   /* support for ZeroRows/Columns operations */
5045960306SStefano Zampini   IS         zrows;
5145960306SStefano Zampini   IS         zcols;
5245960306SStefano Zampini   Vec        zvals;
5345960306SStefano Zampini   Vec        zvals_w;
5445960306SStefano Zampini   VecScatter zvals_sct_r;
5545960306SStefano Zampini   VecScatter zvals_sct_c;
56b77ba244SStefano Zampini 
57b77ba244SStefano Zampini   /* MatMat operations */
58b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
59b77ba244SStefano Zampini 
60b77ba244SStefano Zampini   /* user defined context */
61800f99ffSJeremy L Thompson   PetscContainer ctxcontainer;
6288cf3e7dSBarry Smith } Mat_Shell;
630c0fd78eSBarry Smith 
6445960306SStefano Zampini /*
6545960306SStefano Zampini      Store and scale values on zeroed rows
6645960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed columns
6745960306SStefano Zampini */
68d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx)
69d71ae5a4SJacob Faibussowitsch {
7045960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
7145960306SStefano Zampini 
7245960306SStefano Zampini   PetscFunctionBegin;
7345960306SStefano Zampini   *xx = x;
7445960306SStefano Zampini   if (shell->zrows) {
759566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
769566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
779566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
789566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
7945960306SStefano Zampini   }
8045960306SStefano Zampini   if (shell->zcols) {
8148a46eb9SPierre Jolivet     if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
829566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->right_work));
839566063dSJacob Faibussowitsch     PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0));
8445960306SStefano Zampini     *xx = shell->right_work;
8545960306SStefano Zampini   }
863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8745960306SStefano Zampini }
8845960306SStefano Zampini 
8945960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
90d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x)
91d71ae5a4SJacob Faibussowitsch {
9245960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
9345960306SStefano Zampini 
9445960306SStefano Zampini   PetscFunctionBegin;
9545960306SStefano Zampini   if (shell->zrows) {
969566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
979566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
9845960306SStefano Zampini   }
993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10045960306SStefano Zampini }
10145960306SStefano Zampini 
10245960306SStefano Zampini /*
10345960306SStefano Zampini      Store and scale values on zeroed rows
10445960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
10545960306SStefano Zampini */
106d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx)
107d71ae5a4SJacob Faibussowitsch {
10845960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
10945960306SStefano Zampini 
11045960306SStefano Zampini   PetscFunctionBegin;
11145960306SStefano Zampini   *xx = NULL;
11245960306SStefano Zampini   if (!shell->zrows) {
11345960306SStefano Zampini     *xx = x;
11445960306SStefano Zampini   } else {
11548a46eb9SPierre Jolivet     if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
1169566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->left_work));
1179566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
1189566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1199566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
1209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
1229566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
12345960306SStefano Zampini     *xx = shell->left_work;
12445960306SStefano Zampini   }
1253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12645960306SStefano Zampini }
12745960306SStefano Zampini 
12845960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
129d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x)
130d71ae5a4SJacob Faibussowitsch {
13145960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
13245960306SStefano Zampini 
13345960306SStefano Zampini   PetscFunctionBegin;
1341baa6e33SBarry Smith   if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0));
13545960306SStefano Zampini   if (shell->zrows) {
1369566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
1379566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
13845960306SStefano Zampini   }
1393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14045960306SStefano Zampini }
14145960306SStefano Zampini 
1428fe8eb27SJed Brown /*
1430c0fd78eSBarry Smith       xx = diag(left)*x
1448fe8eb27SJed Brown */
145d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx)
146d71ae5a4SJacob Faibussowitsch {
1478fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1488fe8eb27SJed Brown 
1498fe8eb27SJed Brown   PetscFunctionBegin;
1500298fd71SBarry Smith   *xx = NULL;
1518fe8eb27SJed Brown   if (!shell->left) {
1528fe8eb27SJed Brown     *xx = x;
1538fe8eb27SJed Brown   } else {
1549566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work));
1559566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->left_work, x, shell->left));
1568fe8eb27SJed Brown     *xx = shell->left_work;
1578fe8eb27SJed Brown   }
1583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1598fe8eb27SJed Brown }
1608fe8eb27SJed Brown 
1610c0fd78eSBarry Smith /*
1620c0fd78eSBarry Smith      xx = diag(right)*x
1630c0fd78eSBarry Smith */
164d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx)
165d71ae5a4SJacob Faibussowitsch {
1668fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1678fe8eb27SJed Brown 
1688fe8eb27SJed Brown   PetscFunctionBegin;
1690298fd71SBarry Smith   *xx = NULL;
1708fe8eb27SJed Brown   if (!shell->right) {
1718fe8eb27SJed Brown     *xx = x;
1728fe8eb27SJed Brown   } else {
1739566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work));
1749566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work, x, shell->right));
1758fe8eb27SJed Brown     *xx = shell->right_work;
1768fe8eb27SJed Brown   }
1773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1788fe8eb27SJed Brown }
1798fe8eb27SJed Brown 
1800c0fd78eSBarry Smith /*
1810c0fd78eSBarry Smith     x = diag(left)*x
1820c0fd78eSBarry Smith */
183d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x)
184d71ae5a4SJacob Faibussowitsch {
1858fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1868fe8eb27SJed Brown 
1878fe8eb27SJed Brown   PetscFunctionBegin;
1889566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left));
1893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1908fe8eb27SJed Brown }
1918fe8eb27SJed Brown 
1920c0fd78eSBarry Smith /*
1930c0fd78eSBarry Smith     x = diag(right)*x
1940c0fd78eSBarry Smith */
195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x)
196d71ae5a4SJacob Faibussowitsch {
1978fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1988fe8eb27SJed Brown 
1998fe8eb27SJed Brown   PetscFunctionBegin;
2009566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(x, x, shell->right));
2013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2028fe8eb27SJed Brown }
2038fe8eb27SJed Brown 
2040c0fd78eSBarry Smith /*
2050c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2060c0fd78eSBarry Smith 
2070c0fd78eSBarry Smith          On input Y already contains A*x
2080c0fd78eSBarry Smith */
209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y)
210d71ae5a4SJacob Faibussowitsch {
2118fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
2128fe8eb27SJed Brown 
2138fe8eb27SJed Brown   PetscFunctionBegin;
2148fe8eb27SJed Brown   if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */
2158fe8eb27SJed Brown     PetscInt           i, m;
2168fe8eb27SJed Brown     const PetscScalar *x, *d;
2178fe8eb27SJed Brown     PetscScalar       *y;
2189566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X, &m));
2199566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift, &d));
2209566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X, &x));
2219566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y, &y));
2228fe8eb27SJed Brown     for (i = 0; i < m; i++) y[i] = shell->vscale * y[i] + d[i] * x[i];
2239566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift, &d));
2249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X, &x));
2259566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y, &y));
2260c0fd78eSBarry Smith   } else {
2279566063dSJacob Faibussowitsch     PetscCall(VecScale(Y, shell->vscale));
2288fe8eb27SJed Brown   }
2299566063dSJacob Faibussowitsch   if (shell->vshift != 0.0) PetscCall(VecAXPY(Y, shell->vshift, X)); /* if test is for non-square matrices */
2303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2318fe8eb27SJed Brown }
232e51e0e81SBarry Smith 
233d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx)
234d71ae5a4SJacob Faibussowitsch {
235800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
236800f99ffSJeremy L Thompson 
237789d8953SBarry Smith   PetscFunctionBegin;
238800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx));
239800f99ffSJeremy L Thompson   else *(void **)ctx = NULL;
2403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
241789d8953SBarry Smith }
242789d8953SBarry Smith 
2439d225801SJed Brown /*@
24411a5261eSBarry Smith   MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix.
245b4fd4287SBarry Smith 
246c7fcc2eaSBarry Smith   Not Collective
247c7fcc2eaSBarry Smith 
248b4fd4287SBarry Smith   Input Parameter:
24911a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()`
250b4fd4287SBarry Smith 
251b4fd4287SBarry Smith   Output Parameter:
252b4fd4287SBarry Smith . ctx - the user provided context
253b4fd4287SBarry Smith 
25415091d37SBarry Smith   Level: advanced
25515091d37SBarry Smith 
256fe59aa6dSJacob Faibussowitsch   Fortran Notes:
25727430b45SBarry Smith   You must write a Fortran interface definition for this
258daf670e6SBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
259a62d957aSLois Curfman McInnes 
2601cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2610bc0a719SBarry Smith @*/
262d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx)
263d71ae5a4SJacob Faibussowitsch {
2643a40ed3dSBarry Smith   PetscFunctionBegin;
2650700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2664f572ea9SToby Isaac   PetscAssertPointer(ctx, 2);
267cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx));
2683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
269b4fd4287SBarry Smith }
270b4fd4287SBarry Smith 
271d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc)
272d71ae5a4SJacob Faibussowitsch {
27345960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell *)mat->data;
27445960306SStefano Zampini   Vec             x = NULL, b = NULL;
27545960306SStefano Zampini   IS              is1, is2;
27645960306SStefano Zampini   const PetscInt *ridxs;
27745960306SStefano Zampini   PetscInt       *idxs, *gidxs;
27845960306SStefano Zampini   PetscInt        cum, rst, cst, i;
27945960306SStefano Zampini 
28045960306SStefano Zampini   PetscFunctionBegin;
28148a46eb9SPierre Jolivet   if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals));
28248a46eb9SPierre Jolivet   if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w));
2839566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat, &rst, NULL));
2849566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL));
28545960306SStefano Zampini 
28645960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &idxs));
28845960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
2899566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1));
2909566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2919566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals, is1, diag));
29245960306SStefano Zampini   if (shell->zrows) {
2939566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows, is1, &is2));
2949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
2959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
29645960306SStefano Zampini     shell->zrows = is2;
29745960306SStefano Zampini   } else shell->zrows = is1;
29845960306SStefano Zampini 
29945960306SStefano Zampini   /* Create scatters for diagonal values communications */
3009566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
3019566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
30245960306SStefano Zampini 
30345960306SStefano Zampini   /* row scatter: from/to left vector */
3049566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &b));
3059566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r));
30645960306SStefano Zampini 
30745960306SStefano Zampini   /* col scatter: from right vector to left vector */
3089566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows, &ridxs));
3099566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows, &nr));
3109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &gidxs));
31145960306SStefano Zampini   for (i = 0, cum = 0; i < nr; i++) {
31245960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
31345960306SStefano Zampini     gidxs[cum] = ridxs[i];
31445960306SStefano Zampini     cum++;
31545960306SStefano Zampini   }
3169566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1));
3179566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c));
3189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
3199566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
3209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
32145960306SStefano Zampini 
32245960306SStefano Zampini   /* Expand/create index set of zeroed columns */
32345960306SStefano Zampini   if (rc) {
3249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc, &idxs));
32545960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3269566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1));
3279566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
32845960306SStefano Zampini     if (shell->zcols) {
3299566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols, is1, &is2));
3309566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
33245960306SStefano Zampini       shell->zcols = is2;
33345960306SStefano Zampini     } else shell->zcols = is1;
33445960306SStefano Zampini   }
3353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33645960306SStefano Zampini }
33745960306SStefano Zampini 
338d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
339d71ae5a4SJacob Faibussowitsch {
340ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
34145960306SStefano Zampini   PetscInt   nr, *lrows;
34245960306SStefano Zampini 
34345960306SStefano Zampini   PetscFunctionBegin;
34445960306SStefano Zampini   if (x && b) {
34545960306SStefano Zampini     Vec          xt;
34645960306SStefano Zampini     PetscScalar *vals;
34745960306SStefano Zampini     PetscInt    *gcols, i, st, nl, nc;
34845960306SStefano Zampini 
3499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &gcols));
3509371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3519371c9d4SSatish Balay       if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
35245960306SStefano Zampini 
3539566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, NULL));
3549566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3559566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc, &vals));
3569566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3579566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3589566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3599566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3609566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */
36145960306SStefano Zampini 
3629566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3639566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3649566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
36545960306SStefano Zampini     for (i = 0; i < nl; i++) {
36645960306SStefano Zampini       PetscInt g = i + st;
36745960306SStefano Zampini       if (g > mat->rmap->N) continue;
36845960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3699566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES));
37045960306SStefano Zampini     }
3719566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
3729566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3739566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1, x2 * diag] */
3749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3759566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
37645960306SStefano Zampini   }
3779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL));
3789566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE));
3791baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL));
3809566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38245960306SStefano Zampini }
38345960306SStefano Zampini 
384d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b)
385d71ae5a4SJacob Faibussowitsch {
386ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
38745960306SStefano Zampini   PetscInt  *lrows, *lcols;
38845960306SStefano Zampini   PetscInt   nr, nc;
38945960306SStefano Zampini   PetscBool  congruent;
39045960306SStefano Zampini 
39145960306SStefano Zampini   PetscFunctionBegin;
39245960306SStefano Zampini   if (x && b) {
39345960306SStefano Zampini     Vec          xt, bt;
39445960306SStefano Zampini     PetscScalar *vals;
39545960306SStefano Zampini     PetscInt    *grows, *gcols, i, st, nl;
39645960306SStefano Zampini 
3979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n, &grows, n, &gcols));
3989371c9d4SSatish Balay     for (i = 0, nr = 0; i < n; i++)
3999371c9d4SSatish Balay       if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
4009371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
4019371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
4029566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &vals));
40345960306SStefano Zampini 
4049566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, &bt));
4059566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
4069566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
4079566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
4089566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
4099566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt, -1.0, x));                             /* xt = [0, -x2] */
4109566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, xt, bt));                             /* bt = [-A12*x2,-A22*x2] */
4119566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */
4129566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4139566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4149566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b, 1.0, bt));                              /* b  = [b1 - A12*x2, b2] */
4159566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
4169566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
4179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
4189566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
41945960306SStefano Zampini 
4209566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
4219566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
4229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
42345960306SStefano Zampini     for (i = 0; i < nl; i++) {
42445960306SStefano Zampini       PetscInt g = i + st;
42545960306SStefano Zampini       if (g > mat->rmap->N) continue;
42645960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4279566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES));
42845960306SStefano Zampini     }
4299566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4309566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4319566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1 - A12*x2, x2 * diag] */
4329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4349566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows, gcols));
43545960306SStefano Zampini   }
4369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL));
4379566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat, &congruent));
43845960306SStefano Zampini   if (congruent) {
43945960306SStefano Zampini     nc    = nr;
44045960306SStefano Zampini     lcols = lrows;
44145960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
44245960306SStefano Zampini     PetscInt i, nt, *t;
44345960306SStefano Zampini 
4449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &t));
4459371c9d4SSatish Balay     for (i = 0, nt = 0; i < n; i++)
4469371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4479566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL));
4489566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
44945960306SStefano Zampini   }
4509566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE));
45148a46eb9SPierre Jolivet   if (!congruent) PetscCall(PetscFree(lcols));
4529566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4531baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL));
4543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45545960306SStefano Zampini }
45645960306SStefano Zampini 
457d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat)
458d71ae5a4SJacob Faibussowitsch {
459bf0cc555SLisandro Dalcin   Mat_Shell              *shell = (Mat_Shell *)mat->data;
460b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
461ed3cc1f0SBarry Smith 
4623a40ed3dSBarry Smith   PetscFunctionBegin;
4631baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4649566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps)));
4659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4689566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4729566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4749566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4779566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4789566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4799566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
481b77ba244SStefano Zampini 
482b77ba244SStefano Zampini   matmat = shell->matmat;
483b77ba244SStefano Zampini   while (matmat) {
484b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
485b77ba244SStefano Zampini 
4869566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL));
4879566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
4889566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
4899566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
490b77ba244SStefano Zampini     matmat = next;
491b77ba244SStefano Zampini   }
492800f99ffSJeremy L Thompson   PetscCall(MatShellSetContext(mat, NULL));
4939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL));
4949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL));
495800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL));
4969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL));
4979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL));
4989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
4999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
5009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
5019566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
5023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
503b77ba244SStefano Zampini }
504b77ba244SStefano Zampini 
505b77ba244SStefano Zampini typedef struct {
506b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
507b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
508b77ba244SStefano Zampini   void *userdata;
509b77ba244SStefano Zampini   Mat   B;
510b77ba244SStefano Zampini   Mat   Bt;
511b77ba244SStefano Zampini   Mat   axpy;
512b77ba244SStefano Zampini } MatMatDataShell;
513b77ba244SStefano Zampini 
514d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data)
515d71ae5a4SJacob Faibussowitsch {
516b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
517b77ba244SStefano Zampini 
518b77ba244SStefano Zampini   PetscFunctionBegin;
5191baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
5209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5239566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
525b77ba244SStefano Zampini }
526b77ba244SStefano Zampini 
527d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
528d71ae5a4SJacob Faibussowitsch {
529b77ba244SStefano Zampini   Mat_Product     *product;
530b77ba244SStefano Zampini   Mat              A, B;
531b77ba244SStefano Zampini   MatMatDataShell *mdata;
532b77ba244SStefano Zampini   PetscScalar      zero = 0.0;
533b77ba244SStefano Zampini 
534b77ba244SStefano Zampini   PetscFunctionBegin;
535b77ba244SStefano Zampini   MatCheckProduct(D, 1);
536b77ba244SStefano Zampini   product = D->product;
53728b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
538b77ba244SStefano Zampini   A     = product->A;
539b77ba244SStefano Zampini   B     = product->B;
540b77ba244SStefano Zampini   mdata = (MatMatDataShell *)product->data;
541b77ba244SStefano Zampini   if (mdata->numeric) {
542b77ba244SStefano Zampini     Mat_Shell *shell                = (Mat_Shell *)A->data;
543b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
544b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
545b77ba244SStefano Zampini     PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
546b77ba244SStefano Zampini 
547b77ba244SStefano Zampini     if (shell->managescalingshifts) {
54808401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
549b77ba244SStefano Zampini       if (shell->right || shell->left) {
550b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
551b77ba244SStefano Zampini         if (!mdata->B) {
5529566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
553b77ba244SStefano Zampini         } else {
554b77ba244SStefano Zampini           newB = PETSC_FALSE;
555b77ba244SStefano Zampini         }
5569566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
557b77ba244SStefano Zampini       }
558b77ba244SStefano Zampini       switch (product->type) {
559b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5601baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
561b77ba244SStefano Zampini         break;
562b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5631baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
564b77ba244SStefano Zampini         break;
565b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5661baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
567b77ba244SStefano Zampini         break;
568b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
569b77ba244SStefano Zampini         if (shell->right && shell->left) {
570b77ba244SStefano Zampini           PetscBool flg;
571b77ba244SStefano Zampini 
5729566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5739371c9d4SSatish 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,
5749371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
575b77ba244SStefano Zampini         }
5761baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
577b77ba244SStefano Zampini         break;
578b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
579b77ba244SStefano Zampini         if (shell->right && shell->left) {
580b77ba244SStefano Zampini           PetscBool flg;
581b77ba244SStefano Zampini 
5829566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5839371c9d4SSatish 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,
5849371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
585b77ba244SStefano Zampini         }
5861baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
587b77ba244SStefano Zampini         break;
588d71ae5a4SJacob Faibussowitsch       default:
589d71ae5a4SJacob 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);
590b77ba244SStefano Zampini       }
591b77ba244SStefano Zampini     }
592b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
593b77ba244SStefano Zampini     D->product              = NULL;
594b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
595b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
596b77ba244SStefano Zampini 
5979566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata));
598b77ba244SStefano Zampini 
599b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
6009566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
601b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
602b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
603b77ba244SStefano Zampini     D->product              = product;
604b77ba244SStefano Zampini 
605b77ba244SStefano Zampini     if (shell->managescalingshifts) {
6069566063dSJacob Faibussowitsch       PetscCall(MatScale(D, shell->vscale));
607b77ba244SStefano Zampini       switch (product->type) {
608b77ba244SStefano Zampini       case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
609b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
610b77ba244SStefano Zampini         if (shell->left) {
6119566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->left, NULL));
612b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
6139566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
614b77ba244SStefano Zampini             if (shell->dshift) {
6159566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->left_work));
6169566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work, shell->vshift));
6179566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
618b77ba244SStefano Zampini             } else {
6199566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work, shell->vshift));
620b77ba244SStefano Zampini             }
621b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
622b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
623b77ba244SStefano Zampini               MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
624b77ba244SStefano Zampini 
6259566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6269566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6279566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
628b77ba244SStefano Zampini             } else {
629b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
630b77ba244SStefano Zampini 
6319566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6329566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->B, str));
633b77ba244SStefano Zampini             }
634b77ba244SStefano Zampini           }
635b77ba244SStefano Zampini         }
636b77ba244SStefano Zampini         break;
637b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
638b77ba244SStefano Zampini         if (shell->right) {
6399566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->right, NULL));
640b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
641b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
642b77ba244SStefano Zampini 
6439566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
644b77ba244SStefano Zampini             if (shell->dshift) {
6459566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->right_work));
6469566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work, shell->vshift));
6479566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
648b77ba244SStefano Zampini             } else {
6499566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work, shell->vshift));
650b77ba244SStefano Zampini             }
6519566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6529566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
653b77ba244SStefano Zampini           }
654b77ba244SStefano Zampini         }
655b77ba244SStefano Zampini         break;
656b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
657b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6589371c9d4SSatish 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,
6599371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
660b77ba244SStefano Zampini         break;
661d71ae5a4SJacob Faibussowitsch       default:
662d71ae5a4SJacob 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);
663b77ba244SStefano Zampini       }
664b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
665b77ba244SStefano Zampini         Mat              X;
666b77ba244SStefano Zampini         PetscObjectState axpy_state;
667b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
668b77ba244SStefano Zampini 
6699566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy, &X));
6709566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
67108401ef6SPierre 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,...)");
672b77ba244SStefano Zampini         if (!mdata->axpy) {
673b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
6749566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
6759566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy, product->type));
6769566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6779566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
678b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
679b77ba244SStefano Zampini           PetscBool flg;
680b77ba244SStefano Zampini 
6819566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
6829566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
683b77ba244SStefano Zampini           if (!flg) {
684b77ba244SStefano Zampini             str = DIFFERENT_NONZERO_PATTERN;
6859566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
6869566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
687b77ba244SStefano Zampini           }
688b77ba244SStefano Zampini         }
6899566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
6909566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
691b77ba244SStefano Zampini       }
692b77ba244SStefano Zampini     }
693b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
6943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
695b77ba244SStefano Zampini }
696b77ba244SStefano Zampini 
697d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
698d71ae5a4SJacob Faibussowitsch {
699b77ba244SStefano Zampini   Mat_Product            *product;
700b77ba244SStefano Zampini   Mat                     A, B;
701b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
702b77ba244SStefano Zampini   Mat_Shell              *shell;
703eae3dc7dSJacob Faibussowitsch   PetscBool               flg = PETSC_FALSE;
704b77ba244SStefano Zampini   char                    composedname[256];
705b77ba244SStefano Zampini   MatMatDataShell        *mdata;
706b77ba244SStefano Zampini 
707b77ba244SStefano Zampini   PetscFunctionBegin;
708b77ba244SStefano Zampini   MatCheckProduct(D, 1);
709b77ba244SStefano Zampini   product = D->product;
71028b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
711b77ba244SStefano Zampini   A      = product->A;
712b77ba244SStefano Zampini   B      = product->B;
713b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
714b77ba244SStefano Zampini   matmat = shell->matmat;
7159566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
716b77ba244SStefano Zampini   while (matmat) {
7179566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
718b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
719b77ba244SStefano Zampini     if (flg) break;
720b77ba244SStefano Zampini     matmat = matmat->next;
721b77ba244SStefano Zampini   }
72228b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
723b77ba244SStefano Zampini   switch (product->type) {
724d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
725d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
726d71ae5a4SJacob Faibussowitsch     break;
727d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
728d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
729d71ae5a4SJacob Faibussowitsch     break;
730d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
731d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
732d71ae5a4SJacob Faibussowitsch     break;
733d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
734d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
735d71ae5a4SJacob Faibussowitsch     break;
736d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
737d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
738d71ae5a4SJacob Faibussowitsch     break;
739d71ae5a4SJacob Faibussowitsch   default:
740d71ae5a4SJacob 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);
741b77ba244SStefano Zampini   }
742b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
743b77ba244SStefano Zampini   if (matmat->resultname) {
7449566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
74548a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
746b77ba244SStefano Zampini   }
747b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
748b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
749b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
750b77ba244SStefano Zampini   /* attach product data */
7519566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
752b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
753b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
754b77ba244SStefano Zampini   if (matmat->symbolic) {
7559566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata));
756b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7579566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
758b77ba244SStefano Zampini   }
75928b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
76028b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
761b77ba244SStefano Zampini   D->product->data    = mdata;
762b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
763b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
764b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
765b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
767b77ba244SStefano Zampini }
768b77ba244SStefano Zampini 
769d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
770d71ae5a4SJacob Faibussowitsch {
771b77ba244SStefano Zampini   Mat_Product            *product;
772b77ba244SStefano Zampini   Mat                     A, B;
773b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
774b77ba244SStefano Zampini   Mat_Shell              *shell;
775b77ba244SStefano Zampini   PetscBool               flg;
776b77ba244SStefano Zampini   char                    composedname[256];
777b77ba244SStefano Zampini 
778b77ba244SStefano Zampini   PetscFunctionBegin;
779b77ba244SStefano Zampini   MatCheckProduct(D, 1);
780b77ba244SStefano Zampini   product = D->product;
781b77ba244SStefano Zampini   A       = product->A;
782b77ba244SStefano Zampini   B       = product->B;
7839566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
7843ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
785b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
786b77ba244SStefano Zampini   matmat = shell->matmat;
7879566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
788b77ba244SStefano Zampini   while (matmat) {
7899566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
790b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
791b77ba244SStefano Zampini     if (flg) break;
792b77ba244SStefano Zampini     matmat = matmat->next;
793b77ba244SStefano Zampini   }
7949371c9d4SSatish Balay   if (flg) {
7959371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
7969371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
7973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
798b77ba244SStefano Zampini }
799b77ba244SStefano Zampini 
800d71ae5a4SJacob 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)
801d71ae5a4SJacob Faibussowitsch {
802b77ba244SStefano Zampini   PetscBool               flg;
803b77ba244SStefano Zampini   Mat_Shell              *shell;
804b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
805b77ba244SStefano Zampini 
806b77ba244SStefano Zampini   PetscFunctionBegin;
80728b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
80828b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
809b77ba244SStefano Zampini 
810b77ba244SStefano Zampini   /* add product callback */
811b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
812b77ba244SStefano Zampini   matmat = shell->matmat;
813b77ba244SStefano Zampini   if (!matmat) {
8149566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
815b77ba244SStefano Zampini     matmat = shell->matmat;
816b77ba244SStefano Zampini   } else {
817b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
818b77ba244SStefano Zampini     while (entry) {
8199566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
820b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
821b77ba244SStefano Zampini       matmat = entry;
8222e956fe4SStefano Zampini       if (flg) goto set;
823b77ba244SStefano Zampini       entry = entry->next;
824b77ba244SStefano Zampini     }
8259566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
826b77ba244SStefano Zampini     matmat = matmat->next;
827b77ba244SStefano Zampini   }
828b77ba244SStefano Zampini 
829843d480fSStefano Zampini set:
830b77ba244SStefano Zampini   matmat->symbolic = symbolic;
831b77ba244SStefano Zampini   matmat->numeric  = numeric;
832b77ba244SStefano Zampini   matmat->destroy  = destroy;
833b77ba244SStefano Zampini   matmat->ptype    = ptype;
8349566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8359566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8369566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8379566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8389566063dSJacob 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"));
8399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
841b77ba244SStefano Zampini }
842b77ba244SStefano Zampini 
843b77ba244SStefano Zampini /*@C
84411a5261eSBarry Smith   MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
845b77ba244SStefano Zampini 
84627430b45SBarry Smith   Logically Collective; No Fortran Support
847b77ba244SStefano Zampini 
848b77ba244SStefano Zampini   Input Parameters:
84911a5261eSBarry Smith + A        - the `MATSHELL` shell matrix
850b77ba244SStefano Zampini . ptype    - the product type
8512ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
852b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8532ef1f0ffSBarry Smith . destroy  - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`)
854b77ba244SStefano Zampini . Btype    - the matrix type for the matrix to be multiplied against
8552ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
856b77ba244SStefano Zampini 
857b77ba244SStefano Zampini   Level: advanced
858b77ba244SStefano Zampini 
8592920cce0SJacob Faibussowitsch   Example Usage:
860cf53795eSBarry Smith .vb
861cf53795eSBarry Smith   extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**);
862cf53795eSBarry Smith   extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*);
863cf53795eSBarry Smith   extern PetscErrorCode userdestroy(void*);
8642920cce0SJacob Faibussowitsch 
865cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
8662920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
8672920cce0SJacob Faibussowitsch     A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE
8682920cce0SJacob Faibussowitsch   );
8692920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
8702920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
871cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
872cf53795eSBarry Smith   MatProductSetFromOptions(C);
8732920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
8742920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
8752920cce0SJacob Faibussowitsch   // use C = A * B
876cf53795eSBarry Smith .ve
877b77ba244SStefano Zampini 
878b77ba244SStefano Zampini   Notes:
879cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
88011a5261eSBarry Smith 
8812ef1f0ffSBarry 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`.
88211a5261eSBarry Smith 
883b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
884b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
885b77ba244SStefano Zampini   It is allowed to specify the same callbacks for different Btype matrix types.
88627430b45SBarry Smith   The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
887b77ba244SStefano Zampini 
8881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
889b77ba244SStefano Zampini @*/
890d71ae5a4SJacob 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)
891d71ae5a4SJacob Faibussowitsch {
892b77ba244SStefano Zampini   PetscFunctionBegin;
893b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
894b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
89508401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
89628b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
8974f572ea9SToby Isaac   PetscAssertPointer(Btype, 6);
8984f572ea9SToby Isaac   if (Ctype) PetscAssertPointer(Ctype, 7);
899cac4c232SBarry 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));
9003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
901b77ba244SStefano Zampini }
902b77ba244SStefano Zampini 
903d71ae5a4SJacob 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)
904d71ae5a4SJacob Faibussowitsch {
905b77ba244SStefano Zampini   PetscBool   flg;
906b77ba244SStefano Zampini   char        composedname[256];
907b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
908b77ba244SStefano Zampini   PetscMPIInt size;
909b77ba244SStefano Zampini 
910b77ba244SStefano Zampini   PetscFunctionBegin;
911b77ba244SStefano Zampini   PetscValidType(A, 1);
912b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
9139566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
914b77ba244SStefano Zampini     if (flg) break;
915b77ba244SStefano Zampini     Bnames = Bnames->next;
916b77ba244SStefano Zampini   }
917b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
9189566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
919b77ba244SStefano Zampini     if (flg) break;
920b77ba244SStefano Zampini     Cnames = Cnames->next;
921b77ba244SStefano Zampini   }
9229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
923b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
924b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9259566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9269566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
928e51e0e81SBarry Smith }
929e51e0e81SBarry Smith 
930d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
931d71ae5a4SJacob Faibussowitsch {
93228f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
933cb8c8a77SBarry Smith   PetscBool               matflg;
934b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9357fabda3fSAlex Fikl 
9367fabda3fSAlex Fikl   PetscFunctionBegin;
9379566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
93828b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9397fabda3fSAlex Fikl 
940aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
941aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9427fabda3fSAlex Fikl 
9431baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9447fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9457fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9460c0fd78eSBarry Smith   if (shellA->dshift) {
94748a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9489566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9497fabda3fSAlex Fikl   } else {
9509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9517fabda3fSAlex Fikl   }
9520c0fd78eSBarry Smith   if (shellA->left) {
95348a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9549566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9557fabda3fSAlex Fikl   } else {
9569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9577fabda3fSAlex Fikl   }
9580c0fd78eSBarry Smith   if (shellA->right) {
95948a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9609566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9617fabda3fSAlex Fikl   } else {
9629566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9637fabda3fSAlex Fikl   }
9649566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
965ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
966ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
96740e381c3SBarry Smith   if (shellA->axpy) {
9689566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
96940e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
97040e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
971ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
97240e381c3SBarry Smith   }
97345960306SStefano Zampini   if (shellA->zrows) {
9749566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
97548a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9769566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9779566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9789566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9809566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
98145960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
98245960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
98345960306SStefano Zampini   }
984b77ba244SStefano Zampini 
985b77ba244SStefano Zampini   matmatA = shellA->matmat;
986b77ba244SStefano Zampini   if (matmatA) {
987b77ba244SStefano Zampini     while (matmatA->next) {
9889566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
989b77ba244SStefano Zampini       matmatA = matmatA->next;
990b77ba244SStefano Zampini     }
991b77ba244SStefano Zampini   }
9923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9937fabda3fSAlex Fikl }
9947fabda3fSAlex Fikl 
995d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
996d71ae5a4SJacob Faibussowitsch {
997cb8c8a77SBarry Smith   PetscFunctionBegin;
998800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
999800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
1000800f99ffSJeremy L Thompson   PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
10019566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name));
100248a46eb9SPierre Jolivet   if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
10033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1004cb8c8a77SBarry Smith }
1005cb8c8a77SBarry Smith 
100666976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
1007d71ae5a4SJacob Faibussowitsch {
1008ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
100925578ef6SJed Brown   Vec              xx;
1010e3f487b0SBarry Smith   PetscObjectState instate, outstate;
1011ef66eb69SBarry Smith 
1012ef66eb69SBarry Smith   PetscFunctionBegin;
10139566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
10149566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
10159566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10169566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
10179566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1018e3f487b0SBarry Smith   if (instate == outstate) {
1019e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10209566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1021e3f487b0SBarry Smith   }
10229566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10239566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10249566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10259f137db4SBarry Smith 
10269f137db4SBarry Smith   if (shell->axpy) {
1027ef5c7bd2SStefano Zampini     Mat              X;
1028ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1029ef5c7bd2SStefano Zampini 
10309566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10319566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
103208401ef6SPierre 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,...)");
1033b77ba244SStefano Zampini 
10349566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10359566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10369566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10379566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10389f137db4SBarry Smith   }
10393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1040ef66eb69SBarry Smith }
1041ef66eb69SBarry Smith 
1042d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1043d71ae5a4SJacob Faibussowitsch {
10445edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10455edf6516SJed Brown 
10465edf6516SJed Brown   PetscFunctionBegin;
10475edf6516SJed Brown   if (y == z) {
10489566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10499566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10515edf6516SJed Brown   } else {
10529566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10539566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10545edf6516SJed Brown   }
10553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10565edf6516SJed Brown }
10575edf6516SJed Brown 
1058d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1059d71ae5a4SJacob Faibussowitsch {
106018be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
106125578ef6SJed Brown   Vec              xx;
1062e3f487b0SBarry Smith   PetscObjectState instate, outstate;
106318be62a5SSatish Balay 
106418be62a5SSatish Balay   PetscFunctionBegin;
10659566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
10669566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleLeft(A, xx, &xx));
10679566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10689566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10699566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1070e3f487b0SBarry Smith   if (instate == outstate) {
1071e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10729566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1073e3f487b0SBarry Smith   }
10749566063dSJacob Faibussowitsch   PetscCall(MatShellShiftAndScale(A, xx, y));
10759566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleRight(A, y));
10769566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1077350ec83bSStefano Zampini 
1078350ec83bSStefano Zampini   if (shell->axpy) {
1079ef5c7bd2SStefano Zampini     Mat              X;
1080ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1081ef5c7bd2SStefano Zampini 
10829566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10839566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
108408401ef6SPierre 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,...)");
10859566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10869566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10879566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10889566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1089350ec83bSStefano Zampini   }
10903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
109118be62a5SSatish Balay }
109218be62a5SSatish Balay 
1093d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1094d71ae5a4SJacob Faibussowitsch {
10955edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10965edf6516SJed Brown 
10975edf6516SJed Brown   PetscFunctionBegin;
10985edf6516SJed Brown   if (y == z) {
10999566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11009566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11019566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11025edf6516SJed Brown   } else {
11039566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11049566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11055edf6516SJed Brown   }
11063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11075edf6516SJed Brown }
11085edf6516SJed Brown 
11090c0fd78eSBarry Smith /*
11100c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11110c0fd78eSBarry Smith */
1112d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1113d71ae5a4SJacob Faibussowitsch {
111418be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
111518be62a5SSatish Balay 
111618be62a5SSatish Balay   PetscFunctionBegin;
11170c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11189566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1119305211d5SBarry 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,...)");
11209566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
11211baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
11229566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
11239566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
11249566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
112545960306SStefano Zampini   if (shell->zrows) {
11269566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
11279566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
112845960306SStefano Zampini   }
112981c02519SBarry Smith   if (shell->axpy) {
1130ef5c7bd2SStefano Zampini     Mat              X;
1131ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1132ef5c7bd2SStefano Zampini 
11339566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11349566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
113508401ef6SPierre 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,...)");
11369566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
11379566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
11389566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
113981c02519SBarry Smith   }
11403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114118be62a5SSatish Balay }
114218be62a5SSatish Balay 
1143d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1144d71ae5a4SJacob Faibussowitsch {
1145ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1146789d8953SBarry Smith   PetscBool  flg;
1147b24ad042SBarry Smith 
1148ef66eb69SBarry Smith   PetscFunctionBegin;
11499566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
115028b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
11510c0fd78eSBarry Smith   if (shell->left || shell->right) {
11528fe8eb27SJed Brown     if (!shell->dshift) {
11539566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11549566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
11550c0fd78eSBarry Smith     } else {
11569566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
11579566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
11589566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
11590c0fd78eSBarry Smith     }
11609566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
11619566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
11628fe8eb27SJed Brown   } else shell->vshift += a;
11631baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1165ef66eb69SBarry Smith }
1166ef66eb69SBarry Smith 
1167d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1168d71ae5a4SJacob Faibussowitsch {
11696464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
11706464bf51SAlex Fikl 
11716464bf51SAlex Fikl   PetscFunctionBegin;
11729566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
11730c0fd78eSBarry Smith   if (shell->left || shell->right) {
11749566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
11759f137db4SBarry Smith     if (shell->left && shell->right) {
11769566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11779566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
11789f137db4SBarry Smith     } else if (shell->left) {
11799566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
11809f137db4SBarry Smith     } else {
11819566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
11829f137db4SBarry Smith     }
11839566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
11840c0fd78eSBarry Smith   } else {
11859566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1186b253ae0bS“Marek   }
11873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1188b253ae0bS“Marek }
1189b253ae0bS“Marek 
119066976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1191d71ae5a4SJacob Faibussowitsch {
119245960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1193b253ae0bS“Marek   Vec        d;
1194789d8953SBarry Smith   PetscBool  flg;
1195b253ae0bS“Marek 
1196b253ae0bS“Marek   PetscFunctionBegin;
11979566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
119828b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1199b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12009566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12019566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12029566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12039566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12049566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12051baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1206b253ae0bS“Marek   } else {
12079566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12081baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12096464bf51SAlex Fikl   }
12103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12116464bf51SAlex Fikl }
12126464bf51SAlex Fikl 
1213d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1214d71ae5a4SJacob Faibussowitsch {
1215ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1216b24ad042SBarry Smith 
1217ef66eb69SBarry Smith   PetscFunctionBegin;
1218f4df32b1SMatthew Knepley   shell->vscale *= a;
12190c0fd78eSBarry Smith   shell->vshift *= a;
12201baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
122181c02519SBarry Smith   shell->axpy_vscale *= a;
12221baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122418be62a5SSatish Balay }
12258fe8eb27SJed Brown 
1226d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1227d71ae5a4SJacob Faibussowitsch {
12288fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12298fe8eb27SJed Brown 
12308fe8eb27SJed Brown   PetscFunctionBegin;
12318fe8eb27SJed Brown   if (left) {
12320c0fd78eSBarry Smith     if (!shell->left) {
12339566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12349566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12350c0fd78eSBarry Smith     } else {
12369566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
123718be62a5SSatish Balay     }
12381baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1239ef66eb69SBarry Smith   }
12408fe8eb27SJed Brown   if (right) {
12410c0fd78eSBarry Smith     if (!shell->right) {
12429566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
12439566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
12440c0fd78eSBarry Smith     } else {
12459566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
12468fe8eb27SJed Brown     }
124745960306SStefano Zampini     if (shell->zrows) {
124848a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
12499566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
12509566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12519566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12529566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
125345960306SStefano Zampini     }
12548fe8eb27SJed Brown   }
12551baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
12563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1257ef66eb69SBarry Smith }
1258ef66eb69SBarry Smith 
125966976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1260d71ae5a4SJacob Faibussowitsch {
1261ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1262ef66eb69SBarry Smith 
1263ef66eb69SBarry Smith   PetscFunctionBegin;
12648fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1265ef66eb69SBarry Smith     shell->vshift      = 0.0;
1266ef66eb69SBarry Smith     shell->vscale      = 1.0;
1267ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1268ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
12699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
12709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
12719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
12729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
12739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
12749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
12759566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
12769566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
12779566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
12789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1279ef66eb69SBarry Smith   }
12803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1281ef66eb69SBarry Smith }
1282ef66eb69SBarry Smith 
1283d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1284d71ae5a4SJacob Faibussowitsch {
12853b49f96aSBarry Smith   PetscFunctionBegin;
12863b49f96aSBarry Smith   *missing = PETSC_FALSE;
12873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12883b49f96aSBarry Smith }
12893b49f96aSBarry Smith 
129066976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1291d71ae5a4SJacob Faibussowitsch {
12929f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
12939f137db4SBarry Smith 
12949f137db4SBarry Smith   PetscFunctionBegin;
1295ef5c7bd2SStefano Zampini   if (X == Y) {
12969566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
12973ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1298ef5c7bd2SStefano Zampini   }
1299ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13009566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13019f137db4SBarry Smith     shell->axpy_vscale = a;
13029566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1303ef5c7bd2SStefano Zampini   } else {
13049566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1305ef5c7bd2SStefano Zampini   }
13063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13079f137db4SBarry Smith }
13089f137db4SBarry Smith 
1309f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1310f4259b30SLisandro Dalcin                                        NULL,
1311f4259b30SLisandro Dalcin                                        NULL,
1312f4259b30SLisandro Dalcin                                        NULL,
13130c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1314f4259b30SLisandro Dalcin                                        NULL,
13150c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1316f4259b30SLisandro Dalcin                                        NULL,
1317f4259b30SLisandro Dalcin                                        NULL,
1318f4259b30SLisandro Dalcin                                        NULL,
1319f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1320f4259b30SLisandro Dalcin                                        NULL,
1321f4259b30SLisandro Dalcin                                        NULL,
1322f4259b30SLisandro Dalcin                                        NULL,
1323f4259b30SLisandro Dalcin                                        NULL,
1324f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1325f4259b30SLisandro Dalcin                                        NULL,
1326f4259b30SLisandro Dalcin                                        NULL,
13278fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1328f4259b30SLisandro Dalcin                                        NULL,
1329f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1330ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1331f4259b30SLisandro Dalcin                                        NULL,
1332f4259b30SLisandro Dalcin                                        NULL,
133345960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1334f4259b30SLisandro Dalcin                                        NULL,
1335f4259b30SLisandro Dalcin                                        NULL,
1336f4259b30SLisandro Dalcin                                        NULL,
1337f4259b30SLisandro Dalcin                                        NULL,
1338f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1339f4259b30SLisandro Dalcin                                        NULL,
1340f4259b30SLisandro Dalcin                                        NULL,
1341f4259b30SLisandro Dalcin                                        NULL,
1342f4259b30SLisandro Dalcin                                        NULL,
1343cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1344f4259b30SLisandro Dalcin                                        NULL,
1345f4259b30SLisandro Dalcin                                        NULL,
1346f4259b30SLisandro Dalcin                                        NULL,
1347f4259b30SLisandro Dalcin                                        NULL,
13489f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1349f4259b30SLisandro Dalcin                                        NULL,
1350f4259b30SLisandro Dalcin                                        NULL,
1351f4259b30SLisandro Dalcin                                        NULL,
1352cb8c8a77SBarry Smith                                        MatCopy_Shell,
1353f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1354ef66eb69SBarry Smith                                        MatScale_Shell,
1355ef66eb69SBarry Smith                                        MatShift_Shell,
13566464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
135745960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1358f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1359f4259b30SLisandro Dalcin                                        NULL,
1360f4259b30SLisandro Dalcin                                        NULL,
1361f4259b30SLisandro Dalcin                                        NULL,
1362f4259b30SLisandro Dalcin                                        NULL,
1363f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1364f4259b30SLisandro Dalcin                                        NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
1368f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1369b9b97703SBarry Smith                                        MatDestroy_Shell,
1370f4259b30SLisandro Dalcin                                        NULL,
1371251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1374f4259b30SLisandro Dalcin                                        NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
1376f4259b30SLisandro Dalcin                                        NULL,
1377f4259b30SLisandro Dalcin                                        NULL,
1378f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1379f4259b30SLisandro Dalcin                                        NULL,
1380c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1381f4259b30SLisandro Dalcin                                        NULL,
1382f4259b30SLisandro Dalcin                                        NULL,
1383f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1384f4259b30SLisandro Dalcin                                        NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386f4259b30SLisandro Dalcin                                        NULL,
1387f4259b30SLisandro Dalcin                                        NULL,
1388f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1389f4259b30SLisandro Dalcin                                        NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        NULL,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1399f4259b30SLisandro Dalcin                                        NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        NULL,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1414f4259b30SLisandro Dalcin                                        NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
14223b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1423f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1424f4259b30SLisandro Dalcin                                        NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1434f4259b30SLisandro Dalcin                                        NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
1450d70f29a3SPierre Jolivet                                        NULL,
1451d70f29a3SPierre Jolivet                                        NULL,
1452d70f29a3SPierre Jolivet                                        NULL,
1453d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1454d70f29a3SPierre Jolivet                                        NULL,
1455d70f29a3SPierre Jolivet                                        NULL,
145699a7f59eSMark Adams                                        NULL,
145799a7f59eSMark Adams                                        NULL,
14587fb60732SBarry Smith                                        NULL,
1459dec0b466SHong Zhang                                        /*150*/ NULL,
1460dec0b466SHong Zhang                                        NULL};
1461273d9f13SBarry Smith 
1462d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1463d71ae5a4SJacob Faibussowitsch {
1464789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1465789d8953SBarry Smith 
1466789d8953SBarry Smith   PetscFunctionBegin;
1467800f99ffSJeremy L Thompson   if (ctx) {
1468800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1469800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1470800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1471800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1472800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1473800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1474800f99ffSJeremy L Thompson   } else {
1475800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1476800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1477800f99ffSJeremy L Thompson   }
1478800f99ffSJeremy L Thompson 
14793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1480800f99ffSJeremy L Thompson }
1481800f99ffSJeremy L Thompson 
148266976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1483d71ae5a4SJacob Faibussowitsch {
1484800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1485800f99ffSJeremy L Thompson 
1486800f99ffSJeremy L Thompson   PetscFunctionBegin;
1487800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
14883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1489789d8953SBarry Smith }
1490789d8953SBarry Smith 
1491d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1492d71ae5a4SJacob Faibussowitsch {
1493db77db73SJeremy L Thompson   PetscFunctionBegin;
14949566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
14959566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
14963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1497db77db73SJeremy L Thompson }
1498db77db73SJeremy L Thompson 
149966976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1500d71ae5a4SJacob Faibussowitsch {
1501789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1502789d8953SBarry Smith 
1503789d8953SBarry Smith   PetscFunctionBegin;
1504789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1505789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1506789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1507789d8953SBarry Smith   A->ops->scale              = NULL;
1508789d8953SBarry Smith   A->ops->shift              = NULL;
1509789d8953SBarry Smith   A->ops->axpy               = NULL;
15103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1511789d8953SBarry Smith }
1512789d8953SBarry Smith 
1513d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1514d71ae5a4SJacob Faibussowitsch {
1515feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1516789d8953SBarry Smith 
1517789d8953SBarry Smith   PetscFunctionBegin;
1518789d8953SBarry Smith   switch (op) {
1519d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1520d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1521d71ae5a4SJacob Faibussowitsch     break;
1522789d8953SBarry Smith   case MATOP_VIEW:
1523ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1524789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1525789d8953SBarry Smith     break;
1526d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1527d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1528d71ae5a4SJacob Faibussowitsch     break;
1529789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1530789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1531789d8953SBarry Smith   case MATOP_SHIFT:
1532789d8953SBarry Smith   case MATOP_SCALE:
1533789d8953SBarry Smith   case MATOP_AXPY:
1534789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1535789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
153628b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1537789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1538789d8953SBarry Smith     break;
1539789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1540789d8953SBarry Smith     if (shell->managescalingshifts) {
1541789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1542789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1543789d8953SBarry Smith     } else {
1544789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1545789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1546789d8953SBarry Smith     }
1547789d8953SBarry Smith     break;
1548789d8953SBarry Smith   case MATOP_MULT:
1549789d8953SBarry Smith     if (shell->managescalingshifts) {
1550789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1551789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1552789d8953SBarry Smith     } else {
1553789d8953SBarry Smith       shell->ops->mult = NULL;
1554789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1555789d8953SBarry Smith     }
1556789d8953SBarry Smith     break;
1557789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1558789d8953SBarry Smith     if (shell->managescalingshifts) {
1559789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1560789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1561789d8953SBarry Smith     } else {
1562789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1563789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1564789d8953SBarry Smith     }
1565789d8953SBarry Smith     break;
1566d71ae5a4SJacob Faibussowitsch   default:
1567d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1568d71ae5a4SJacob Faibussowitsch     break;
1569789d8953SBarry Smith   }
15703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1571789d8953SBarry Smith }
1572789d8953SBarry Smith 
1573d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1574d71ae5a4SJacob Faibussowitsch {
1575789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1576789d8953SBarry Smith 
1577789d8953SBarry Smith   PetscFunctionBegin;
1578789d8953SBarry Smith   switch (op) {
1579d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1580d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1581d71ae5a4SJacob Faibussowitsch     break;
1582d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1583d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1584d71ae5a4SJacob Faibussowitsch     break;
1585d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1586d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1587d71ae5a4SJacob Faibussowitsch     break;
1588789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1589789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1590789d8953SBarry Smith   case MATOP_SHIFT:
1591789d8953SBarry Smith   case MATOP_SCALE:
1592789d8953SBarry Smith   case MATOP_AXPY:
1593789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1594d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1595d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1596d71ae5a4SJacob Faibussowitsch     break;
1597789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
15989371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
15999371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1600789d8953SBarry Smith     break;
1601789d8953SBarry Smith   case MATOP_MULT:
16029371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
16039371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1604789d8953SBarry Smith     break;
1605789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
16069371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
16079371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1608789d8953SBarry Smith     break;
1609d71ae5a4SJacob Faibussowitsch   default:
1610d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1611789d8953SBarry Smith   }
16123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1613789d8953SBarry Smith }
1614789d8953SBarry Smith 
16150bad9183SKris Buschelman /*MC
161601c1178eSBarry Smith    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free.
16170bad9183SKris Buschelman 
16180bad9183SKris Buschelman   Level: advanced
16190bad9183SKris Buschelman 
16201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`
16210bad9183SKris Buschelman M*/
16220bad9183SKris Buschelman 
1623d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1624d71ae5a4SJacob Faibussowitsch {
1625273d9f13SBarry Smith   Mat_Shell *b;
1626273d9f13SBarry Smith 
1627273d9f13SBarry Smith   PetscFunctionBegin;
16284dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1629273d9f13SBarry Smith   A->data   = (void *)b;
1630aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1631273d9f13SBarry Smith 
1632800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1633ef66eb69SBarry Smith   b->vshift              = 0.0;
1634ef66eb69SBarry Smith   b->vscale              = 1.0;
16350c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1636273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1637210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
16382205254eSKarl Rupp 
16399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
16409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1641800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
16429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
16439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
16449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
16459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
16469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
16479566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
16483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1649273d9f13SBarry Smith }
1650e51e0e81SBarry Smith 
16514b828684SBarry Smith /*@C
165211a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1653ff756334SLois Curfman McInnes   private data storage format.
1654e51e0e81SBarry Smith 
1655d083f849SBarry Smith   Collective
1656c7fcc2eaSBarry Smith 
1657e51e0e81SBarry Smith   Input Parameters:
1658c7fcc2eaSBarry Smith + comm - MPI communicator
1659*45f401ebSJose E. Roman . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
1660*45f401ebSJose E. Roman . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
1661*45f401ebSJose E. Roman . M    - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given)
1662*45f401ebSJose E. Roman . N    - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given)
1663c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1664e51e0e81SBarry Smith 
1665ff756334SLois Curfman McInnes   Output Parameter:
166644cd7ae7SLois Curfman McInnes . A - the matrix
1667e51e0e81SBarry Smith 
1668ff2fd236SBarry Smith   Level: advanced
1669ff2fd236SBarry Smith 
16702920cce0SJacob Faibussowitsch   Example Usage:
167127430b45SBarry Smith .vb
167227430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
16732920cce0SJacob Faibussowitsch 
167427430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
167527430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
16762920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
167727430b45SBarry Smith   MatDestroy(mat);
167827430b45SBarry Smith .ve
1679f39d1f56SLois Curfman McInnes 
1680ff756334SLois Curfman McInnes   Notes:
1681ff756334SLois Curfman McInnes   The shell matrix type is intended to provide a simple class to use
168211a5261eSBarry Smith   with `KSP` (such as, for use with matrix-free methods). You should not
1683ff756334SLois Curfman McInnes   use the shell type if you plan to define a complete matrix class.
1684e51e0e81SBarry Smith 
1685f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1686f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
16872ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
168811a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1689645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1690645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1691645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1692645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1693645985a0SLois Curfman McInnes   For example,
1694f39d1f56SLois Curfman McInnes 
169527430b45SBarry Smith .vb
169627430b45SBarry Smith      Vec x, y
169727430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
169827430b45SBarry Smith      Mat A
169927430b45SBarry Smith 
170027430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
170127430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
170227430b45SBarry Smith      VecGetLocalSize(y,&m);
170327430b45SBarry Smith      VecGetLocalSize(x,&n);
170427430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
170527430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
170627430b45SBarry Smith      MatMult(A,x,y);
170727430b45SBarry Smith      MatDestroy(&A);
170827430b45SBarry Smith      VecDestroy(&y);
170927430b45SBarry Smith      VecDestroy(&x);
171027430b45SBarry Smith .ve
1711e51e0e81SBarry Smith 
17122ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
17132ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
17140c0fd78eSBarry Smith 
171527430b45SBarry Smith   Developer Notes:
17162ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
17172ef1f0ffSBarry Smith 
171895452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
17190c0fd78eSBarry Smith 
17200c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17210c0fd78eSBarry Smith 
17220c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
17230c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17240c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
17250c0fd78eSBarry Smith 
17260c0fd78eSBarry Smith   A is the user provided function.
17270c0fd78eSBarry Smith 
172827430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1729c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
173011a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
173111a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1732ad2f5c3fSBarry Smith 
173311a5261eSBarry Smith   Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1734b77ba244SStefano Zampini 
173511a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
173611a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1737ad2f5c3fSBarry Smith 
1738fe59aa6dSJacob Faibussowitsch   Fortran Notes:
17392ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
174011a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
17412ef1f0ffSBarry Smith   in as the `ctx` argument.
174211a5261eSBarry Smith 
1743fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1744e51e0e81SBarry Smith @*/
1745d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1746d71ae5a4SJacob Faibussowitsch {
17473a40ed3dSBarry Smith   PetscFunctionBegin;
17489566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
17499566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
17509566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
17519566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
17529566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
17533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1754c7fcc2eaSBarry Smith }
1755c7fcc2eaSBarry Smith 
1756c6866cfdSSatish Balay /*@
175711a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1758c7fcc2eaSBarry Smith 
1759c3339decSBarry Smith   Logically Collective
1760c7fcc2eaSBarry Smith 
1761273d9f13SBarry Smith   Input Parameters:
176211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1763273d9f13SBarry Smith - ctx - the context
1764273d9f13SBarry Smith 
1765273d9f13SBarry Smith   Level: advanced
1766273d9f13SBarry Smith 
1767fe59aa6dSJacob Faibussowitsch   Fortran Notes:
176827430b45SBarry Smith   You must write a Fortran interface definition for this
17692ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1770273d9f13SBarry Smith 
17711cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
17720bc0a719SBarry Smith @*/
1773d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1774d71ae5a4SJacob Faibussowitsch {
1775273d9f13SBarry Smith   PetscFunctionBegin;
17760700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1777cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
17783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1779e51e0e81SBarry Smith }
1780e51e0e81SBarry Smith 
1781fe59aa6dSJacob Faibussowitsch /*@C
178211a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1783800f99ffSJeremy L Thompson 
1784c3339decSBarry Smith   Logically Collective
1785800f99ffSJeremy L Thompson 
1786800f99ffSJeremy L Thompson   Input Parameters:
1787800f99ffSJeremy L Thompson + mat - the shell matrix
1788800f99ffSJeremy L Thompson - f   - the context destroy function
1789800f99ffSJeremy L Thompson 
179027430b45SBarry Smith   Level: advanced
179127430b45SBarry Smith 
1792800f99ffSJeremy L Thompson   Note:
1793800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
179411a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1795800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
179611a5261eSBarry Smith   the `MATSHELL` is duplicated.
1797800f99ffSJeremy L Thompson 
17981cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1799800f99ffSJeremy L Thompson @*/
1800d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1801d71ae5a4SJacob Faibussowitsch {
1802800f99ffSJeremy L Thompson   PetscFunctionBegin;
1803800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1804800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
18053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1806800f99ffSJeremy L Thompson }
1807800f99ffSJeremy L Thompson 
1808db77db73SJeremy L Thompson /*@C
18092ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1810db77db73SJeremy L Thompson 
18112ef1f0ffSBarry Smith   Logically Collective
1812db77db73SJeremy L Thompson 
1813db77db73SJeremy L Thompson   Input Parameters:
181411a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1815db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1816db77db73SJeremy L Thompson 
1817db77db73SJeremy L Thompson   Level: advanced
1818db77db73SJeremy L Thompson 
18191cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1820db77db73SJeremy L Thompson @*/
1821d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1822d71ae5a4SJacob Faibussowitsch {
1823db77db73SJeremy L Thompson   PetscFunctionBegin;
1824cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
18253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1826db77db73SJeremy L Thompson }
1827db77db73SJeremy L Thompson 
18280c0fd78eSBarry Smith /*@
182911a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
183011a5261eSBarry Smith   after `MatCreateShell()`
18310c0fd78eSBarry Smith 
183227430b45SBarry Smith   Logically Collective
18330c0fd78eSBarry Smith 
18340c0fd78eSBarry Smith   Input Parameter:
1835fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
18360c0fd78eSBarry Smith 
18370c0fd78eSBarry Smith   Level: advanced
18380c0fd78eSBarry Smith 
18391cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
18400c0fd78eSBarry Smith @*/
1841d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1842d71ae5a4SJacob Faibussowitsch {
18430c0fd78eSBarry Smith   PetscFunctionBegin;
18440c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1845cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
18463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18470c0fd78eSBarry Smith }
18480c0fd78eSBarry Smith 
1849c16cb8f2SBarry Smith /*@C
185011a5261eSBarry Smith   MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
1851f3b1f45cSBarry Smith 
1852cf53795eSBarry Smith   Logically Collective; No Fortran Support
1853f3b1f45cSBarry Smith 
1854f3b1f45cSBarry Smith   Input Parameters:
185511a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1856f3b1f45cSBarry Smith . f    - the function
185711a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1858f3b1f45cSBarry Smith - ctx  - an optional context for the function
1859f3b1f45cSBarry Smith 
1860f3b1f45cSBarry Smith   Output Parameter:
186111a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1862f3b1f45cSBarry Smith 
18633c7db156SBarry Smith   Options Database Key:
1864f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1865f3b1f45cSBarry Smith 
1866f3b1f45cSBarry Smith   Level: advanced
1867f3b1f45cSBarry Smith 
18681cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
1869f3b1f45cSBarry Smith @*/
1870d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1871d71ae5a4SJacob Faibussowitsch {
1872f3b1f45cSBarry Smith   PetscInt  m, n;
1873f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1874f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
187574e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1876f3b1f45cSBarry Smith 
1877f3b1f45cSBarry Smith   PetscFunctionBegin;
1878f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
18799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
18809566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
18819566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
18829566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
18839566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
1884f3b1f45cSBarry Smith 
18859566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
18869566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
1887f3b1f45cSBarry Smith 
18889566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
18899566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
18909566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
18919566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1892f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1893f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1894f3b1f45cSBarry Smith     if (v) {
189501c1178eSBarry Smith       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)));
18969566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
18979566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
18989566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
1899f3b1f45cSBarry Smith     }
1900f3b1f45cSBarry Smith   } else if (v) {
190101c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n"));
1902f3b1f45cSBarry Smith   }
1903f3b1f45cSBarry Smith   if (flg) *flg = flag;
19049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1909f3b1f45cSBarry Smith }
1910f3b1f45cSBarry Smith 
1911f3b1f45cSBarry Smith /*@C
191211a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
1913f3b1f45cSBarry Smith 
1914cf53795eSBarry Smith   Logically Collective; No Fortran Support
1915f3b1f45cSBarry Smith 
1916f3b1f45cSBarry Smith   Input Parameters:
191711a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1918f3b1f45cSBarry Smith . f    - the function
191911a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1920f3b1f45cSBarry Smith - ctx  - an optional context for the function
1921f3b1f45cSBarry Smith 
1922f3b1f45cSBarry Smith   Output Parameter:
192311a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1924f3b1f45cSBarry Smith 
19253c7db156SBarry Smith   Options Database Key:
1926f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1927f3b1f45cSBarry Smith 
1928f3b1f45cSBarry Smith   Level: advanced
1929f3b1f45cSBarry Smith 
19301cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1931f3b1f45cSBarry Smith @*/
1932d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1933d71ae5a4SJacob Faibussowitsch {
1934f3b1f45cSBarry Smith   Vec       x, y, z;
1935f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
1936f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1937f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
193874e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1939f3b1f45cSBarry Smith 
1940f3b1f45cSBarry Smith   PetscFunctionBegin;
1941f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
19429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
19439566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
19449566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
19459566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
19469566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
19479566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
19489566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
19499566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
19509566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
19519566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
19529566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
1953f3b1f45cSBarry Smith 
19549566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
19559566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
19569566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
19579566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1958f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1959f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1960f3b1f45cSBarry Smith     if (v) {
196101c1178eSBarry Smith       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)));
19629566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19639566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
19649566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
1965f3b1f45cSBarry Smith     }
1966f3b1f45cSBarry Smith   } else if (v) {
196701c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n"));
1968f3b1f45cSBarry Smith   }
1969f3b1f45cSBarry Smith   if (flg) *flg = flag;
19709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
19759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
19769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
19773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1978f3b1f45cSBarry Smith }
1979f3b1f45cSBarry Smith 
1980f3b1f45cSBarry Smith /*@C
198111a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
1982e51e0e81SBarry Smith 
1983c3339decSBarry Smith   Logically Collective
1984fee21e36SBarry Smith 
1985c7fcc2eaSBarry Smith   Input Parameters:
198611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1987c7fcc2eaSBarry Smith . op  - the name of the operation
1988789d8953SBarry Smith - g   - the function that provides the operation.
1989c7fcc2eaSBarry Smith 
199015091d37SBarry Smith   Level: advanced
199115091d37SBarry Smith 
19922920cce0SJacob Faibussowitsch   Example Usage:
1993c3339decSBarry Smith .vb
1994c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
19952920cce0SJacob Faibussowitsch 
1996c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
1997c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
1998c3339decSBarry Smith .ve
19990b627109SLois Curfman McInnes 
2000a62d957aSLois Curfman McInnes   Notes:
2001e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
20021c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2003a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
200411a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2005a62d957aSLois Curfman McInnes 
200611a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2007deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2008deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2009deebb3c3SLois Curfman McInnes   routines, e.g.,
2010a62d957aSLois Curfman McInnes $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2011a62d957aSLois Curfman McInnes 
20124aa34b0aSBarry Smith   In particular each function MUST return an error code of 0 on success and
20134aa34b0aSBarry Smith   nonzero on failure.
20144aa34b0aSBarry Smith 
2015a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
201611a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
201711a5261eSBarry Smith   set by `MatCreateShell()`.
2018a62d957aSLois Curfman McInnes 
20192ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
20202ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2021b77ba244SStefano Zampini 
2022fe59aa6dSJacob Faibussowitsch   Fortran Notes:
202311a5261eSBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2024c4762a1bSJed Brown   generate a matrix. See src/mat/tests/ex120f.F
2025501d9185SBarry Smith 
20261cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2027e51e0e81SBarry Smith @*/
2028d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2029d71ae5a4SJacob Faibussowitsch {
20303a40ed3dSBarry Smith   PetscFunctionBegin;
20310700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2032cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
20333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2034e51e0e81SBarry Smith }
2035f0479e8cSBarry Smith 
2036d4bb536fSBarry Smith /*@C
203711a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2038d4bb536fSBarry Smith 
2039c7fcc2eaSBarry Smith   Not Collective
2040c7fcc2eaSBarry Smith 
2041d4bb536fSBarry Smith   Input Parameters:
204211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2043c7fcc2eaSBarry Smith - op  - the name of the operation
2044d4bb536fSBarry Smith 
2045d4bb536fSBarry Smith   Output Parameter:
2046789d8953SBarry Smith . g - the function that provides the operation.
2047d4bb536fSBarry Smith 
204815091d37SBarry Smith   Level: advanced
204915091d37SBarry Smith 
205027430b45SBarry Smith   Notes:
2051e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2052d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2053d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
205411a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2055d4bb536fSBarry Smith 
2056d4bb536fSBarry Smith   All user-provided functions have the same calling
2057d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2058d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2059d4bb536fSBarry Smith   routines, e.g.,
2060d4bb536fSBarry Smith $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2061d4bb536fSBarry Smith 
2062d4bb536fSBarry Smith   Within each user-defined routine, the user should call
206311a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
206411a5261eSBarry Smith   set by `MatCreateShell()`.
2065d4bb536fSBarry Smith 
20661cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2067d4bb536fSBarry Smith @*/
2068d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2069d71ae5a4SJacob Faibussowitsch {
20703a40ed3dSBarry Smith   PetscFunctionBegin;
20710700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2072cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
20733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2074d4bb536fSBarry Smith }
2075b77ba244SStefano Zampini 
2076b77ba244SStefano Zampini /*@
207711a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2078b77ba244SStefano Zampini 
2079b77ba244SStefano Zampini   Input Parameter:
2080b77ba244SStefano Zampini . mat - the matrix
2081b77ba244SStefano Zampini 
2082b77ba244SStefano Zampini   Output Parameter:
2083b77ba244SStefano Zampini . flg - the boolean value
2084b77ba244SStefano Zampini 
2085b77ba244SStefano Zampini   Level: developer
2086b77ba244SStefano Zampini 
2087fe59aa6dSJacob Faibussowitsch   Developer Notes:
20882ef1f0ffSBarry Smith   In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices
20892ef1f0ffSBarry Smith   (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc)
2090b77ba244SStefano Zampini 
20911cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2092b77ba244SStefano Zampini @*/
2093d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2094d71ae5a4SJacob Faibussowitsch {
2095b77ba244SStefano Zampini   PetscFunctionBegin;
2096b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
20974f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
2098b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
20993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2100b77ba244SStefano Zampini }
2101