xref: /petsc/src/mat/impls/shell/shell.c (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
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 
786a9fd05SPierre Jolivet #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/
80c0fd78eSBarry Smith 
945960306SStefano Zampini /*
1045960306SStefano Zampini      Store and scale values on zeroed rows
1145960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed columns
1245960306SStefano Zampini */
13d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx)
14d71ae5a4SJacob Faibussowitsch {
1545960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1645960306SStefano Zampini 
1745960306SStefano Zampini   PetscFunctionBegin;
1845960306SStefano Zampini   *xx = x;
1945960306SStefano Zampini   if (shell->zrows) {
209566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
219566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
229566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
239566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
2445960306SStefano Zampini   }
2545960306SStefano Zampini   if (shell->zcols) {
2648a46eb9SPierre Jolivet     if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
279566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->right_work));
289566063dSJacob Faibussowitsch     PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0));
2945960306SStefano Zampini     *xx = shell->right_work;
3045960306SStefano Zampini   }
313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3245960306SStefano Zampini }
3345960306SStefano Zampini 
3445960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
35d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x)
36d71ae5a4SJacob Faibussowitsch {
3745960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
3845960306SStefano Zampini 
3945960306SStefano Zampini   PetscFunctionBegin;
4045960306SStefano Zampini   if (shell->zrows) {
419566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
429566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE));
4345960306SStefano Zampini   }
443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4545960306SStefano Zampini }
4645960306SStefano Zampini 
4745960306SStefano Zampini /*
4845960306SStefano Zampini      Store and scale values on zeroed rows
4945960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
5045960306SStefano Zampini */
51d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx)
52d71ae5a4SJacob Faibussowitsch {
5345960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
5445960306SStefano Zampini 
5545960306SStefano Zampini   PetscFunctionBegin;
5645960306SStefano Zampini   *xx = NULL;
5745960306SStefano Zampini   if (!shell->zrows) {
5845960306SStefano Zampini     *xx = x;
5945960306SStefano Zampini   } else {
6048a46eb9SPierre Jolivet     if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
619566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->left_work));
629566063dSJacob Faibussowitsch     PetscCall(VecSet(shell->zvals_w, 0.0));
639566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
649566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE));
659566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
669566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
679566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals));
6845960306SStefano Zampini     *xx = shell->left_work;
6945960306SStefano Zampini   }
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7145960306SStefano Zampini }
7245960306SStefano Zampini 
7345960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
74d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x)
75d71ae5a4SJacob Faibussowitsch {
7645960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
7745960306SStefano Zampini 
7845960306SStefano Zampini   PetscFunctionBegin;
791baa6e33SBarry Smith   if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0));
8045960306SStefano Zampini   if (shell->zrows) {
819566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
829566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE));
8345960306SStefano Zampini   }
843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8545960306SStefano Zampini }
8645960306SStefano Zampini 
878fe8eb27SJed Brown /*
880c0fd78eSBarry Smith       xx = diag(left)*x
898fe8eb27SJed Brown */
90f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx, PetscBool conjugate)
91d71ae5a4SJacob Faibussowitsch {
928fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
938fe8eb27SJed Brown 
948fe8eb27SJed Brown   PetscFunctionBegin;
950298fd71SBarry Smith   *xx = NULL;
968fe8eb27SJed Brown   if (!shell->left) {
978fe8eb27SJed Brown     *xx = x;
988fe8eb27SJed Brown   } else {
999566063dSJacob Faibussowitsch     if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work));
100f8e07d23SBlanca Mellado Pinto     if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */
101f8e07d23SBlanca Mellado Pinto       PetscInt           i, m;
102f8e07d23SBlanca Mellado Pinto       const PetscScalar *d, *xarray;
103f8e07d23SBlanca Mellado Pinto       PetscScalar       *w;
104f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetLocalSize(x, &m));
105f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(shell->left, &d));
106f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(x, &xarray));
107f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayWrite(shell->left_work, &w));
108f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) w[i] = PetscConj(d[i]) * xarray[i];
109f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(shell->dshift, &d));
110f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(x, &xarray));
111f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayWrite(shell->left_work, &w));
112f8e07d23SBlanca Mellado Pinto     } else PetscCall(VecPointwiseMult(shell->left_work, x, shell->left));
1138fe8eb27SJed Brown     *xx = shell->left_work;
1148fe8eb27SJed Brown   }
1153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1168fe8eb27SJed Brown }
1178fe8eb27SJed Brown 
1180c0fd78eSBarry Smith /*
1190c0fd78eSBarry Smith      xx = diag(right)*x
1200c0fd78eSBarry Smith */
121d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx)
122d71ae5a4SJacob Faibussowitsch {
1238fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1248fe8eb27SJed Brown 
1258fe8eb27SJed Brown   PetscFunctionBegin;
1260298fd71SBarry Smith   *xx = NULL;
1278fe8eb27SJed Brown   if (!shell->right) {
1288fe8eb27SJed Brown     *xx = x;
1298fe8eb27SJed Brown   } else {
1309566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work));
1319566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->right_work, x, shell->right));
1328fe8eb27SJed Brown     *xx = shell->right_work;
1338fe8eb27SJed Brown   }
1343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1358fe8eb27SJed Brown }
1368fe8eb27SJed Brown 
1370c0fd78eSBarry Smith /*
1380c0fd78eSBarry Smith     x = diag(left)*x
1390c0fd78eSBarry Smith */
140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x)
141d71ae5a4SJacob Faibussowitsch {
1428fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1438fe8eb27SJed Brown 
1448fe8eb27SJed Brown   PetscFunctionBegin;
1459566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left));
1463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1478fe8eb27SJed Brown }
1488fe8eb27SJed Brown 
1490c0fd78eSBarry Smith /*
1500c0fd78eSBarry Smith     x = diag(right)*x
1510c0fd78eSBarry Smith */
152f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x, PetscBool conjugate)
153d71ae5a4SJacob Faibussowitsch {
1548fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
1558fe8eb27SJed Brown 
1568fe8eb27SJed Brown   PetscFunctionBegin;
157f8e07d23SBlanca Mellado Pinto   if (shell->right) {
158f8e07d23SBlanca Mellado Pinto     if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */
159f8e07d23SBlanca Mellado Pinto       PetscInt           i, m;
160f8e07d23SBlanca Mellado Pinto       const PetscScalar *d;
161f8e07d23SBlanca Mellado Pinto       PetscScalar       *xarray;
162f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetLocalSize(x, &m));
163f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArrayRead(shell->right, &d));
164f8e07d23SBlanca Mellado Pinto       PetscCall(VecGetArray(x, &xarray));
165f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) xarray[i] = PetscConj(d[i]) * xarray[i];
166f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArrayRead(shell->dshift, &d));
167f8e07d23SBlanca Mellado Pinto       PetscCall(VecRestoreArray(x, &xarray));
168f8e07d23SBlanca Mellado Pinto     } else PetscCall(VecPointwiseMult(x, x, shell->right));
169f8e07d23SBlanca Mellado Pinto   }
1703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1718fe8eb27SJed Brown }
1728fe8eb27SJed Brown 
1730c0fd78eSBarry Smith /*
1740c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
1750c0fd78eSBarry Smith 
1760c0fd78eSBarry Smith          On input Y already contains A*x
177f8e07d23SBlanca Mellado Pinto 
178f8e07d23SBlanca Mellado Pinto          If conjugate=PETSC_TRUE then vscale, dshift, and vshift are conjugated
1790c0fd78eSBarry Smith */
180f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y, PetscBool conjugate)
181d71ae5a4SJacob Faibussowitsch {
1828fe8eb27SJed Brown   Mat_Shell  *shell  = (Mat_Shell *)A->data;
183f8e07d23SBlanca Mellado Pinto   PetscScalar vscale = conjugate ? PetscConj(shell->vscale) : shell->vscale;
184f8e07d23SBlanca Mellado Pinto   PetscScalar vshift = conjugate ? PetscConj(shell->vshift) : shell->vshift;
1858fe8eb27SJed Brown 
1868fe8eb27SJed Brown   PetscFunctionBegin;
1878fe8eb27SJed Brown   if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */
1888fe8eb27SJed Brown     PetscInt           i, m;
1898fe8eb27SJed Brown     const PetscScalar *x, *d;
1908fe8eb27SJed Brown     PetscScalar       *y;
1919566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X, &m));
1929566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->dshift, &d));
1939566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(X, &x));
1949566063dSJacob Faibussowitsch     PetscCall(VecGetArray(Y, &y));
195f8e07d23SBlanca Mellado Pinto     if (conjugate)
196f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) y[i] = vscale * y[i] + PetscConj(d[i]) * x[i];
197f8e07d23SBlanca Mellado Pinto     else
198f8e07d23SBlanca Mellado Pinto       for (i = 0; i < m; i++) y[i] = vscale * y[i] + d[i] * x[i];
1999566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->dshift, &d));
2009566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(X, &x));
2019566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(Y, &y));
2020c0fd78eSBarry Smith   } else {
203f8e07d23SBlanca Mellado Pinto     PetscCall(VecScale(Y, vscale));
2048fe8eb27SJed Brown   }
205f8e07d23SBlanca Mellado Pinto   if (vshift != 0.0) PetscCall(VecAXPY(Y, vshift, X)); /* if test is for non-square matrices */
2063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2078fe8eb27SJed Brown }
208e51e0e81SBarry Smith 
209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx)
210d71ae5a4SJacob Faibussowitsch {
211800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
212800f99ffSJeremy L Thompson 
213789d8953SBarry Smith   PetscFunctionBegin;
214800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx));
215800f99ffSJeremy L Thompson   else *(void **)ctx = NULL;
2163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
217789d8953SBarry Smith }
218789d8953SBarry Smith 
2199d225801SJed Brown /*@
22011a5261eSBarry Smith   MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix.
221b4fd4287SBarry Smith 
222c7fcc2eaSBarry Smith   Not Collective
223c7fcc2eaSBarry Smith 
224b4fd4287SBarry Smith   Input Parameter:
22511a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()`
226b4fd4287SBarry Smith 
227b4fd4287SBarry Smith   Output Parameter:
228b4fd4287SBarry Smith . ctx - the user provided context
229b4fd4287SBarry Smith 
23015091d37SBarry Smith   Level: advanced
23115091d37SBarry Smith 
232fe59aa6dSJacob Faibussowitsch   Fortran Notes:
23327430b45SBarry Smith   You must write a Fortran interface definition for this
234daf670e6SBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
235a62d957aSLois Curfman McInnes 
2361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2370bc0a719SBarry Smith @*/
238d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx)
239d71ae5a4SJacob Faibussowitsch {
2403a40ed3dSBarry Smith   PetscFunctionBegin;
2410700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2424f572ea9SToby Isaac   PetscAssertPointer(ctx, 2);
243cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx));
2443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
245b4fd4287SBarry Smith }
246b4fd4287SBarry Smith 
247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc)
248d71ae5a4SJacob Faibussowitsch {
24945960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell *)mat->data;
25045960306SStefano Zampini   Vec             x = NULL, b = NULL;
25145960306SStefano Zampini   IS              is1, is2;
25245960306SStefano Zampini   const PetscInt *ridxs;
25345960306SStefano Zampini   PetscInt       *idxs, *gidxs;
25445960306SStefano Zampini   PetscInt        cum, rst, cst, i;
25545960306SStefano Zampini 
25645960306SStefano Zampini   PetscFunctionBegin;
25748a46eb9SPierre Jolivet   if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals));
25848a46eb9SPierre Jolivet   if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w));
2599566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat, &rst, NULL));
2609566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL));
26145960306SStefano Zampini 
26245960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &idxs));
26445960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
2659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1));
2669566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2679566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals, is1, diag));
26845960306SStefano Zampini   if (shell->zrows) {
2699566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows, is1, &is2));
2709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
2719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
27245960306SStefano Zampini     shell->zrows = is2;
27345960306SStefano Zampini   } else shell->zrows = is1;
27445960306SStefano Zampini 
27545960306SStefano Zampini   /* Create scatters for diagonal values communications */
2769566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
2779566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
27845960306SStefano Zampini 
27945960306SStefano Zampini   /* row scatter: from/to left vector */
2809566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &b));
2819566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r));
28245960306SStefano Zampini 
28345960306SStefano Zampini   /* col scatter: from right vector to left vector */
2849566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows, &ridxs));
2859566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows, &nr));
2869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &gidxs));
28745960306SStefano Zampini   for (i = 0, cum = 0; i < nr; i++) {
28845960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
28945960306SStefano Zampini     gidxs[cum] = ridxs[i];
29045960306SStefano Zampini     cum++;
29145960306SStefano Zampini   }
2929566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1));
2939566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c));
2949566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
2959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
2969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
29745960306SStefano Zampini 
29845960306SStefano Zampini   /* Expand/create index set of zeroed columns */
29945960306SStefano Zampini   if (rc) {
3009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc, &idxs));
30145960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
3029566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1));
3039566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
30445960306SStefano Zampini     if (shell->zcols) {
3059566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols, is1, &is2));
3069566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3079566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
30845960306SStefano Zampini       shell->zcols = is2;
30945960306SStefano Zampini     } else shell->zcols = is1;
31045960306SStefano Zampini   }
3113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31245960306SStefano Zampini }
31345960306SStefano Zampini 
314d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
315d71ae5a4SJacob Faibussowitsch {
316ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
31745960306SStefano Zampini   PetscInt   nr, *lrows;
31845960306SStefano Zampini 
31945960306SStefano Zampini   PetscFunctionBegin;
32045960306SStefano Zampini   if (x && b) {
32145960306SStefano Zampini     Vec          xt;
32245960306SStefano Zampini     PetscScalar *vals;
32345960306SStefano Zampini     PetscInt    *gcols, i, st, nl, nc;
32445960306SStefano Zampini 
3259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &gcols));
3269371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3279371c9d4SSatish Balay       if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
32845960306SStefano Zampini 
3299566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, NULL));
3309566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3319566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc, &vals));
3329566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3339566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3349566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3359566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3369566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */
33745960306SStefano Zampini 
3389566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3399566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3409566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
34145960306SStefano Zampini     for (i = 0; i < nl; i++) {
34245960306SStefano Zampini       PetscInt g = i + st;
34345960306SStefano Zampini       if (g > mat->rmap->N) continue;
34445960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3459566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES));
34645960306SStefano Zampini     }
3479566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
3489566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1, x2 * diag] */
3509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3519566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
35245960306SStefano Zampini   }
3539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL));
3549566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE));
3551baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL));
3569566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35845960306SStefano Zampini }
35945960306SStefano Zampini 
360d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b)
361d71ae5a4SJacob Faibussowitsch {
362ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
36345960306SStefano Zampini   PetscInt  *lrows, *lcols;
36445960306SStefano Zampini   PetscInt   nr, nc;
36545960306SStefano Zampini   PetscBool  congruent;
36645960306SStefano Zampini 
36745960306SStefano Zampini   PetscFunctionBegin;
36845960306SStefano Zampini   if (x && b) {
36945960306SStefano Zampini     Vec          xt, bt;
37045960306SStefano Zampini     PetscScalar *vals;
37145960306SStefano Zampini     PetscInt    *grows, *gcols, i, st, nl;
37245960306SStefano Zampini 
3739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n, &grows, n, &gcols));
3749371c9d4SSatish Balay     for (i = 0, nr = 0; i < n; i++)
3759371c9d4SSatish Balay       if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
3769371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3779371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
3789566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &vals));
37945960306SStefano Zampini 
3809566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, &bt));
3819566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3829566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3839566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3849566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3859566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt, -1.0, x));                             /* xt = [0, -x2] */
3869566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, xt, bt));                             /* bt = [-A12*x2,-A22*x2] */
3879566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */
3889566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
3899566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
3909566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b, 1.0, bt));                              /* b  = [b1 - A12*x2, b2] */
3919566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
3929566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
3939566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
3949566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
39545960306SStefano Zampini 
3969566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3979566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3989566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
39945960306SStefano Zampini     for (i = 0; i < nl; i++) {
40045960306SStefano Zampini       PetscInt g = i + st;
40145960306SStefano Zampini       if (g > mat->rmap->N) continue;
40245960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4039566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES));
40445960306SStefano Zampini     }
4059566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4069566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4079566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1 - A12*x2, x2 * diag] */
4089566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4099566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4109566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows, gcols));
41145960306SStefano Zampini   }
4129566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL));
4139566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat, &congruent));
41445960306SStefano Zampini   if (congruent) {
41545960306SStefano Zampini     nc    = nr;
41645960306SStefano Zampini     lcols = lrows;
41745960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
41845960306SStefano Zampini     PetscInt i, nt, *t;
41945960306SStefano Zampini 
4209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &t));
4219371c9d4SSatish Balay     for (i = 0, nt = 0; i < n; i++)
4229371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4239566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL));
4249566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
42545960306SStefano Zampini   }
4269566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE));
42748a46eb9SPierre Jolivet   if (!congruent) PetscCall(PetscFree(lcols));
4289566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4291baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL));
4303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43145960306SStefano Zampini }
43245960306SStefano Zampini 
433d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat)
434d71ae5a4SJacob Faibussowitsch {
435bf0cc555SLisandro Dalcin   Mat_Shell              *shell = (Mat_Shell *)mat->data;
436b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
437ed3cc1f0SBarry Smith 
4383a40ed3dSBarry Smith   PetscFunctionBegin;
4391baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4409566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps)));
4419566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4539566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4549566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4559566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4569566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
457b77ba244SStefano Zampini 
458b77ba244SStefano Zampini   matmat = shell->matmat;
459b77ba244SStefano Zampini   while (matmat) {
460b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
461b77ba244SStefano Zampini 
4629566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL));
4639566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
4649566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
4659566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
466b77ba244SStefano Zampini     matmat = next;
467b77ba244SStefano Zampini   }
468800f99ffSJeremy L Thompson   PetscCall(MatShellSetContext(mat, NULL));
4699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL));
4709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL));
471800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL));
4729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL));
4739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL));
4749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
4759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
4769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
4779566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
4783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
479b77ba244SStefano Zampini }
480b77ba244SStefano Zampini 
481b77ba244SStefano Zampini typedef struct {
482b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
483b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
484b77ba244SStefano Zampini   void *userdata;
485b77ba244SStefano Zampini   Mat   B;
486b77ba244SStefano Zampini   Mat   Bt;
487b77ba244SStefano Zampini   Mat   axpy;
488b77ba244SStefano Zampini } MatMatDataShell;
489b77ba244SStefano Zampini 
490d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data)
491d71ae5a4SJacob Faibussowitsch {
492b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
493b77ba244SStefano Zampini 
494b77ba244SStefano Zampini   PetscFunctionBegin;
4951baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
4969566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
4979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
4989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
4999566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
501b77ba244SStefano Zampini }
502b77ba244SStefano Zampini 
503d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
504d71ae5a4SJacob Faibussowitsch {
505b77ba244SStefano Zampini   Mat_Product     *product;
506b77ba244SStefano Zampini   Mat              A, B;
507b77ba244SStefano Zampini   MatMatDataShell *mdata;
508b77ba244SStefano Zampini   PetscScalar      zero = 0.0;
509b77ba244SStefano Zampini 
510b77ba244SStefano Zampini   PetscFunctionBegin;
511b77ba244SStefano Zampini   MatCheckProduct(D, 1);
512b77ba244SStefano Zampini   product = D->product;
51328b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
514b77ba244SStefano Zampini   A     = product->A;
515b77ba244SStefano Zampini   B     = product->B;
516b77ba244SStefano Zampini   mdata = (MatMatDataShell *)product->data;
517b77ba244SStefano Zampini   if (mdata->numeric) {
518b77ba244SStefano Zampini     Mat_Shell *shell                = (Mat_Shell *)A->data;
519b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
520b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
521b77ba244SStefano Zampini     PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
522b77ba244SStefano Zampini 
523b77ba244SStefano Zampini     if (shell->managescalingshifts) {
52408401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
525b77ba244SStefano Zampini       if (shell->right || shell->left) {
526b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
527b77ba244SStefano Zampini         if (!mdata->B) {
5289566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
529b77ba244SStefano Zampini         } else {
530b77ba244SStefano Zampini           newB = PETSC_FALSE;
531b77ba244SStefano Zampini         }
5329566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
533b77ba244SStefano Zampini       }
534b77ba244SStefano Zampini       switch (product->type) {
535b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5361baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
537b77ba244SStefano Zampini         break;
538b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5391baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
540b77ba244SStefano Zampini         break;
541b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5421baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
543b77ba244SStefano Zampini         break;
544b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
545b77ba244SStefano Zampini         if (shell->right && shell->left) {
546b77ba244SStefano Zampini           PetscBool flg;
547b77ba244SStefano Zampini 
5489566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5499371c9d4SSatish 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,
5509371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
551b77ba244SStefano Zampini         }
5521baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
553b77ba244SStefano Zampini         break;
554b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
555b77ba244SStefano Zampini         if (shell->right && shell->left) {
556b77ba244SStefano Zampini           PetscBool flg;
557b77ba244SStefano Zampini 
5589566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5599371c9d4SSatish 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,
5609371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
561b77ba244SStefano Zampini         }
5621baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
563b77ba244SStefano Zampini         break;
564d71ae5a4SJacob Faibussowitsch       default:
565d71ae5a4SJacob 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);
566b77ba244SStefano Zampini       }
567b77ba244SStefano Zampini     }
568b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
569b77ba244SStefano Zampini     D->product              = NULL;
570b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
571b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
572b77ba244SStefano Zampini 
5739566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata));
574b77ba244SStefano Zampini 
575b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
5769566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
577b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
578b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
579b77ba244SStefano Zampini     D->product              = product;
580b77ba244SStefano Zampini 
581b77ba244SStefano Zampini     if (shell->managescalingshifts) {
5829566063dSJacob Faibussowitsch       PetscCall(MatScale(D, shell->vscale));
583b77ba244SStefano Zampini       switch (product->type) {
584b77ba244SStefano Zampini       case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
585b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
586b77ba244SStefano Zampini         if (shell->left) {
5879566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->left, NULL));
588b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
5899566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
590b77ba244SStefano Zampini             if (shell->dshift) {
5919566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->left_work));
5929566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work, shell->vshift));
5939566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
594b77ba244SStefano Zampini             } else {
5959566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work, shell->vshift));
596b77ba244SStefano Zampini             }
597b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
598b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
599b77ba244SStefano Zampini               MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
600b77ba244SStefano Zampini 
6019566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6029566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6039566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
604b77ba244SStefano Zampini             } else {
605b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
606b77ba244SStefano Zampini 
6079566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6089566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->B, str));
609b77ba244SStefano Zampini             }
610b77ba244SStefano Zampini           }
611b77ba244SStefano Zampini         }
612b77ba244SStefano Zampini         break;
613b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
614b77ba244SStefano Zampini         if (shell->right) {
6159566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->right, NULL));
616b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
617b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
618b77ba244SStefano Zampini 
6199566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
620b77ba244SStefano Zampini             if (shell->dshift) {
6219566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->right_work));
6229566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work, shell->vshift));
6239566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
624b77ba244SStefano Zampini             } else {
6259566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work, shell->vshift));
626b77ba244SStefano Zampini             }
6279566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6289566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
629b77ba244SStefano Zampini           }
630b77ba244SStefano Zampini         }
631b77ba244SStefano Zampini         break;
632b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
633b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6349371c9d4SSatish 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,
6359371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
636b77ba244SStefano Zampini         break;
637d71ae5a4SJacob Faibussowitsch       default:
638d71ae5a4SJacob 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);
639b77ba244SStefano Zampini       }
640b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
641b77ba244SStefano Zampini         Mat              X;
642b77ba244SStefano Zampini         PetscObjectState axpy_state;
643b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
644b77ba244SStefano Zampini 
6459566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy, &X));
6469566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
64708401ef6SPierre 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,...)");
648b77ba244SStefano Zampini         if (!mdata->axpy) {
649b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
6509566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
6519566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy, product->type));
6529566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6539566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
654b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
655b77ba244SStefano Zampini           PetscBool flg;
656b77ba244SStefano Zampini 
6579566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
6589566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
659b77ba244SStefano Zampini           if (!flg) {
660b77ba244SStefano Zampini             str = DIFFERENT_NONZERO_PATTERN;
6619566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
6629566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
663b77ba244SStefano Zampini           }
664b77ba244SStefano Zampini         }
6659566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
6669566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
667b77ba244SStefano Zampini       }
668b77ba244SStefano Zampini     }
669b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
6703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
671b77ba244SStefano Zampini }
672b77ba244SStefano Zampini 
673d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
674d71ae5a4SJacob Faibussowitsch {
675b77ba244SStefano Zampini   Mat_Product            *product;
676b77ba244SStefano Zampini   Mat                     A, B;
677b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
678b77ba244SStefano Zampini   Mat_Shell              *shell;
679eae3dc7dSJacob Faibussowitsch   PetscBool               flg = PETSC_FALSE;
680b77ba244SStefano Zampini   char                    composedname[256];
681b77ba244SStefano Zampini   MatMatDataShell        *mdata;
682b77ba244SStefano Zampini 
683b77ba244SStefano Zampini   PetscFunctionBegin;
684b77ba244SStefano Zampini   MatCheckProduct(D, 1);
685b77ba244SStefano Zampini   product = D->product;
68628b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
687b77ba244SStefano Zampini   A      = product->A;
688b77ba244SStefano Zampini   B      = product->B;
689b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
690b77ba244SStefano Zampini   matmat = shell->matmat;
6919566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
692b77ba244SStefano Zampini   while (matmat) {
6939566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
694b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
695b77ba244SStefano Zampini     if (flg) break;
696b77ba244SStefano Zampini     matmat = matmat->next;
697b77ba244SStefano Zampini   }
69828b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
699b77ba244SStefano Zampini   switch (product->type) {
700d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
701d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
702d71ae5a4SJacob Faibussowitsch     break;
703d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
704d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
705d71ae5a4SJacob Faibussowitsch     break;
706d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
707d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
708d71ae5a4SJacob Faibussowitsch     break;
709d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
710d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
711d71ae5a4SJacob Faibussowitsch     break;
712d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
713d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
714d71ae5a4SJacob Faibussowitsch     break;
715d71ae5a4SJacob Faibussowitsch   default:
716d71ae5a4SJacob 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);
717b77ba244SStefano Zampini   }
718b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
719b77ba244SStefano Zampini   if (matmat->resultname) {
7209566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
72148a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
722b77ba244SStefano Zampini   }
723b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
724b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
725b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
726b77ba244SStefano Zampini   /* attach product data */
7279566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
728b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
729b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
730b77ba244SStefano Zampini   if (matmat->symbolic) {
7319566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata));
732b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7339566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
734b77ba244SStefano Zampini   }
73528b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
73628b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
737b77ba244SStefano Zampini   D->product->data    = mdata;
738b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
739b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
740b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
741b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
743b77ba244SStefano Zampini }
744b77ba244SStefano Zampini 
745d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
746d71ae5a4SJacob Faibussowitsch {
747b77ba244SStefano Zampini   Mat_Product            *product;
748b77ba244SStefano Zampini   Mat                     A, B;
749b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
750b77ba244SStefano Zampini   Mat_Shell              *shell;
751b77ba244SStefano Zampini   PetscBool               flg;
752b77ba244SStefano Zampini   char                    composedname[256];
753b77ba244SStefano Zampini 
754b77ba244SStefano Zampini   PetscFunctionBegin;
755b77ba244SStefano Zampini   MatCheckProduct(D, 1);
756b77ba244SStefano Zampini   product = D->product;
757b77ba244SStefano Zampini   A       = product->A;
758b77ba244SStefano Zampini   B       = product->B;
7599566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
7603ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
761b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
762b77ba244SStefano Zampini   matmat = shell->matmat;
7639566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
764b77ba244SStefano Zampini   while (matmat) {
7659566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
766b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
767b77ba244SStefano Zampini     if (flg) break;
768b77ba244SStefano Zampini     matmat = matmat->next;
769b77ba244SStefano Zampini   }
7709371c9d4SSatish Balay   if (flg) {
7719371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
7729371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
7733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
774b77ba244SStefano Zampini }
775b77ba244SStefano Zampini 
776d71ae5a4SJacob 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)
777d71ae5a4SJacob Faibussowitsch {
778b77ba244SStefano Zampini   PetscBool               flg;
779b77ba244SStefano Zampini   Mat_Shell              *shell;
780b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
781b77ba244SStefano Zampini 
782b77ba244SStefano Zampini   PetscFunctionBegin;
78328b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
78428b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
785b77ba244SStefano Zampini 
786b77ba244SStefano Zampini   /* add product callback */
787b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
788b77ba244SStefano Zampini   matmat = shell->matmat;
789b77ba244SStefano Zampini   if (!matmat) {
7909566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
791b77ba244SStefano Zampini     matmat = shell->matmat;
792b77ba244SStefano Zampini   } else {
793b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
794b77ba244SStefano Zampini     while (entry) {
7959566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
796b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
797b77ba244SStefano Zampini       matmat = entry;
7982e956fe4SStefano Zampini       if (flg) goto set;
799b77ba244SStefano Zampini       entry = entry->next;
800b77ba244SStefano Zampini     }
8019566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
802b77ba244SStefano Zampini     matmat = matmat->next;
803b77ba244SStefano Zampini   }
804b77ba244SStefano Zampini 
805843d480fSStefano Zampini set:
806b77ba244SStefano Zampini   matmat->symbolic = symbolic;
807b77ba244SStefano Zampini   matmat->numeric  = numeric;
808b77ba244SStefano Zampini   matmat->destroy  = destroy;
809b77ba244SStefano Zampini   matmat->ptype    = ptype;
8109566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8119566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8129566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8139566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8149566063dSJacob 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"));
8159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
817b77ba244SStefano Zampini }
818b77ba244SStefano Zampini 
819b77ba244SStefano Zampini /*@C
82011a5261eSBarry Smith   MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
821b77ba244SStefano Zampini 
82227430b45SBarry Smith   Logically Collective; No Fortran Support
823b77ba244SStefano Zampini 
824b77ba244SStefano Zampini   Input Parameters:
82511a5261eSBarry Smith + A        - the `MATSHELL` shell matrix
826b77ba244SStefano Zampini . ptype    - the product type
8272ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
828b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8292ef1f0ffSBarry Smith . destroy  - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`)
830b77ba244SStefano Zampini . Btype    - the matrix type for the matrix to be multiplied against
8312ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
832b77ba244SStefano Zampini 
833b77ba244SStefano Zampini   Level: advanced
834b77ba244SStefano Zampini 
8352920cce0SJacob Faibussowitsch   Example Usage:
836cf53795eSBarry Smith .vb
837cf53795eSBarry Smith   extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**);
838cf53795eSBarry Smith   extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*);
839cf53795eSBarry Smith   extern PetscErrorCode userdestroy(void*);
8402920cce0SJacob Faibussowitsch 
841cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
8422920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
8432920cce0SJacob Faibussowitsch     A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE
8442920cce0SJacob Faibussowitsch   );
8452920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
8462920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
847cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
848cf53795eSBarry Smith   MatProductSetFromOptions(C);
8492920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
8502920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
8512920cce0SJacob Faibussowitsch   // use C = A * B
852cf53795eSBarry Smith .ve
853b77ba244SStefano Zampini 
854b77ba244SStefano Zampini   Notes:
855cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
85611a5261eSBarry Smith 
8572ef1f0ffSBarry 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`.
85811a5261eSBarry Smith 
859b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
860b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
861b77ba244SStefano Zampini   It is allowed to specify the same callbacks for different Btype matrix types.
86227430b45SBarry Smith   The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
863b77ba244SStefano Zampini 
8641cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
865b77ba244SStefano Zampini @*/
866d71ae5a4SJacob 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)
867d71ae5a4SJacob Faibussowitsch {
868b77ba244SStefano Zampini   PetscFunctionBegin;
869b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
870b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
87108401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
87228b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
8734f572ea9SToby Isaac   PetscAssertPointer(Btype, 6);
8744f572ea9SToby Isaac   if (Ctype) PetscAssertPointer(Ctype, 7);
875cac4c232SBarry 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));
8763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
877b77ba244SStefano Zampini }
878b77ba244SStefano Zampini 
879d71ae5a4SJacob 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)
880d71ae5a4SJacob Faibussowitsch {
881b77ba244SStefano Zampini   PetscBool   flg;
882b77ba244SStefano Zampini   char        composedname[256];
883b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
884b77ba244SStefano Zampini   PetscMPIInt size;
885b77ba244SStefano Zampini 
886b77ba244SStefano Zampini   PetscFunctionBegin;
887b77ba244SStefano Zampini   PetscValidType(A, 1);
888b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
8899566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
890b77ba244SStefano Zampini     if (flg) break;
891b77ba244SStefano Zampini     Bnames = Bnames->next;
892b77ba244SStefano Zampini   }
893b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
8949566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
895b77ba244SStefano Zampini     if (flg) break;
896b77ba244SStefano Zampini     Cnames = Cnames->next;
897b77ba244SStefano Zampini   }
8989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
899b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
900b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9019566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9029566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
904e51e0e81SBarry Smith }
905e51e0e81SBarry Smith 
906d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
907d71ae5a4SJacob Faibussowitsch {
90828f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
909cb8c8a77SBarry Smith   PetscBool               matflg;
910b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9117fabda3fSAlex Fikl 
9127fabda3fSAlex Fikl   PetscFunctionBegin;
9139566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
91428b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9157fabda3fSAlex Fikl 
916aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
917aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9187fabda3fSAlex Fikl 
9191baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9207fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9217fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9220c0fd78eSBarry Smith   if (shellA->dshift) {
92348a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9249566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9257fabda3fSAlex Fikl   } else {
9269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9277fabda3fSAlex Fikl   }
9280c0fd78eSBarry Smith   if (shellA->left) {
92948a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9309566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9317fabda3fSAlex Fikl   } else {
9329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9337fabda3fSAlex Fikl   }
9340c0fd78eSBarry Smith   if (shellA->right) {
93548a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9369566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9377fabda3fSAlex Fikl   } else {
9389566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9397fabda3fSAlex Fikl   }
9409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
941ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
942ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
94340e381c3SBarry Smith   if (shellA->axpy) {
9449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
94540e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
94640e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
947ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
94840e381c3SBarry Smith   }
94945960306SStefano Zampini   if (shellA->zrows) {
9509566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
95148a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9529566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9539566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9549566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9559566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9569566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
95745960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
95845960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
95945960306SStefano Zampini   }
960b77ba244SStefano Zampini 
961b77ba244SStefano Zampini   matmatA = shellA->matmat;
962b77ba244SStefano Zampini   if (matmatA) {
963b77ba244SStefano Zampini     while (matmatA->next) {
9649566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
965b77ba244SStefano Zampini       matmatA = matmatA->next;
966b77ba244SStefano Zampini     }
967b77ba244SStefano Zampini   }
9683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9697fabda3fSAlex Fikl }
9707fabda3fSAlex Fikl 
971d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
972d71ae5a4SJacob Faibussowitsch {
973cb8c8a77SBarry Smith   PetscFunctionBegin;
974800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
975800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
976*f4f49eeaSPierre Jolivet   PetscCall(PetscObjectCompose((PetscObject)*M, "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
977*f4f49eeaSPierre Jolivet   PetscCall(PetscObjectChangeTypeName((PetscObject)*M, ((PetscObject)mat)->type_name));
978623b4cf3SPierre Jolivet   if (op == MAT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
97901f93aa2SJose E. Roman   PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M));
9803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
981cb8c8a77SBarry Smith }
982cb8c8a77SBarry Smith 
98366976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
984d71ae5a4SJacob Faibussowitsch {
985ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
98625578ef6SJed Brown   Vec              xx;
987e3f487b0SBarry Smith   PetscObjectState instate, outstate;
988ef66eb69SBarry Smith 
989ef66eb69SBarry Smith   PetscFunctionBegin;
9909566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
9919566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
9929566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
9939566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
9949566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
995e3f487b0SBarry Smith   if (instate == outstate) {
996e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
9979566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
998e3f487b0SBarry Smith   }
999f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
10009566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10019566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10029f137db4SBarry Smith 
10039f137db4SBarry Smith   if (shell->axpy) {
1004ef5c7bd2SStefano Zampini     Mat              X;
1005ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1006ef5c7bd2SStefano Zampini 
10079566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10089566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
100908401ef6SPierre 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,...)");
1010b77ba244SStefano Zampini 
10119566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10129566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10139566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10149566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10159f137db4SBarry Smith   }
10163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1017ef66eb69SBarry Smith }
1018ef66eb69SBarry Smith 
1019d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1020d71ae5a4SJacob Faibussowitsch {
10215edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10225edf6516SJed Brown 
10235edf6516SJed Brown   PetscFunctionBegin;
10245edf6516SJed Brown   if (y == z) {
10259566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10269566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10279566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10285edf6516SJed Brown   } else {
10299566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10309566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10315edf6516SJed Brown   }
10323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10335edf6516SJed Brown }
10345edf6516SJed Brown 
1035d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1036d71ae5a4SJacob Faibussowitsch {
103718be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
103825578ef6SJed Brown   Vec              xx;
1039e3f487b0SBarry Smith   PetscObjectState instate, outstate;
104018be62a5SSatish Balay 
104118be62a5SSatish Balay   PetscFunctionBegin;
10429566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1043f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE));
10449566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10459566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10469566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1047e3f487b0SBarry Smith   if (instate == outstate) {
1048e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10499566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1050e3f487b0SBarry Smith   }
1051f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
1052f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE));
10539566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1054350ec83bSStefano Zampini 
1055350ec83bSStefano Zampini   if (shell->axpy) {
1056ef5c7bd2SStefano Zampini     Mat              X;
1057ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1058ef5c7bd2SStefano Zampini 
10599566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10609566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
106108401ef6SPierre 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,...)");
10629566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10639566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10649566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10659566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1066350ec83bSStefano Zampini   }
10673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106818be62a5SSatish Balay }
106918be62a5SSatish Balay 
1070f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y)
1071f8e07d23SBlanca Mellado Pinto {
1072f8e07d23SBlanca Mellado Pinto   Mat_Shell       *shell = (Mat_Shell *)A->data;
1073f8e07d23SBlanca Mellado Pinto   Vec              xx;
1074f8e07d23SBlanca Mellado Pinto   PetscObjectState instate, outstate;
1075f8e07d23SBlanca Mellado Pinto 
1076f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1077f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1078f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE));
1079f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
1080f8e07d23SBlanca Mellado Pinto   PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y));
1081f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1082f8e07d23SBlanca Mellado Pinto   if (instate == outstate) {
1083f8e07d23SBlanca Mellado Pinto     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1084f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1085f8e07d23SBlanca Mellado Pinto   }
1086f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE));
1087f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE));
1088f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostZeroRight(A, y));
1089f8e07d23SBlanca Mellado Pinto 
1090f8e07d23SBlanca Mellado Pinto   if (shell->axpy) {
1091f8e07d23SBlanca Mellado Pinto     Mat              X;
1092f8e07d23SBlanca Mellado Pinto     PetscObjectState axpy_state;
1093f8e07d23SBlanca Mellado Pinto 
1094f8e07d23SBlanca Mellado Pinto     PetscCall(MatShellGetContext(shell->axpy, &X));
1095f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
1096f8e07d23SBlanca Mellado Pinto     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,...)");
1097f8e07d23SBlanca Mellado Pinto     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
1098f8e07d23SBlanca Mellado Pinto     PetscCall(VecCopy(x, shell->axpy_left));
1099f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
1100f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right));
1101f8e07d23SBlanca Mellado Pinto   }
1102f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1103f8e07d23SBlanca Mellado Pinto }
1104f8e07d23SBlanca Mellado Pinto 
1105d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1106d71ae5a4SJacob Faibussowitsch {
11075edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
11085edf6516SJed Brown 
11095edf6516SJed Brown   PetscFunctionBegin;
11105edf6516SJed Brown   if (y == z) {
11119566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11129566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11139566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11145edf6516SJed Brown   } else {
11159566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11169566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11175edf6516SJed Brown   }
11183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11195edf6516SJed Brown }
11205edf6516SJed Brown 
1121f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1122f8e07d23SBlanca Mellado Pinto {
1123f8e07d23SBlanca Mellado Pinto   Mat_Shell *shell = (Mat_Shell *)A->data;
1124f8e07d23SBlanca Mellado Pinto 
1125f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1126f8e07d23SBlanca Mellado Pinto   if (y == z) {
1127f8e07d23SBlanca Mellado Pinto     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
1128f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work));
1129f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
1130f8e07d23SBlanca Mellado Pinto   } else {
1131f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, z));
1132f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, y));
1133f8e07d23SBlanca Mellado Pinto   }
1134f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1135f8e07d23SBlanca Mellado Pinto }
1136f8e07d23SBlanca Mellado Pinto 
11370c0fd78eSBarry Smith /*
11380c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11390c0fd78eSBarry Smith */
1140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1141d71ae5a4SJacob Faibussowitsch {
114218be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
114318be62a5SSatish Balay 
114418be62a5SSatish Balay   PetscFunctionBegin;
11450c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11469566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1147305211d5SBarry 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,...)");
11489566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
11491baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
11509566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
11519566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
11529566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
115345960306SStefano Zampini   if (shell->zrows) {
11549566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
11559566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
115645960306SStefano Zampini   }
115781c02519SBarry Smith   if (shell->axpy) {
1158ef5c7bd2SStefano Zampini     Mat              X;
1159ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1160ef5c7bd2SStefano Zampini 
11619566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11629566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
116308401ef6SPierre 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,...)");
11649566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
11659566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
11669566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
116781c02519SBarry Smith   }
11683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
116918be62a5SSatish Balay }
117018be62a5SSatish Balay 
1171d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1172d71ae5a4SJacob Faibussowitsch {
1173ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1174789d8953SBarry Smith   PetscBool  flg;
1175b24ad042SBarry Smith 
1176ef66eb69SBarry Smith   PetscFunctionBegin;
11779566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
117828b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
11790c0fd78eSBarry Smith   if (shell->left || shell->right) {
11808fe8eb27SJed Brown     if (!shell->dshift) {
11819566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
11829566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
11830c0fd78eSBarry Smith     } else {
11849566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
11859566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
11869566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
11870c0fd78eSBarry Smith     }
11889566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
11899566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
11908fe8eb27SJed Brown   } else shell->vshift += a;
11911baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
11923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1193ef66eb69SBarry Smith }
1194ef66eb69SBarry Smith 
1195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1196d71ae5a4SJacob Faibussowitsch {
11976464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
11986464bf51SAlex Fikl 
11996464bf51SAlex Fikl   PetscFunctionBegin;
12009566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
12010c0fd78eSBarry Smith   if (shell->left || shell->right) {
12029566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
12039f137db4SBarry Smith     if (shell->left && shell->right) {
12049566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12059566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
12069f137db4SBarry Smith     } else if (shell->left) {
12079566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12089f137db4SBarry Smith     } else {
12099566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
12109f137db4SBarry Smith     }
12119566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
12120c0fd78eSBarry Smith   } else {
12139566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1214b253ae0bS“Marek   }
12153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1216b253ae0bS“Marek }
1217b253ae0bS“Marek 
121866976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1219d71ae5a4SJacob Faibussowitsch {
122045960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1221b253ae0bS“Marek   Vec        d;
1222789d8953SBarry Smith   PetscBool  flg;
1223b253ae0bS“Marek 
1224b253ae0bS“Marek   PetscFunctionBegin;
12259566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
122628b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1227b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12289566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12299566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12309566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12319566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12331baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1234b253ae0bS“Marek   } else {
12359566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12361baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12376464bf51SAlex Fikl   }
12383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12396464bf51SAlex Fikl }
12406464bf51SAlex Fikl 
1241d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1242d71ae5a4SJacob Faibussowitsch {
1243ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1244b24ad042SBarry Smith 
1245ef66eb69SBarry Smith   PetscFunctionBegin;
1246f4df32b1SMatthew Knepley   shell->vscale *= a;
12470c0fd78eSBarry Smith   shell->vshift *= a;
12481baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
124981c02519SBarry Smith   shell->axpy_vscale *= a;
12501baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
125218be62a5SSatish Balay }
12538fe8eb27SJed Brown 
1254d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1255d71ae5a4SJacob Faibussowitsch {
12568fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12578fe8eb27SJed Brown 
12588fe8eb27SJed Brown   PetscFunctionBegin;
12598fe8eb27SJed Brown   if (left) {
12600c0fd78eSBarry Smith     if (!shell->left) {
12619566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12629566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12630c0fd78eSBarry Smith     } else {
12649566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
126518be62a5SSatish Balay     }
12661baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1267ef66eb69SBarry Smith   }
12688fe8eb27SJed Brown   if (right) {
12690c0fd78eSBarry Smith     if (!shell->right) {
12709566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
12719566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
12720c0fd78eSBarry Smith     } else {
12739566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
12748fe8eb27SJed Brown     }
127545960306SStefano Zampini     if (shell->zrows) {
127648a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
12779566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
12789566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12799566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
12809566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
128145960306SStefano Zampini     }
12828fe8eb27SJed Brown   }
12831baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
12843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1285ef66eb69SBarry Smith }
1286ef66eb69SBarry Smith 
128786a9fd05SPierre Jolivet PETSC_INTERN PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1288d71ae5a4SJacob Faibussowitsch {
1289ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1290ef66eb69SBarry Smith 
1291ef66eb69SBarry Smith   PetscFunctionBegin;
12928fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1293ef66eb69SBarry Smith     shell->vshift      = 0.0;
1294ef66eb69SBarry Smith     shell->vscale      = 1.0;
1295ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1296ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
12979566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
12989566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
12999566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
13009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
13019566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
13029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
13039566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
13049566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
13059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
13069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1307ef66eb69SBarry Smith   }
13083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1309ef66eb69SBarry Smith }
1310ef66eb69SBarry Smith 
1311d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1312d71ae5a4SJacob Faibussowitsch {
13133b49f96aSBarry Smith   PetscFunctionBegin;
13143b49f96aSBarry Smith   *missing = PETSC_FALSE;
13153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13163b49f96aSBarry Smith }
13173b49f96aSBarry Smith 
131866976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1319d71ae5a4SJacob Faibussowitsch {
13209f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
13219f137db4SBarry Smith 
13229f137db4SBarry Smith   PetscFunctionBegin;
1323ef5c7bd2SStefano Zampini   if (X == Y) {
13249566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
13253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1326ef5c7bd2SStefano Zampini   }
1327ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13289566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13299f137db4SBarry Smith     shell->axpy_vscale = a;
13309566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1331ef5c7bd2SStefano Zampini   } else {
13329566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1333ef5c7bd2SStefano Zampini   }
13343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13359f137db4SBarry Smith }
13369f137db4SBarry Smith 
1337f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1338f4259b30SLisandro Dalcin                                        NULL,
1339f4259b30SLisandro Dalcin                                        NULL,
1340f4259b30SLisandro Dalcin                                        NULL,
13410c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1342f4259b30SLisandro Dalcin                                        NULL,
13430c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1344f4259b30SLisandro Dalcin                                        NULL,
1345f4259b30SLisandro Dalcin                                        NULL,
1346f4259b30SLisandro Dalcin                                        NULL,
1347f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1348f4259b30SLisandro Dalcin                                        NULL,
1349f4259b30SLisandro Dalcin                                        NULL,
1350f4259b30SLisandro Dalcin                                        NULL,
1351f4259b30SLisandro Dalcin                                        NULL,
1352f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1353f4259b30SLisandro Dalcin                                        NULL,
1354f4259b30SLisandro Dalcin                                        NULL,
13558fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1356f4259b30SLisandro Dalcin                                        NULL,
1357f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1358ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1359f4259b30SLisandro Dalcin                                        NULL,
1360f4259b30SLisandro Dalcin                                        NULL,
136145960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1362f4259b30SLisandro Dalcin                                        NULL,
1363f4259b30SLisandro Dalcin                                        NULL,
1364f4259b30SLisandro Dalcin                                        NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
1368f4259b30SLisandro Dalcin                                        NULL,
1369f4259b30SLisandro Dalcin                                        NULL,
1370f4259b30SLisandro Dalcin                                        NULL,
1371cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                        NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
13769f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1377f4259b30SLisandro Dalcin                                        NULL,
1378f4259b30SLisandro Dalcin                                        NULL,
1379f4259b30SLisandro Dalcin                                        NULL,
1380cb8c8a77SBarry Smith                                        MatCopy_Shell,
1381f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1382ef66eb69SBarry Smith                                        MatScale_Shell,
1383ef66eb69SBarry Smith                                        MatShift_Shell,
13846464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
138545960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1386f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1387f4259b30SLisandro Dalcin                                        NULL,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                        NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1397b9b97703SBarry Smith                                        MatDestroy_Shell,
1398f4259b30SLisandro Dalcin                                        NULL,
1399251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
1408c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
1411f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
1414f4259b30SLisandro Dalcin                                        NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424f4259b30SLisandro Dalcin                                        NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        NULL,
1434f4259b30SLisandro Dalcin                                        NULL,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
14503b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1451f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1452f4259b30SLisandro Dalcin                                        NULL,
1453f4259b30SLisandro Dalcin                                        NULL,
1454f4259b30SLisandro Dalcin                                        NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1457f4259b30SLisandro Dalcin                                        NULL,
1458f4259b30SLisandro Dalcin                                        NULL,
1459f8e07d23SBlanca Mellado Pinto                                        MatMultHermitianTransposeAdd_Shell,
1460f4259b30SLisandro Dalcin                                        NULL,
1461f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1462f4259b30SLisandro Dalcin                                        NULL,
1463f4259b30SLisandro Dalcin                                        NULL,
1464f4259b30SLisandro Dalcin                                        NULL,
1465f4259b30SLisandro Dalcin                                        NULL,
1466f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1467f4259b30SLisandro Dalcin                                        NULL,
1468f4259b30SLisandro Dalcin                                        NULL,
1469f4259b30SLisandro Dalcin                                        NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1472f4259b30SLisandro Dalcin                                        NULL,
1473f4259b30SLisandro Dalcin                                        NULL,
1474f4259b30SLisandro Dalcin                                        NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
1476f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1477f4259b30SLisandro Dalcin                                        NULL,
1478d70f29a3SPierre Jolivet                                        NULL,
1479d70f29a3SPierre Jolivet                                        NULL,
1480d70f29a3SPierre Jolivet                                        NULL,
1481d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1482d70f29a3SPierre Jolivet                                        NULL,
1483d70f29a3SPierre Jolivet                                        NULL,
148499a7f59eSMark Adams                                        NULL,
148599a7f59eSMark Adams                                        NULL,
14867fb60732SBarry Smith                                        NULL,
1487dec0b466SHong Zhang                                        /*150*/ NULL,
1488eede4a3fSMark Adams                                        NULL,
1489dec0b466SHong Zhang                                        NULL};
1490273d9f13SBarry Smith 
1491d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1492d71ae5a4SJacob Faibussowitsch {
1493789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1494789d8953SBarry Smith 
1495789d8953SBarry Smith   PetscFunctionBegin;
1496800f99ffSJeremy L Thompson   if (ctx) {
1497800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1498800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1499800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1500800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1501800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1502800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1503800f99ffSJeremy L Thompson   } else {
1504800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1505800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1506800f99ffSJeremy L Thompson   }
15073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1508800f99ffSJeremy L Thompson }
1509800f99ffSJeremy L Thompson 
151066976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1511d71ae5a4SJacob Faibussowitsch {
1512800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1513800f99ffSJeremy L Thompson 
1514800f99ffSJeremy L Thompson   PetscFunctionBegin;
1515800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
15163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1517789d8953SBarry Smith }
1518789d8953SBarry Smith 
151986a9fd05SPierre Jolivet PetscErrorCode MatShellSetContext_Immutable(Mat mat, void *ctx)
152086a9fd05SPierre Jolivet {
152186a9fd05SPierre Jolivet   PetscFunctionBegin;
152286a9fd05SPierre Jolivet   SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot call MatShellSetContext() for a %s, it is used internally by the structure", ((PetscObject)mat)->type_name);
152386a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
152486a9fd05SPierre Jolivet }
152586a9fd05SPierre Jolivet 
152686a9fd05SPierre Jolivet PetscErrorCode MatShellSetContextDestroy_Immutable(Mat mat, PetscErrorCode (*f)(void *))
152786a9fd05SPierre Jolivet {
152886a9fd05SPierre Jolivet   PetscFunctionBegin;
152986a9fd05SPierre Jolivet   SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot call MatShellSetContextDestroy() for a %s, it is used internally by the structure", ((PetscObject)mat)->type_name);
153086a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
153186a9fd05SPierre Jolivet }
153286a9fd05SPierre Jolivet 
153386a9fd05SPierre Jolivet PetscErrorCode MatShellSetManageScalingShifts_Immutable(Mat mat)
153486a9fd05SPierre Jolivet {
153586a9fd05SPierre Jolivet   PetscFunctionBegin;
153686a9fd05SPierre Jolivet   SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot call MatShellSetManageScalingShifts() for a %s, it is used internally by the structure", ((PetscObject)mat)->type_name);
153786a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
153886a9fd05SPierre Jolivet }
153986a9fd05SPierre Jolivet 
1540d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1541d71ae5a4SJacob Faibussowitsch {
1542db77db73SJeremy L Thompson   PetscFunctionBegin;
15439566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
15449566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
15453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1546db77db73SJeremy L Thompson }
1547db77db73SJeremy L Thompson 
154866976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1549d71ae5a4SJacob Faibussowitsch {
1550789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1551789d8953SBarry Smith 
1552789d8953SBarry Smith   PetscFunctionBegin;
1553789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1554789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1555789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1556789d8953SBarry Smith   A->ops->scale              = NULL;
1557789d8953SBarry Smith   A->ops->shift              = NULL;
1558789d8953SBarry Smith   A->ops->axpy               = NULL;
15593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1560789d8953SBarry Smith }
1561789d8953SBarry Smith 
1562d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1563d71ae5a4SJacob Faibussowitsch {
1564feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1565789d8953SBarry Smith 
1566789d8953SBarry Smith   PetscFunctionBegin;
1567789d8953SBarry Smith   switch (op) {
1568d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1569d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1570d71ae5a4SJacob Faibussowitsch     break;
1571789d8953SBarry Smith   case MATOP_VIEW:
1572ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1573789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1574789d8953SBarry Smith     break;
1575d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1576d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1577d71ae5a4SJacob Faibussowitsch     break;
1578789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1579789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1580789d8953SBarry Smith   case MATOP_SHIFT:
1581789d8953SBarry Smith   case MATOP_SCALE:
1582789d8953SBarry Smith   case MATOP_AXPY:
1583789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1584789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
158528b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1586789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1587789d8953SBarry Smith     break;
1588789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1589789d8953SBarry Smith     if (shell->managescalingshifts) {
1590789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1591789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1592789d8953SBarry Smith     } else {
1593789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1594789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1595789d8953SBarry Smith     }
1596789d8953SBarry Smith     break;
1597789d8953SBarry Smith   case MATOP_MULT:
1598789d8953SBarry Smith     if (shell->managescalingshifts) {
1599789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1600789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1601789d8953SBarry Smith     } else {
1602789d8953SBarry Smith       shell->ops->mult = NULL;
1603789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1604789d8953SBarry Smith     }
1605789d8953SBarry Smith     break;
1606789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1607789d8953SBarry Smith     if (shell->managescalingshifts) {
1608789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1609789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1610789d8953SBarry Smith     } else {
1611789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1612789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1613789d8953SBarry Smith     }
1614789d8953SBarry Smith     break;
1615f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1616f8e07d23SBlanca Mellado Pinto     if (shell->managescalingshifts) {
1617f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1618f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = MatMultHermitianTranspose_Shell;
1619f8e07d23SBlanca Mellado Pinto     } else {
1620f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = NULL;
1621f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1622f8e07d23SBlanca Mellado Pinto     }
1623f8e07d23SBlanca Mellado Pinto     break;
1624d71ae5a4SJacob Faibussowitsch   default:
1625d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1626d71ae5a4SJacob Faibussowitsch     break;
1627789d8953SBarry Smith   }
16283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1629789d8953SBarry Smith }
1630789d8953SBarry Smith 
1631d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1632d71ae5a4SJacob Faibussowitsch {
1633789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1634789d8953SBarry Smith 
1635789d8953SBarry Smith   PetscFunctionBegin;
1636789d8953SBarry Smith   switch (op) {
1637d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1638d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1639d71ae5a4SJacob Faibussowitsch     break;
1640d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1641d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1642d71ae5a4SJacob Faibussowitsch     break;
1643d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1644d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1645d71ae5a4SJacob Faibussowitsch     break;
1646789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1647789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1648789d8953SBarry Smith   case MATOP_SHIFT:
1649789d8953SBarry Smith   case MATOP_SCALE:
1650789d8953SBarry Smith   case MATOP_AXPY:
1651789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1652d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1653d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1654d71ae5a4SJacob Faibussowitsch     break;
1655789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
16569371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
16579371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1658789d8953SBarry Smith     break;
1659789d8953SBarry Smith   case MATOP_MULT:
16609371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
16619371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1662789d8953SBarry Smith     break;
1663789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
16649371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
16659371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1666789d8953SBarry Smith     break;
1667f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1668f8e07d23SBlanca Mellado Pinto     if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose;
1669f8e07d23SBlanca Mellado Pinto     else *f = (((void (**)(void))mat->ops)[op]);
1670f8e07d23SBlanca Mellado Pinto     break;
1671d71ae5a4SJacob Faibussowitsch   default:
1672d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1673789d8953SBarry Smith   }
16743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1675789d8953SBarry Smith }
1676789d8953SBarry Smith 
16770bad9183SKris Buschelman /*MC
167801c1178eSBarry Smith    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free.
16790bad9183SKris Buschelman 
16800bad9183SKris Buschelman   Level: advanced
16810bad9183SKris Buschelman 
16821cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`
16830bad9183SKris Buschelman M*/
16840bad9183SKris Buschelman 
1685d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1686d71ae5a4SJacob Faibussowitsch {
1687273d9f13SBarry Smith   Mat_Shell *b;
1688273d9f13SBarry Smith 
1689273d9f13SBarry Smith   PetscFunctionBegin;
16904dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1691273d9f13SBarry Smith   A->data   = (void *)b;
1692aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1693273d9f13SBarry Smith 
1694800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1695ef66eb69SBarry Smith   b->vshift              = 0.0;
1696ef66eb69SBarry Smith   b->vscale              = 1.0;
16970c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1698273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1699210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17002205254eSKarl Rupp 
17019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
17029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1703800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
17049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
17059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
17069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
17079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
17089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
17099566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
17103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1711273d9f13SBarry Smith }
1712e51e0e81SBarry Smith 
17134b828684SBarry Smith /*@C
171411a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1715ff756334SLois Curfman McInnes   private data storage format.
1716e51e0e81SBarry Smith 
1717d083f849SBarry Smith   Collective
1718c7fcc2eaSBarry Smith 
1719e51e0e81SBarry Smith   Input Parameters:
1720c7fcc2eaSBarry Smith + comm - MPI communicator
172145f401ebSJose E. Roman . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
172245f401ebSJose E. Roman . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
172345f401ebSJose E. Roman . M    - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given)
172445f401ebSJose E. Roman . N    - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given)
1725c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1726e51e0e81SBarry Smith 
1727ff756334SLois Curfman McInnes   Output Parameter:
172844cd7ae7SLois Curfman McInnes . A - the matrix
1729e51e0e81SBarry Smith 
1730ff2fd236SBarry Smith   Level: advanced
1731ff2fd236SBarry Smith 
17322920cce0SJacob Faibussowitsch   Example Usage:
173327430b45SBarry Smith .vb
173427430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
17352920cce0SJacob Faibussowitsch 
173627430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
173727430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
17382920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
173927430b45SBarry Smith   MatDestroy(mat);
174027430b45SBarry Smith .ve
1741f39d1f56SLois Curfman McInnes 
1742ff756334SLois Curfman McInnes   Notes:
1743ff756334SLois Curfman McInnes   The shell matrix type is intended to provide a simple class to use
174411a5261eSBarry Smith   with `KSP` (such as, for use with matrix-free methods). You should not
1745ff756334SLois Curfman McInnes   use the shell type if you plan to define a complete matrix class.
1746e51e0e81SBarry Smith 
1747f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1748f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
17492ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
175011a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1751645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1752645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1753645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1754645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1755645985a0SLois Curfman McInnes   For example,
1756f39d1f56SLois Curfman McInnes 
175727430b45SBarry Smith .vb
175827430b45SBarry Smith      Vec x, y
175927430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
176027430b45SBarry Smith      Mat A
176127430b45SBarry Smith 
176227430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
176327430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
176427430b45SBarry Smith      VecGetLocalSize(y,&m);
176527430b45SBarry Smith      VecGetLocalSize(x,&n);
176627430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
176727430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
176827430b45SBarry Smith      MatMult(A,x,y);
176927430b45SBarry Smith      MatDestroy(&A);
177027430b45SBarry Smith      VecDestroy(&y);
177127430b45SBarry Smith      VecDestroy(&x);
177227430b45SBarry Smith .ve
1773e51e0e81SBarry Smith 
17742ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
17752ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
17760c0fd78eSBarry Smith 
177727430b45SBarry Smith   Developer Notes:
17782ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
17792ef1f0ffSBarry Smith 
178095452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
17810c0fd78eSBarry Smith 
17820c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17830c0fd78eSBarry Smith 
17840c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
17850c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17860c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
17870c0fd78eSBarry Smith 
17880c0fd78eSBarry Smith   A is the user provided function.
17890c0fd78eSBarry Smith 
179027430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1791c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
179211a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
179311a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1794ad2f5c3fSBarry Smith 
179511a5261eSBarry Smith   Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1796b77ba244SStefano Zampini 
179711a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
179811a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1799ad2f5c3fSBarry Smith 
1800fe59aa6dSJacob Faibussowitsch   Fortran Notes:
18012ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
180211a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
18032ef1f0ffSBarry Smith   in as the `ctx` argument.
180411a5261eSBarry Smith 
1805fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1806e51e0e81SBarry Smith @*/
1807d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1808d71ae5a4SJacob Faibussowitsch {
18093a40ed3dSBarry Smith   PetscFunctionBegin;
18109566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
18119566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
18129566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
18139566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
18149566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
18153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1816c7fcc2eaSBarry Smith }
1817c7fcc2eaSBarry Smith 
1818c6866cfdSSatish Balay /*@
181911a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1820c7fcc2eaSBarry Smith 
1821c3339decSBarry Smith   Logically Collective
1822c7fcc2eaSBarry Smith 
1823273d9f13SBarry Smith   Input Parameters:
182411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1825273d9f13SBarry Smith - ctx - the context
1826273d9f13SBarry Smith 
1827273d9f13SBarry Smith   Level: advanced
1828273d9f13SBarry Smith 
1829fe59aa6dSJacob Faibussowitsch   Fortran Notes:
183027430b45SBarry Smith   You must write a Fortran interface definition for this
18312ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1832273d9f13SBarry Smith 
18331cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
18340bc0a719SBarry Smith @*/
1835d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1836d71ae5a4SJacob Faibussowitsch {
1837273d9f13SBarry Smith   PetscFunctionBegin;
18380700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1839cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
18403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1841e51e0e81SBarry Smith }
1842e51e0e81SBarry Smith 
1843fe59aa6dSJacob Faibussowitsch /*@C
184411a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1845800f99ffSJeremy L Thompson 
1846c3339decSBarry Smith   Logically Collective
1847800f99ffSJeremy L Thompson 
1848800f99ffSJeremy L Thompson   Input Parameters:
1849800f99ffSJeremy L Thompson + mat - the shell matrix
1850800f99ffSJeremy L Thompson - f   - the context destroy function
1851800f99ffSJeremy L Thompson 
185227430b45SBarry Smith   Level: advanced
185327430b45SBarry Smith 
1854800f99ffSJeremy L Thompson   Note:
1855800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
185611a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1857800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
185811a5261eSBarry Smith   the `MATSHELL` is duplicated.
1859800f99ffSJeremy L Thompson 
18601cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1861800f99ffSJeremy L Thompson @*/
1862d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1863d71ae5a4SJacob Faibussowitsch {
1864800f99ffSJeremy L Thompson   PetscFunctionBegin;
1865800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1866800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
18673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1868800f99ffSJeremy L Thompson }
1869800f99ffSJeremy L Thompson 
1870db77db73SJeremy L Thompson /*@C
18712ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1872db77db73SJeremy L Thompson 
18732ef1f0ffSBarry Smith   Logically Collective
1874db77db73SJeremy L Thompson 
1875db77db73SJeremy L Thompson   Input Parameters:
187611a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1877db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1878db77db73SJeremy L Thompson 
1879db77db73SJeremy L Thompson   Level: advanced
1880db77db73SJeremy L Thompson 
18811cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1882db77db73SJeremy L Thompson @*/
1883d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1884d71ae5a4SJacob Faibussowitsch {
1885db77db73SJeremy L Thompson   PetscFunctionBegin;
1886cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
18873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1888db77db73SJeremy L Thompson }
1889db77db73SJeremy L Thompson 
18900c0fd78eSBarry Smith /*@
189111a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
189211a5261eSBarry Smith   after `MatCreateShell()`
18930c0fd78eSBarry Smith 
189427430b45SBarry Smith   Logically Collective
18950c0fd78eSBarry Smith 
18960c0fd78eSBarry Smith   Input Parameter:
1897fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
18980c0fd78eSBarry Smith 
18990c0fd78eSBarry Smith   Level: advanced
19000c0fd78eSBarry Smith 
19011cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
19020c0fd78eSBarry Smith @*/
1903d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1904d71ae5a4SJacob Faibussowitsch {
19050c0fd78eSBarry Smith   PetscFunctionBegin;
19060c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1907cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
19083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19090c0fd78eSBarry Smith }
19100c0fd78eSBarry Smith 
1911c16cb8f2SBarry Smith /*@C
191211a5261eSBarry Smith   MatShellTestMult - Compares the multiply 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()`, `MatShellTestMultTranspose()`
1931f3b1f45cSBarry Smith @*/
1932d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1933d71ae5a4SJacob Faibussowitsch {
1934f3b1f45cSBarry Smith   PetscInt  m, n;
1935f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1936f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
193774e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
1938f3b1f45cSBarry Smith 
1939f3b1f45cSBarry Smith   PetscFunctionBegin;
1940f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
19419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
19429566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
19439566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
19449566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
19459566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
1946f3b1f45cSBarry Smith 
19479566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
19489566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
1949f3b1f45cSBarry Smith 
19509566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
19519566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
19529566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
19539566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
1954f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
1955f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1956f3b1f45cSBarry Smith     if (v) {
195701c1178eSBarry 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)));
19589566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
19599566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
19609566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
1961f3b1f45cSBarry Smith     }
1962f3b1f45cSBarry Smith   } else if (v) {
196301c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n"));
1964f3b1f45cSBarry Smith   }
1965f3b1f45cSBarry Smith   if (flg) *flg = flag;
19669566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
19679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
19689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
19699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
19703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1971f3b1f45cSBarry Smith }
1972f3b1f45cSBarry Smith 
1973f3b1f45cSBarry Smith /*@C
197411a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
1975f3b1f45cSBarry Smith 
1976cf53795eSBarry Smith   Logically Collective; No Fortran Support
1977f3b1f45cSBarry Smith 
1978f3b1f45cSBarry Smith   Input Parameters:
197911a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
1980f3b1f45cSBarry Smith . f    - the function
198111a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
1982f3b1f45cSBarry Smith - ctx  - an optional context for the function
1983f3b1f45cSBarry Smith 
1984f3b1f45cSBarry Smith   Output Parameter:
198511a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
1986f3b1f45cSBarry Smith 
19873c7db156SBarry Smith   Options Database Key:
1988f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1989f3b1f45cSBarry Smith 
1990f3b1f45cSBarry Smith   Level: advanced
1991f3b1f45cSBarry Smith 
19921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
1993f3b1f45cSBarry Smith @*/
1994d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
1995d71ae5a4SJacob Faibussowitsch {
1996f3b1f45cSBarry Smith   Vec       x, y, z;
1997f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
1998f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
1999f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
200074e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2001f3b1f45cSBarry Smith 
2002f3b1f45cSBarry Smith   PetscFunctionBegin;
2003f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
20049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
20059566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
20069566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
20079566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20089566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20099566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
20109566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
20119566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
20129566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
20139566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
20149566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
2015f3b1f45cSBarry Smith 
20169566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
20179566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
20189566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
20199566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2020f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2021f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2022f3b1f45cSBarry Smith     if (v) {
202301c1178eSBarry 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)));
20249566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
20259566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
20269566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
2027f3b1f45cSBarry Smith     }
2028f3b1f45cSBarry Smith   } else if (v) {
202901c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n"));
2030f3b1f45cSBarry Smith   }
2031f3b1f45cSBarry Smith   if (flg) *flg = flag;
20329566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
20339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
20349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
20359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
20369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
20379566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
20389566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
20393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2040f3b1f45cSBarry Smith }
2041f3b1f45cSBarry Smith 
2042f3b1f45cSBarry Smith /*@C
204311a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
2044e51e0e81SBarry Smith 
2045c3339decSBarry Smith   Logically Collective
2046fee21e36SBarry Smith 
2047c7fcc2eaSBarry Smith   Input Parameters:
204811a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2049c7fcc2eaSBarry Smith . op  - the name of the operation
2050789d8953SBarry Smith - g   - the function that provides the operation.
2051c7fcc2eaSBarry Smith 
205215091d37SBarry Smith   Level: advanced
205315091d37SBarry Smith 
20542920cce0SJacob Faibussowitsch   Example Usage:
2055c3339decSBarry Smith .vb
2056c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
20572920cce0SJacob Faibussowitsch 
2058c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
2059c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
2060c3339decSBarry Smith .ve
20610b627109SLois Curfman McInnes 
2062a62d957aSLois Curfman McInnes   Notes:
2063e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
20641c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2065a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
206611a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2067a62d957aSLois Curfman McInnes 
206811a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2069deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2070deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2071deebb3c3SLois Curfman McInnes   routines, e.g.,
2072a62d957aSLois Curfman McInnes $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2073a62d957aSLois Curfman McInnes 
20744aa34b0aSBarry Smith   In particular each function MUST return an error code of 0 on success and
20754aa34b0aSBarry Smith   nonzero on failure.
20764aa34b0aSBarry Smith 
2077a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
207811a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
207911a5261eSBarry Smith   set by `MatCreateShell()`.
2080a62d957aSLois Curfman McInnes 
20812ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
20822ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2083b77ba244SStefano Zampini 
2084fe59aa6dSJacob Faibussowitsch   Fortran Notes:
208511a5261eSBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2086c4762a1bSJed Brown   generate a matrix. See src/mat/tests/ex120f.F
2087501d9185SBarry Smith 
20881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2089e51e0e81SBarry Smith @*/
2090d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2091d71ae5a4SJacob Faibussowitsch {
20923a40ed3dSBarry Smith   PetscFunctionBegin;
20930700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2094cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
20953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2096e51e0e81SBarry Smith }
2097f0479e8cSBarry Smith 
2098d4bb536fSBarry Smith /*@C
209911a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2100d4bb536fSBarry Smith 
2101c7fcc2eaSBarry Smith   Not Collective
2102c7fcc2eaSBarry Smith 
2103d4bb536fSBarry Smith   Input Parameters:
210411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2105c7fcc2eaSBarry Smith - op  - the name of the operation
2106d4bb536fSBarry Smith 
2107d4bb536fSBarry Smith   Output Parameter:
2108789d8953SBarry Smith . g - the function that provides the operation.
2109d4bb536fSBarry Smith 
211015091d37SBarry Smith   Level: advanced
211115091d37SBarry Smith 
211227430b45SBarry Smith   Notes:
2113e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2114d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2115d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
211611a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2117d4bb536fSBarry Smith 
2118d4bb536fSBarry Smith   All user-provided functions have the same calling
2119d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2120d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2121d4bb536fSBarry Smith   routines, e.g.,
2122d4bb536fSBarry Smith $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2123d4bb536fSBarry Smith 
2124d4bb536fSBarry Smith   Within each user-defined routine, the user should call
212511a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
212611a5261eSBarry Smith   set by `MatCreateShell()`.
2127d4bb536fSBarry Smith 
21281cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2129d4bb536fSBarry Smith @*/
2130d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2131d71ae5a4SJacob Faibussowitsch {
21323a40ed3dSBarry Smith   PetscFunctionBegin;
21330700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2134cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
21353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2136d4bb536fSBarry Smith }
2137b77ba244SStefano Zampini 
2138b77ba244SStefano Zampini /*@
213911a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2140b77ba244SStefano Zampini 
2141b77ba244SStefano Zampini   Input Parameter:
2142b77ba244SStefano Zampini . mat - the matrix
2143b77ba244SStefano Zampini 
2144b77ba244SStefano Zampini   Output Parameter:
2145b77ba244SStefano Zampini . flg - the boolean value
2146b77ba244SStefano Zampini 
2147b77ba244SStefano Zampini   Level: developer
2148b77ba244SStefano Zampini 
2149fe59aa6dSJacob Faibussowitsch   Developer Notes:
21502ef1f0ffSBarry Smith   In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices
21512ef1f0ffSBarry Smith   (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc)
2152b77ba244SStefano Zampini 
21531cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2154b77ba244SStefano Zampini @*/
2155d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2156d71ae5a4SJacob Faibussowitsch {
2157b77ba244SStefano Zampini   PetscFunctionBegin;
2158b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
21594f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
2160b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
21613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2162b77ba244SStefano Zampini }
2163