xref: /petsc/src/mat/impls/shell/shell.c (revision a3f1d042deeee8d591d0e166df91c7782e45ac59)
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;
265bd72c1ddSStefano Zampini   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), 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;
302bd72c1ddSStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), 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));
474b9c875b8SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetScalingShifts_C", NULL));
4759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
4769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
4779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
4789566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
4793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
480b77ba244SStefano Zampini }
481b77ba244SStefano Zampini 
482b77ba244SStefano Zampini typedef struct {
483b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
484b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void *);
485b77ba244SStefano Zampini   void *userdata;
486b77ba244SStefano Zampini   Mat   B;
487b77ba244SStefano Zampini   Mat   Bt;
488b77ba244SStefano Zampini   Mat   axpy;
489b77ba244SStefano Zampini } MatMatDataShell;
490b77ba244SStefano Zampini 
491d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data)
492d71ae5a4SJacob Faibussowitsch {
493b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
494b77ba244SStefano Zampini 
495b77ba244SStefano Zampini   PetscFunctionBegin;
4961baa6e33SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata));
4979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
4989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
4999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5009566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
502b77ba244SStefano Zampini }
503b77ba244SStefano Zampini 
504d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
505d71ae5a4SJacob Faibussowitsch {
506b77ba244SStefano Zampini   Mat_Product     *product;
507b77ba244SStefano Zampini   Mat              A, B;
508b77ba244SStefano Zampini   MatMatDataShell *mdata;
509b77ba244SStefano Zampini   PetscScalar      zero = 0.0;
510b77ba244SStefano Zampini 
511b77ba244SStefano Zampini   PetscFunctionBegin;
512b77ba244SStefano Zampini   MatCheckProduct(D, 1);
513b77ba244SStefano Zampini   product = D->product;
51428b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
515b77ba244SStefano Zampini   A     = product->A;
516b77ba244SStefano Zampini   B     = product->B;
517b77ba244SStefano Zampini   mdata = (MatMatDataShell *)product->data;
518b77ba244SStefano Zampini   if (mdata->numeric) {
519b77ba244SStefano Zampini     Mat_Shell *shell                = (Mat_Shell *)A->data;
520b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
521b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
522b77ba244SStefano Zampini     PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
523b77ba244SStefano Zampini 
524b77ba244SStefano Zampini     if (shell->managescalingshifts) {
52508401ef6SPierre Jolivet       PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
526b77ba244SStefano Zampini       if (shell->right || shell->left) {
527b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
528b77ba244SStefano Zampini         if (!mdata->B) {
5299566063dSJacob Faibussowitsch           PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
530b77ba244SStefano Zampini         } else {
531b77ba244SStefano Zampini           newB = PETSC_FALSE;
532b77ba244SStefano Zampini         }
5339566063dSJacob Faibussowitsch         PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
534b77ba244SStefano Zampini       }
535b77ba244SStefano Zampini       switch (product->type) {
536b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5371baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
538b77ba244SStefano Zampini         break;
539b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5401baa6e33SBarry Smith         if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
541b77ba244SStefano Zampini         break;
542b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5431baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
544b77ba244SStefano Zampini         break;
545b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
546b77ba244SStefano Zampini         if (shell->right && shell->left) {
547b77ba244SStefano Zampini           PetscBool flg;
548b77ba244SStefano Zampini 
5499566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5509371c9d4SSatish 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,
5519371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
552b77ba244SStefano Zampini         }
5531baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
554b77ba244SStefano Zampini         break;
555b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
556b77ba244SStefano Zampini         if (shell->right && shell->left) {
557b77ba244SStefano Zampini           PetscBool flg;
558b77ba244SStefano Zampini 
5599566063dSJacob Faibussowitsch           PetscCall(VecEqual(shell->right, shell->left, &flg));
5609371c9d4SSatish 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,
5619371c9d4SSatish Balay                      ((PetscObject)B)->type_name);
562b77ba244SStefano Zampini         }
5631baa6e33SBarry Smith         if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
564b77ba244SStefano Zampini         break;
565d71ae5a4SJacob Faibussowitsch       default:
566d71ae5a4SJacob 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);
567b77ba244SStefano Zampini       }
568b77ba244SStefano Zampini     }
569b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
570b77ba244SStefano Zampini     D->product              = NULL;
571b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
572b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
573b77ba244SStefano Zampini 
5749566063dSJacob Faibussowitsch     PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata));
575b77ba244SStefano Zampini 
576b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
5779566063dSJacob Faibussowitsch     PetscCall(MatProductClear(D));
578b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
579b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
580b77ba244SStefano Zampini     D->product              = product;
581b77ba244SStefano Zampini 
582b77ba244SStefano Zampini     if (shell->managescalingshifts) {
5839566063dSJacob Faibussowitsch       PetscCall(MatScale(D, shell->vscale));
584b77ba244SStefano Zampini       switch (product->type) {
585b77ba244SStefano Zampini       case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
586b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
587b77ba244SStefano Zampini         if (shell->left) {
5889566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->left, NULL));
589b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
5909566063dSJacob Faibussowitsch             if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
591b77ba244SStefano Zampini             if (shell->dshift) {
5929566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->left_work));
5939566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->left_work, shell->vshift));
5949566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
595b77ba244SStefano Zampini             } else {
5969566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->left_work, shell->vshift));
597b77ba244SStefano Zampini             }
598b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
599b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
600b77ba244SStefano Zampini               MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
601b77ba244SStefano Zampini 
6029566063dSJacob Faibussowitsch               PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6039566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6049566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
605b77ba244SStefano Zampini             } else {
606b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
607b77ba244SStefano Zampini 
6089566063dSJacob Faibussowitsch               PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6099566063dSJacob Faibussowitsch               PetscCall(MatAXPY(D, 1.0, mdata->B, str));
610b77ba244SStefano Zampini             }
611b77ba244SStefano Zampini           }
612b77ba244SStefano Zampini         }
613b77ba244SStefano Zampini         break;
614b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
615b77ba244SStefano Zampini         if (shell->right) {
6169566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(D, shell->right, NULL));
617b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
618b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
619b77ba244SStefano Zampini 
6209566063dSJacob Faibussowitsch             if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
621b77ba244SStefano Zampini             if (shell->dshift) {
6229566063dSJacob Faibussowitsch               PetscCall(VecCopy(shell->dshift, shell->right_work));
6239566063dSJacob Faibussowitsch               PetscCall(VecShift(shell->right_work, shell->vshift));
6249566063dSJacob Faibussowitsch               PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
625b77ba244SStefano Zampini             } else {
6269566063dSJacob Faibussowitsch               PetscCall(VecSet(shell->right_work, shell->vshift));
627b77ba244SStefano Zampini             }
6289566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6299566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
630b77ba244SStefano Zampini           }
631b77ba244SStefano Zampini         }
632b77ba244SStefano Zampini         break;
633b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
634b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6359371c9d4SSatish 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,
6369371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
637b77ba244SStefano Zampini         break;
638d71ae5a4SJacob Faibussowitsch       default:
639d71ae5a4SJacob 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);
640b77ba244SStefano Zampini       }
641b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
642b77ba244SStefano Zampini         Mat              X;
643b77ba244SStefano Zampini         PetscObjectState axpy_state;
644b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
645b77ba244SStefano Zampini 
6469566063dSJacob Faibussowitsch         PetscCall(MatShellGetContext(shell->axpy, &X));
6479566063dSJacob Faibussowitsch         PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
64808401ef6SPierre 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,...)");
649b77ba244SStefano Zampini         if (!mdata->axpy) {
650b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
6519566063dSJacob Faibussowitsch           PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
6529566063dSJacob Faibussowitsch           PetscCall(MatProductSetType(mdata->axpy, product->type));
6539566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6549566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
655b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
656b77ba244SStefano Zampini           PetscBool flg;
657b77ba244SStefano Zampini 
6589566063dSJacob Faibussowitsch           PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
6599566063dSJacob Faibussowitsch           PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
660b77ba244SStefano Zampini           if (!flg) {
661b77ba244SStefano Zampini             str = DIFFERENT_NONZERO_PATTERN;
6629566063dSJacob Faibussowitsch             PetscCall(MatProductSetFromOptions(mdata->axpy));
6639566063dSJacob Faibussowitsch             PetscCall(MatProductSymbolic(mdata->axpy));
664b77ba244SStefano Zampini           }
665b77ba244SStefano Zampini         }
6669566063dSJacob Faibussowitsch         PetscCall(MatProductNumeric(mdata->axpy));
6679566063dSJacob Faibussowitsch         PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
668b77ba244SStefano Zampini       }
669b77ba244SStefano Zampini     }
670b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
6713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
672b77ba244SStefano Zampini }
673b77ba244SStefano Zampini 
674d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
675d71ae5a4SJacob Faibussowitsch {
676b77ba244SStefano Zampini   Mat_Product            *product;
677b77ba244SStefano Zampini   Mat                     A, B;
678b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
679b77ba244SStefano Zampini   Mat_Shell              *shell;
680eae3dc7dSJacob Faibussowitsch   PetscBool               flg = PETSC_FALSE;
681b77ba244SStefano Zampini   char                    composedname[256];
682b77ba244SStefano Zampini   MatMatDataShell        *mdata;
683b77ba244SStefano Zampini 
684b77ba244SStefano Zampini   PetscFunctionBegin;
685b77ba244SStefano Zampini   MatCheckProduct(D, 1);
686b77ba244SStefano Zampini   product = D->product;
68728b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
688b77ba244SStefano Zampini   A      = product->A;
689b77ba244SStefano Zampini   B      = product->B;
690b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
691b77ba244SStefano Zampini   matmat = shell->matmat;
6929566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
693b77ba244SStefano Zampini   while (matmat) {
6949566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
695b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
696b77ba244SStefano Zampini     if (flg) break;
697b77ba244SStefano Zampini     matmat = matmat->next;
698b77ba244SStefano Zampini   }
69928b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
700b77ba244SStefano Zampini   switch (product->type) {
701d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
702d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
703d71ae5a4SJacob Faibussowitsch     break;
704d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
705d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
706d71ae5a4SJacob Faibussowitsch     break;
707d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
708d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
709d71ae5a4SJacob Faibussowitsch     break;
710d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
711d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
712d71ae5a4SJacob Faibussowitsch     break;
713d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
714d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
715d71ae5a4SJacob Faibussowitsch     break;
716d71ae5a4SJacob Faibussowitsch   default:
717d71ae5a4SJacob 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);
718b77ba244SStefano Zampini   }
719b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
720b77ba244SStefano Zampini   if (matmat->resultname) {
7219566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
72248a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
723b77ba244SStefano Zampini   }
724b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
725b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
726b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
727b77ba244SStefano Zampini   /* attach product data */
7289566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
729b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
730b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
731b77ba244SStefano Zampini   if (matmat->symbolic) {
7329566063dSJacob Faibussowitsch     PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata));
733b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7349566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
735b77ba244SStefano Zampini   }
73628b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
73728b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
738b77ba244SStefano Zampini   D->product->data    = mdata;
739b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
740b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
741b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
742b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
744b77ba244SStefano Zampini }
745b77ba244SStefano Zampini 
746d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
747d71ae5a4SJacob Faibussowitsch {
748b77ba244SStefano Zampini   Mat_Product            *product;
749b77ba244SStefano Zampini   Mat                     A, B;
750b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
751b77ba244SStefano Zampini   Mat_Shell              *shell;
752b77ba244SStefano Zampini   PetscBool               flg;
753b77ba244SStefano Zampini   char                    composedname[256];
754b77ba244SStefano Zampini 
755b77ba244SStefano Zampini   PetscFunctionBegin;
756b77ba244SStefano Zampini   MatCheckProduct(D, 1);
757b77ba244SStefano Zampini   product = D->product;
758b77ba244SStefano Zampini   A       = product->A;
759b77ba244SStefano Zampini   B       = product->B;
7609566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
7613ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
762b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
763b77ba244SStefano Zampini   matmat = shell->matmat;
7649566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
765b77ba244SStefano Zampini   while (matmat) {
7669566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
767b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
768b77ba244SStefano Zampini     if (flg) break;
769b77ba244SStefano Zampini     matmat = matmat->next;
770b77ba244SStefano Zampini   }
7719371c9d4SSatish Balay   if (flg) {
7729371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
7739371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
7743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
775b77ba244SStefano Zampini }
776b77ba244SStefano Zampini 
777d71ae5a4SJacob 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)
778d71ae5a4SJacob Faibussowitsch {
779b77ba244SStefano Zampini   PetscBool               flg;
780b77ba244SStefano Zampini   Mat_Shell              *shell;
781b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
782b77ba244SStefano Zampini 
783b77ba244SStefano Zampini   PetscFunctionBegin;
78428b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
78528b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
786b77ba244SStefano Zampini 
787b77ba244SStefano Zampini   /* add product callback */
788b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
789b77ba244SStefano Zampini   matmat = shell->matmat;
790b77ba244SStefano Zampini   if (!matmat) {
7919566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
792b77ba244SStefano Zampini     matmat = shell->matmat;
793b77ba244SStefano Zampini   } else {
794b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
795b77ba244SStefano Zampini     while (entry) {
7969566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
797b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
798b77ba244SStefano Zampini       matmat = entry;
7992e956fe4SStefano Zampini       if (flg) goto set;
800b77ba244SStefano Zampini       entry = entry->next;
801b77ba244SStefano Zampini     }
8029566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
803b77ba244SStefano Zampini     matmat = matmat->next;
804b77ba244SStefano Zampini   }
805b77ba244SStefano Zampini 
806843d480fSStefano Zampini set:
807b77ba244SStefano Zampini   matmat->symbolic = symbolic;
808b77ba244SStefano Zampini   matmat->numeric  = numeric;
809b77ba244SStefano Zampini   matmat->destroy  = destroy;
810b77ba244SStefano Zampini   matmat->ptype    = ptype;
8119566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8129566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8139566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8149566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8159566063dSJacob 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"));
8169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
818b77ba244SStefano Zampini }
819b77ba244SStefano Zampini 
820b77ba244SStefano Zampini /*@C
82111a5261eSBarry Smith   MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
822b77ba244SStefano Zampini 
82327430b45SBarry Smith   Logically Collective; No Fortran Support
824b77ba244SStefano Zampini 
825b77ba244SStefano Zampini   Input Parameters:
82611a5261eSBarry Smith + A        - the `MATSHELL` shell matrix
827b77ba244SStefano Zampini . ptype    - the product type
8282ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
829b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8302ef1f0ffSBarry Smith . destroy  - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`)
831b77ba244SStefano Zampini . Btype    - the matrix type for the matrix to be multiplied against
8322ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
833b77ba244SStefano Zampini 
834b77ba244SStefano Zampini   Level: advanced
835b77ba244SStefano Zampini 
8362920cce0SJacob Faibussowitsch   Example Usage:
837cf53795eSBarry Smith .vb
838cf53795eSBarry Smith   extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**);
839cf53795eSBarry Smith   extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*);
840cf53795eSBarry Smith   extern PetscErrorCode userdestroy(void*);
8412920cce0SJacob Faibussowitsch 
842cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
8432920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
8442920cce0SJacob Faibussowitsch     A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE
8452920cce0SJacob Faibussowitsch   );
8462920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
8472920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
848cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
849cf53795eSBarry Smith   MatProductSetFromOptions(C);
8502920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
8512920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
8522920cce0SJacob Faibussowitsch   // use C = A * B
853cf53795eSBarry Smith .ve
854b77ba244SStefano Zampini 
855b77ba244SStefano Zampini   Notes:
856cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
85711a5261eSBarry Smith 
8582ef1f0ffSBarry 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`.
85911a5261eSBarry Smith 
860b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
861b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
862b77ba244SStefano Zampini   It is allowed to specify the same callbacks for different Btype matrix types.
86327430b45SBarry Smith   The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence.
864b77ba244SStefano Zampini 
8651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
866b77ba244SStefano Zampini @*/
867d71ae5a4SJacob 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)
868d71ae5a4SJacob Faibussowitsch {
869b77ba244SStefano Zampini   PetscFunctionBegin;
870b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
871b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
87208401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
87328b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
8744f572ea9SToby Isaac   PetscAssertPointer(Btype, 6);
8754f572ea9SToby Isaac   if (Ctype) PetscAssertPointer(Ctype, 7);
876cac4c232SBarry 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));
8773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
878b77ba244SStefano Zampini }
879b77ba244SStefano Zampini 
880d71ae5a4SJacob 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)
881d71ae5a4SJacob Faibussowitsch {
882b77ba244SStefano Zampini   PetscBool   flg;
883b77ba244SStefano Zampini   char        composedname[256];
884b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
885b77ba244SStefano Zampini   PetscMPIInt size;
886b77ba244SStefano Zampini 
887b77ba244SStefano Zampini   PetscFunctionBegin;
888b77ba244SStefano Zampini   PetscValidType(A, 1);
889b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
8909566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
891b77ba244SStefano Zampini     if (flg) break;
892b77ba244SStefano Zampini     Bnames = Bnames->next;
893b77ba244SStefano Zampini   }
894b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
8959566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
896b77ba244SStefano Zampini     if (flg) break;
897b77ba244SStefano Zampini     Cnames = Cnames->next;
898b77ba244SStefano Zampini   }
8999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
900b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
901b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9029566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9039566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
905e51e0e81SBarry Smith }
906e51e0e81SBarry Smith 
907d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
908d71ae5a4SJacob Faibussowitsch {
90928f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
910cb8c8a77SBarry Smith   PetscBool               matflg;
911b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9127fabda3fSAlex Fikl 
9137fabda3fSAlex Fikl   PetscFunctionBegin;
9149566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
91528b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9167fabda3fSAlex Fikl 
917aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
918aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9197fabda3fSAlex Fikl 
9201baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9217fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9227fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9230c0fd78eSBarry Smith   if (shellA->dshift) {
92448a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9259566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9267fabda3fSAlex Fikl   } else {
9279566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9287fabda3fSAlex Fikl   }
9290c0fd78eSBarry Smith   if (shellA->left) {
93048a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9319566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9327fabda3fSAlex Fikl   } else {
9339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9347fabda3fSAlex Fikl   }
9350c0fd78eSBarry Smith   if (shellA->right) {
93648a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9379566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9387fabda3fSAlex Fikl   } else {
9399566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9407fabda3fSAlex Fikl   }
9419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
942ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
943ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
94440e381c3SBarry Smith   if (shellA->axpy) {
9459566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
94640e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
94740e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
948ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
94940e381c3SBarry Smith   }
95045960306SStefano Zampini   if (shellA->zrows) {
9519566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
95248a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9539566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9549566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9559566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9569566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
95845960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
95945960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
96045960306SStefano Zampini   }
961b77ba244SStefano Zampini 
962b77ba244SStefano Zampini   matmatA = shellA->matmat;
963b77ba244SStefano Zampini   if (matmatA) {
964b77ba244SStefano Zampini     while (matmatA->next) {
9659566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
966b77ba244SStefano Zampini       matmatA = matmatA->next;
967b77ba244SStefano Zampini     }
968b77ba244SStefano Zampini   }
9693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9707fabda3fSAlex Fikl }
9717fabda3fSAlex Fikl 
972d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
973d71ae5a4SJacob Faibussowitsch {
974cb8c8a77SBarry Smith   PetscFunctionBegin;
975800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
976800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
977f4f49eeaSPierre Jolivet   PetscCall(PetscObjectCompose((PetscObject)*M, "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
978f4f49eeaSPierre Jolivet   PetscCall(PetscObjectChangeTypeName((PetscObject)*M, ((PetscObject)mat)->type_name));
979623b4cf3SPierre Jolivet   if (op == MAT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
98001f93aa2SJose E. Roman   PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M));
9813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
982cb8c8a77SBarry Smith }
983cb8c8a77SBarry Smith 
98466976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
985d71ae5a4SJacob Faibussowitsch {
986ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
98725578ef6SJed Brown   Vec              xx;
988e3f487b0SBarry Smith   PetscObjectState instate, outstate;
989ef66eb69SBarry Smith 
990ef66eb69SBarry Smith   PetscFunctionBegin;
9919566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
9929566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
9939566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
9949566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
9959566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
996e3f487b0SBarry Smith   if (instate == outstate) {
997e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
9989566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
999e3f487b0SBarry Smith   }
1000f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
10019566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10029566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10039f137db4SBarry Smith 
10049f137db4SBarry Smith   if (shell->axpy) {
1005ef5c7bd2SStefano Zampini     Mat              X;
1006ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1007ef5c7bd2SStefano Zampini 
10089566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10099566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
101008401ef6SPierre 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,...)");
1011b77ba244SStefano Zampini 
10129566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10139566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10149566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10159566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10169f137db4SBarry Smith   }
10173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1018ef66eb69SBarry Smith }
1019ef66eb69SBarry Smith 
1020d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1021d71ae5a4SJacob Faibussowitsch {
10225edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10235edf6516SJed Brown 
10245edf6516SJed Brown   PetscFunctionBegin;
10255edf6516SJed Brown   if (y == z) {
10269566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10279566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10289566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10295edf6516SJed Brown   } else {
10309566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10319566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10325edf6516SJed Brown   }
10333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10345edf6516SJed Brown }
10355edf6516SJed Brown 
1036d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1037d71ae5a4SJacob Faibussowitsch {
103818be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
103925578ef6SJed Brown   Vec              xx;
1040e3f487b0SBarry Smith   PetscObjectState instate, outstate;
104118be62a5SSatish Balay 
104218be62a5SSatish Balay   PetscFunctionBegin;
10439566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1044f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE));
10459566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10469566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10479566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1048e3f487b0SBarry Smith   if (instate == outstate) {
1049e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10509566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1051e3f487b0SBarry Smith   }
1052f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
1053f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE));
10549566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1055350ec83bSStefano Zampini 
1056350ec83bSStefano Zampini   if (shell->axpy) {
1057ef5c7bd2SStefano Zampini     Mat              X;
1058ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1059ef5c7bd2SStefano Zampini 
10609566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10619566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
106208401ef6SPierre 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,...)");
10639566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10649566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10659566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10669566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1067350ec83bSStefano Zampini   }
10683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106918be62a5SSatish Balay }
107018be62a5SSatish Balay 
1071f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y)
1072f8e07d23SBlanca Mellado Pinto {
1073f8e07d23SBlanca Mellado Pinto   Mat_Shell       *shell = (Mat_Shell *)A->data;
1074f8e07d23SBlanca Mellado Pinto   Vec              xx;
1075f8e07d23SBlanca Mellado Pinto   PetscObjectState instate, outstate;
1076f8e07d23SBlanca Mellado Pinto 
1077f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1078f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1079f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE));
1080f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
1081f8e07d23SBlanca Mellado Pinto   PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y));
1082f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1083f8e07d23SBlanca Mellado Pinto   if (instate == outstate) {
1084f8e07d23SBlanca Mellado Pinto     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1085f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1086f8e07d23SBlanca Mellado Pinto   }
1087f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE));
1088f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE));
1089f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostZeroRight(A, y));
1090f8e07d23SBlanca Mellado Pinto 
1091f8e07d23SBlanca Mellado Pinto   if (shell->axpy) {
1092f8e07d23SBlanca Mellado Pinto     Mat              X;
1093f8e07d23SBlanca Mellado Pinto     PetscObjectState axpy_state;
1094f8e07d23SBlanca Mellado Pinto 
1095f8e07d23SBlanca Mellado Pinto     PetscCall(MatShellGetContext(shell->axpy, &X));
1096f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
1097f8e07d23SBlanca 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,...)");
1098f8e07d23SBlanca Mellado Pinto     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
1099f8e07d23SBlanca Mellado Pinto     PetscCall(VecCopy(x, shell->axpy_left));
1100f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
1101f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right));
1102f8e07d23SBlanca Mellado Pinto   }
1103f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1104f8e07d23SBlanca Mellado Pinto }
1105f8e07d23SBlanca Mellado Pinto 
1106d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1107d71ae5a4SJacob Faibussowitsch {
11085edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
11095edf6516SJed Brown 
11105edf6516SJed Brown   PetscFunctionBegin;
11115edf6516SJed Brown   if (y == z) {
11129566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11139566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11149566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11155edf6516SJed Brown   } else {
11169566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11179566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11185edf6516SJed Brown   }
11193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11205edf6516SJed Brown }
11215edf6516SJed Brown 
1122f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1123f8e07d23SBlanca Mellado Pinto {
1124f8e07d23SBlanca Mellado Pinto   Mat_Shell *shell = (Mat_Shell *)A->data;
1125f8e07d23SBlanca Mellado Pinto 
1126f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1127f8e07d23SBlanca Mellado Pinto   if (y == z) {
1128f8e07d23SBlanca Mellado Pinto     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
1129f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work));
1130f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
1131f8e07d23SBlanca Mellado Pinto   } else {
1132f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, z));
1133f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, y));
1134f8e07d23SBlanca Mellado Pinto   }
1135f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1136f8e07d23SBlanca Mellado Pinto }
1137f8e07d23SBlanca Mellado Pinto 
11380c0fd78eSBarry Smith /*
11390c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11400c0fd78eSBarry Smith */
1141d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1142d71ae5a4SJacob Faibussowitsch {
114318be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
114418be62a5SSatish Balay 
114518be62a5SSatish Balay   PetscFunctionBegin;
11460c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
11479566063dSJacob Faibussowitsch     PetscCall((*shell->ops->getdiagonal)(A, v));
1148305211d5SBarry 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,...)");
11499566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->vscale));
11501baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift));
11519566063dSJacob Faibussowitsch   PetscCall(VecShift(v, shell->vshift));
11529566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left));
11539566063dSJacob Faibussowitsch   if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right));
115445960306SStefano Zampini   if (shell->zrows) {
11559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
11569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE));
115745960306SStefano Zampini   }
115881c02519SBarry Smith   if (shell->axpy) {
1159ef5c7bd2SStefano Zampini     Mat              X;
1160ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1161ef5c7bd2SStefano Zampini 
11629566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
11639566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
116408401ef6SPierre 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,...)");
11659566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left));
11669566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left));
11679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left));
116881c02519SBarry Smith   }
11693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
117018be62a5SSatish Balay }
117118be62a5SSatish Balay 
1172a29b93afSAudic XU static PetscErrorCode MatGetDiagonalBlock_Shell(Mat A, Mat *b)
1173a29b93afSAudic XU {
1174a29b93afSAudic XU   Mat_Shell *shell = (Mat_Shell *)A->data;
1175a29b93afSAudic XU   Vec        left = NULL, right = NULL;
1176a29b93afSAudic XU 
1177a29b93afSAudic XU   PetscFunctionBegin;
1178a29b93afSAudic XU   PetscCheck(!shell->zrows && !shell->zcols, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatZeroRows() or MatZeroRowsColumns() has been called on the input Mat"); // TODO FIXME
1179a29b93afSAudic XU   PetscCheck(!shell->axpy, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatAXPY() has been called on the input Mat");                                               // TODO FIXME
1180a29b93afSAudic XU   PetscCheck(!shell->dshift, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatDiagonalSet() has been called on the input Mat");                                      // TODO FIXME
1181a29b93afSAudic XU   if (shell->ops->getdiagonalblock) {
1182a29b93afSAudic XU     PetscCall((*shell->ops->getdiagonalblock)(A, b));
1183a29b93afSAudic XU   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal block using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL_BLOCK,...)");
1184a29b93afSAudic XU   PetscCall(MatScale(*b, shell->vscale));
1185a29b93afSAudic XU   PetscCall(MatShift(*b, shell->vshift));
1186a29b93afSAudic XU   if (shell->left) {
1187a29b93afSAudic XU     PetscCall(VecCreateLocalVector(shell->left, &left));
1188a29b93afSAudic XU     PetscCall(VecGetLocalVectorRead(shell->left, left));
1189a29b93afSAudic XU   }
1190a29b93afSAudic XU   if (shell->right) {
1191a29b93afSAudic XU     PetscCall(VecCreateLocalVector(shell->right, &right));
1192a29b93afSAudic XU     PetscCall(VecGetLocalVectorRead(shell->right, right));
1193a29b93afSAudic XU   }
1194a29b93afSAudic XU   PetscCall(MatDiagonalScale(*b, left, right));
1195a29b93afSAudic XU   if (shell->left) {
1196a29b93afSAudic XU     PetscCall(VecRestoreLocalVectorRead(shell->left, left));
1197a29b93afSAudic XU     PetscCall(VecDestroy(&left));
1198a29b93afSAudic XU   }
1199a29b93afSAudic XU   if (shell->right) {
1200a29b93afSAudic XU     PetscCall(VecRestoreLocalVectorRead(shell->right, right));
1201a29b93afSAudic XU     PetscCall(VecDestroy(&right));
1202a29b93afSAudic XU   }
1203a29b93afSAudic XU   PetscFunctionReturn(PETSC_SUCCESS);
1204a29b93afSAudic XU }
1205a29b93afSAudic XU 
1206d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1207d71ae5a4SJacob Faibussowitsch {
1208ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1209789d8953SBarry Smith   PetscBool  flg;
1210b24ad042SBarry Smith 
1211ef66eb69SBarry Smith   PetscFunctionBegin;
12129566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
121328b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
12140c0fd78eSBarry Smith   if (shell->left || shell->right) {
12158fe8eb27SJed Brown     if (!shell->dshift) {
12169566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
12179566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
12180c0fd78eSBarry Smith     } else {
12199566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
12209566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
12219566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
12220c0fd78eSBarry Smith     }
12239566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
12249566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
12258fe8eb27SJed Brown   } else shell->vshift += a;
12261baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
12273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1228ef66eb69SBarry Smith }
1229ef66eb69SBarry Smith 
1230d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1231d71ae5a4SJacob Faibussowitsch {
12326464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
12336464bf51SAlex Fikl 
12346464bf51SAlex Fikl   PetscFunctionBegin;
12359566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
12360c0fd78eSBarry Smith   if (shell->left || shell->right) {
12379566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
12389f137db4SBarry Smith     if (shell->left && shell->right) {
12399566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12409566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
12419f137db4SBarry Smith     } else if (shell->left) {
12429566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12439f137db4SBarry Smith     } else {
12449566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
12459f137db4SBarry Smith     }
12469566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
12470c0fd78eSBarry Smith   } else {
12489566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1249b253ae0bS“Marek   }
12503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1251b253ae0bS“Marek }
1252b253ae0bS“Marek 
125366976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1254d71ae5a4SJacob Faibussowitsch {
125545960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1256b253ae0bS“Marek   Vec        d;
1257789d8953SBarry Smith   PetscBool  flg;
1258b253ae0bS“Marek 
1259b253ae0bS“Marek   PetscFunctionBegin;
12609566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
126128b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1262b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12639566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12649566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12659566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12669566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12679566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12681baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1269b253ae0bS“Marek   } else {
12709566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12711baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12726464bf51SAlex Fikl   }
12733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12746464bf51SAlex Fikl }
12756464bf51SAlex Fikl 
1276d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1277d71ae5a4SJacob Faibussowitsch {
1278ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1279b24ad042SBarry Smith 
1280ef66eb69SBarry Smith   PetscFunctionBegin;
1281f4df32b1SMatthew Knepley   shell->vscale *= a;
12820c0fd78eSBarry Smith   shell->vshift *= a;
12831baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
128481c02519SBarry Smith   shell->axpy_vscale *= a;
12851baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128718be62a5SSatish Balay }
12888fe8eb27SJed Brown 
1289d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1290d71ae5a4SJacob Faibussowitsch {
12918fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12928fe8eb27SJed Brown 
12938fe8eb27SJed Brown   PetscFunctionBegin;
12948fe8eb27SJed Brown   if (left) {
12950c0fd78eSBarry Smith     if (!shell->left) {
12969566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12979566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12980c0fd78eSBarry Smith     } else {
12999566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
130018be62a5SSatish Balay     }
13011baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1302ef66eb69SBarry Smith   }
13038fe8eb27SJed Brown   if (right) {
13040c0fd78eSBarry Smith     if (!shell->right) {
13059566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
13069566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
13070c0fd78eSBarry Smith     } else {
13089566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
13098fe8eb27SJed Brown     }
131045960306SStefano Zampini     if (shell->zrows) {
131148a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
13129566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
13139566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13149566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13159566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
131645960306SStefano Zampini     }
13178fe8eb27SJed Brown   }
13181baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
13193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1320ef66eb69SBarry Smith }
1321ef66eb69SBarry Smith 
132286a9fd05SPierre Jolivet PETSC_INTERN PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1323d71ae5a4SJacob Faibussowitsch {
1324ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1325ef66eb69SBarry Smith 
1326ef66eb69SBarry Smith   PetscFunctionBegin;
13278fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1328ef66eb69SBarry Smith     shell->vshift      = 0.0;
1329ef66eb69SBarry Smith     shell->vscale      = 1.0;
1330ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1331ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
13339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
13349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
13359566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
13369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
13379566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
13389566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
13399566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
13409566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
13419566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1342ef66eb69SBarry Smith   }
13433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1344ef66eb69SBarry Smith }
1345ef66eb69SBarry Smith 
1346d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d)
1347d71ae5a4SJacob Faibussowitsch {
13483b49f96aSBarry Smith   PetscFunctionBegin;
13493b49f96aSBarry Smith   *missing = PETSC_FALSE;
13503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13513b49f96aSBarry Smith }
13523b49f96aSBarry Smith 
135366976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1354d71ae5a4SJacob Faibussowitsch {
13559f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
13569f137db4SBarry Smith 
13579f137db4SBarry Smith   PetscFunctionBegin;
1358ef5c7bd2SStefano Zampini   if (X == Y) {
13599566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
13603ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1361ef5c7bd2SStefano Zampini   }
1362ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13639566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13649f137db4SBarry Smith     shell->axpy_vscale = a;
13659566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1366ef5c7bd2SStefano Zampini   } else {
13679566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1368ef5c7bd2SStefano Zampini   }
13693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13709f137db4SBarry Smith }
13719f137db4SBarry Smith 
1372f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                        NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
13760c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1377f4259b30SLisandro Dalcin                                        NULL,
13780c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1379f4259b30SLisandro Dalcin                                        NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381f4259b30SLisandro Dalcin                                        NULL,
1382f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                        NULL,
1385f4259b30SLisandro Dalcin                                        NULL,
1386f4259b30SLisandro Dalcin                                        NULL,
1387f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1388f4259b30SLisandro Dalcin                                        NULL,
1389f4259b30SLisandro Dalcin                                        NULL,
13908fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1393ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
139645960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        NULL,
1399f4259b30SLisandro Dalcin                                        NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404a29b93afSAudic XU                                        /*32*/ NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1407f4259b30SLisandro Dalcin                                        NULL,
1408f4259b30SLisandro Dalcin                                        NULL,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                        NULL,
14119f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
1414f4259b30SLisandro Dalcin                                        NULL,
1415cb8c8a77SBarry Smith                                        MatCopy_Shell,
1416f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1417ef66eb69SBarry Smith                                        MatScale_Shell,
1418ef66eb69SBarry Smith                                        MatShift_Shell,
14196464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
142045960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1421f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424f4259b30SLisandro Dalcin                                        NULL,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1432b9b97703SBarry Smith                                        MatDestroy_Shell,
1433f4259b30SLisandro Dalcin                                        NULL,
1434251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1437f4259b30SLisandro Dalcin                                        NULL,
1438f4259b30SLisandro Dalcin                                        NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1452f4259b30SLisandro Dalcin                                        NULL,
1453f4259b30SLisandro Dalcin                                        NULL,
1454f4259b30SLisandro Dalcin                                        NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1457f4259b30SLisandro Dalcin                                        NULL,
1458f4259b30SLisandro Dalcin                                        NULL,
1459f4259b30SLisandro Dalcin                                        NULL,
1460f4259b30SLisandro Dalcin                                        NULL,
1461f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1462f4259b30SLisandro Dalcin                                        NULL,
1463f4259b30SLisandro Dalcin                                        NULL,
1464f4259b30SLisandro Dalcin                                        NULL,
1465f4259b30SLisandro Dalcin                                        NULL,
1466f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1467f4259b30SLisandro Dalcin                                        NULL,
1468f4259b30SLisandro Dalcin                                        NULL,
1469f4259b30SLisandro Dalcin                                        NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1472f4259b30SLisandro Dalcin                                        NULL,
1473f4259b30SLisandro Dalcin                                        NULL,
1474f4259b30SLisandro Dalcin                                        NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
1476f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1477f4259b30SLisandro Dalcin                                        NULL,
1478f4259b30SLisandro Dalcin                                        NULL,
1479f4259b30SLisandro Dalcin                                        NULL,
1480f4259b30SLisandro Dalcin                                        NULL,
1481f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1482f4259b30SLisandro Dalcin                                        NULL,
1483f4259b30SLisandro Dalcin                                        NULL,
1484f4259b30SLisandro Dalcin                                        NULL,
14853b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1486f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1487f4259b30SLisandro Dalcin                                        NULL,
1488f4259b30SLisandro Dalcin                                        NULL,
1489f4259b30SLisandro Dalcin                                        NULL,
1490f4259b30SLisandro Dalcin                                        NULL,
1491f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1492f4259b30SLisandro Dalcin                                        NULL,
1493f4259b30SLisandro Dalcin                                        NULL,
1494f8e07d23SBlanca Mellado Pinto                                        MatMultHermitianTransposeAdd_Shell,
1495f4259b30SLisandro Dalcin                                        NULL,
1496f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1497f4259b30SLisandro Dalcin                                        NULL,
1498f4259b30SLisandro Dalcin                                        NULL,
1499f4259b30SLisandro Dalcin                                        NULL,
1500f4259b30SLisandro Dalcin                                        NULL,
1501f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1502f4259b30SLisandro Dalcin                                        NULL,
1503f4259b30SLisandro Dalcin                                        NULL,
1504f4259b30SLisandro Dalcin                                        NULL,
1505f4259b30SLisandro Dalcin                                        NULL,
1506f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1507f4259b30SLisandro Dalcin                                        NULL,
1508f4259b30SLisandro Dalcin                                        NULL,
1509f4259b30SLisandro Dalcin                                        NULL,
1510f4259b30SLisandro Dalcin                                        NULL,
1511f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1512f4259b30SLisandro Dalcin                                        NULL,
1513d70f29a3SPierre Jolivet                                        NULL,
1514d70f29a3SPierre Jolivet                                        NULL,
1515d70f29a3SPierre Jolivet                                        NULL,
1516d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1517d70f29a3SPierre Jolivet                                        NULL,
1518d70f29a3SPierre Jolivet                                        NULL,
151999a7f59eSMark Adams                                        NULL,
152099a7f59eSMark Adams                                        NULL,
15217fb60732SBarry Smith                                        NULL,
1522dec0b466SHong Zhang                                        /*150*/ NULL,
1523eede4a3fSMark Adams                                        NULL,
15244cc2b5b5SPierre Jolivet                                        NULL,
1525dec0b466SHong Zhang                                        NULL};
1526273d9f13SBarry Smith 
1527d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx)
1528d71ae5a4SJacob Faibussowitsch {
1529789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1530789d8953SBarry Smith 
1531789d8953SBarry Smith   PetscFunctionBegin;
1532800f99ffSJeremy L Thompson   if (ctx) {
1533800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1534800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1535800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1536800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1537800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1538800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1539800f99ffSJeremy L Thompson   } else {
1540800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1541800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1542800f99ffSJeremy L Thompson   }
15433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1544800f99ffSJeremy L Thompson }
1545800f99ffSJeremy L Thompson 
154666976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *))
1547d71ae5a4SJacob Faibussowitsch {
1548800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1549800f99ffSJeremy L Thompson 
1550800f99ffSJeremy L Thompson   PetscFunctionBegin;
1551800f99ffSJeremy L Thompson   if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f));
15523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1553789d8953SBarry Smith }
1554789d8953SBarry Smith 
155586a9fd05SPierre Jolivet PetscErrorCode MatShellSetContext_Immutable(Mat mat, void *ctx)
155686a9fd05SPierre Jolivet {
155786a9fd05SPierre Jolivet   PetscFunctionBegin;
155886a9fd05SPierre 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);
155986a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
156086a9fd05SPierre Jolivet }
156186a9fd05SPierre Jolivet 
156286a9fd05SPierre Jolivet PetscErrorCode MatShellSetContextDestroy_Immutable(Mat mat, PetscErrorCode (*f)(void *))
156386a9fd05SPierre Jolivet {
156486a9fd05SPierre Jolivet   PetscFunctionBegin;
156586a9fd05SPierre 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);
156686a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
156786a9fd05SPierre Jolivet }
156886a9fd05SPierre Jolivet 
156986a9fd05SPierre Jolivet PetscErrorCode MatShellSetManageScalingShifts_Immutable(Mat mat)
157086a9fd05SPierre Jolivet {
157186a9fd05SPierre Jolivet   PetscFunctionBegin;
157286a9fd05SPierre 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);
157386a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
157486a9fd05SPierre Jolivet }
157586a9fd05SPierre Jolivet 
1576d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1577d71ae5a4SJacob Faibussowitsch {
1578db77db73SJeremy L Thompson   PetscFunctionBegin;
15799566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
15809566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
15813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1582db77db73SJeremy L Thompson }
1583db77db73SJeremy L Thompson 
158466976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1585d71ae5a4SJacob Faibussowitsch {
1586789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1587789d8953SBarry Smith 
1588789d8953SBarry Smith   PetscFunctionBegin;
1589789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1590789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1591789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1592789d8953SBarry Smith   A->ops->scale              = NULL;
1593789d8953SBarry Smith   A->ops->shift              = NULL;
1594789d8953SBarry Smith   A->ops->axpy               = NULL;
15953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1596789d8953SBarry Smith }
1597789d8953SBarry Smith 
1598b9c875b8SPierre Jolivet static PetscErrorCode MatShellGetScalingShifts_Shell(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols)
1599b9c875b8SPierre Jolivet {
1600b9c875b8SPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)A->data;
1601b9c875b8SPierre Jolivet 
1602b9c875b8SPierre Jolivet   PetscFunctionBegin;
1603b9c875b8SPierre Jolivet   PetscCheck(shell->managescalingshifts, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot get scaling and shifts if MatShellSetManageScalingShifts() has been called");
1604b9c875b8SPierre Jolivet   if (vshift == MAT_SHELL_NOT_ALLOWED) PetscCheck(shell->vshift == 0.0, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: vshift != 0.0, set via MatShift()");
1605b9c875b8SPierre Jolivet   else if (vshift) *vshift = shell->vshift;
1606b9c875b8SPierre Jolivet   if (vscale == MAT_SHELL_NOT_ALLOWED) PetscCheck(shell->vscale == 1.0, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: vscale != 1.0, set via MatScale()");
1607b9c875b8SPierre Jolivet   else if (vscale) *vscale = shell->vscale;
1608b9c875b8SPierre Jolivet   if (dshift == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->dshift, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: dshift, set via MatDiagonalSet()");
1609b9c875b8SPierre Jolivet   else if (dshift) *dshift = shell->dshift;
1610b9c875b8SPierre Jolivet   if (left == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->left, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: left, set via MatDiagonalScale()");
1611b9c875b8SPierre Jolivet   else if (left) *left = shell->left;
1612b9c875b8SPierre Jolivet   if (right == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->right, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: right, set via MatDiagonalScale()");
1613b9c875b8SPierre Jolivet   else if (right) *right = shell->right;
1614b9c875b8SPierre Jolivet   if (axpy == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->axpy, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: axpy, set via MatAXPY()");
1615b9c875b8SPierre Jolivet   else if (axpy) *axpy = shell->axpy;
1616b9c875b8SPierre Jolivet   if (zrows == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->zrows, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: zrows, set via MatZeroRows()");
1617b9c875b8SPierre Jolivet   else if (zrows) *zrows = shell->zrows;
1618b9c875b8SPierre Jolivet   if (zcols == MAT_SHELL_NOT_ALLOWED) PetscCheck(!shell->zcols, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Non-trivial member in parent MatShell: zcols, set via MatZeroRowsColumns()");
1619b9c875b8SPierre Jolivet   else if (zcols) *zcols = shell->zcols;
1620b9c875b8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
1621b9c875b8SPierre Jolivet }
1622b9c875b8SPierre Jolivet 
1623d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void))
1624d71ae5a4SJacob Faibussowitsch {
1625feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1626789d8953SBarry Smith 
1627789d8953SBarry Smith   PetscFunctionBegin;
1628789d8953SBarry Smith   switch (op) {
1629d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1630d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode(*)(Mat))f;
1631d71ae5a4SJacob Faibussowitsch     break;
1632789d8953SBarry Smith   case MATOP_VIEW:
1633ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1634789d8953SBarry Smith     mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f;
1635789d8953SBarry Smith     break;
1636d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1637d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f;
1638d71ae5a4SJacob Faibussowitsch     break;
1639789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1640789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1641789d8953SBarry Smith   case MATOP_SHIFT:
1642789d8953SBarry Smith   case MATOP_SCALE:
1643789d8953SBarry Smith   case MATOP_AXPY:
1644789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1645789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
164628b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1647789d8953SBarry Smith     (((void (**)(void))mat->ops)[op]) = f;
1648789d8953SBarry Smith     break;
1649789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1650789d8953SBarry Smith     if (shell->managescalingshifts) {
1651789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f;
1652789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1653789d8953SBarry Smith     } else {
1654789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1655789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode(*)(Mat, Vec))f;
1656789d8953SBarry Smith     }
1657789d8953SBarry Smith     break;
1658a29b93afSAudic XU   case MATOP_GET_DIAGONAL_BLOCK:
1659a29b93afSAudic XU     if (shell->managescalingshifts) {
1660a29b93afSAudic XU       shell->ops->getdiagonalblock = (PetscErrorCode(*)(Mat, Mat *))f;
1661a29b93afSAudic XU       mat->ops->getdiagonalblock   = MatGetDiagonalBlock_Shell;
1662a29b93afSAudic XU     } else {
1663a29b93afSAudic XU       shell->ops->getdiagonalblock = NULL;
1664a29b93afSAudic XU       mat->ops->getdiagonalblock   = (PetscErrorCode(*)(Mat, Mat *))f;
1665a29b93afSAudic XU     }
1666a29b93afSAudic XU     break;
1667789d8953SBarry Smith   case MATOP_MULT:
1668789d8953SBarry Smith     if (shell->managescalingshifts) {
1669789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1670789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1671789d8953SBarry Smith     } else {
1672789d8953SBarry Smith       shell->ops->mult = NULL;
1673789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1674789d8953SBarry Smith     }
1675789d8953SBarry Smith     break;
1676789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1677789d8953SBarry Smith     if (shell->managescalingshifts) {
1678789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1679789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1680789d8953SBarry Smith     } else {
1681789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1682789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1683789d8953SBarry Smith     }
1684789d8953SBarry Smith     break;
1685f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1686f8e07d23SBlanca Mellado Pinto     if (shell->managescalingshifts) {
1687f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1688f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = MatMultHermitianTranspose_Shell;
1689f8e07d23SBlanca Mellado Pinto     } else {
1690f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = NULL;
1691f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = (PetscErrorCode(*)(Mat, Vec, Vec))f;
1692f8e07d23SBlanca Mellado Pinto     }
1693f8e07d23SBlanca Mellado Pinto     break;
1694d71ae5a4SJacob Faibussowitsch   default:
1695d71ae5a4SJacob Faibussowitsch     (((void (**)(void))mat->ops)[op]) = f;
1696d71ae5a4SJacob Faibussowitsch     break;
1697789d8953SBarry Smith   }
16983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1699789d8953SBarry Smith }
1700789d8953SBarry Smith 
1701d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void))
1702d71ae5a4SJacob Faibussowitsch {
1703789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1704789d8953SBarry Smith 
1705789d8953SBarry Smith   PetscFunctionBegin;
1706789d8953SBarry Smith   switch (op) {
1707d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1708d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->destroy;
1709d71ae5a4SJacob Faibussowitsch     break;
1710d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
1711d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))mat->ops->view;
1712d71ae5a4SJacob Faibussowitsch     break;
1713d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1714d71ae5a4SJacob Faibussowitsch     *f = (void (*)(void))shell->ops->copy;
1715d71ae5a4SJacob Faibussowitsch     break;
1716789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1717789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1718789d8953SBarry Smith   case MATOP_SHIFT:
1719789d8953SBarry Smith   case MATOP_SCALE:
1720789d8953SBarry Smith   case MATOP_AXPY:
1721789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1722d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
1723d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1724d71ae5a4SJacob Faibussowitsch     break;
1725789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
17269371c9d4SSatish Balay     if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal;
17279371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1728789d8953SBarry Smith     break;
1729a29b93afSAudic XU   case MATOP_GET_DIAGONAL_BLOCK:
1730a29b93afSAudic XU     if (shell->ops->getdiagonalblock) *f = (void (*)(void))shell->ops->getdiagonalblock;
1731a29b93afSAudic XU     else *f = (((void (**)(void))mat->ops)[op]);
1732a29b93afSAudic XU     break;
1733789d8953SBarry Smith   case MATOP_MULT:
17349371c9d4SSatish Balay     if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult;
17359371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1736789d8953SBarry Smith     break;
1737789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
17389371c9d4SSatish Balay     if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose;
17399371c9d4SSatish Balay     else *f = (((void (**)(void))mat->ops)[op]);
1740789d8953SBarry Smith     break;
1741f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1742f8e07d23SBlanca Mellado Pinto     if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose;
1743f8e07d23SBlanca Mellado Pinto     else *f = (((void (**)(void))mat->ops)[op]);
1744f8e07d23SBlanca Mellado Pinto     break;
1745d71ae5a4SJacob Faibussowitsch   default:
1746d71ae5a4SJacob Faibussowitsch     *f = (((void (**)(void))mat->ops)[op]);
1747789d8953SBarry Smith   }
17483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1749789d8953SBarry Smith }
1750789d8953SBarry Smith 
17510bad9183SKris Buschelman /*MC
175201c1178eSBarry Smith    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free.
17530bad9183SKris Buschelman 
17540bad9183SKris Buschelman   Level: advanced
17550bad9183SKris Buschelman 
17561cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`
17570bad9183SKris Buschelman M*/
17580bad9183SKris Buschelman 
1759d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1760d71ae5a4SJacob Faibussowitsch {
1761273d9f13SBarry Smith   Mat_Shell *b;
1762273d9f13SBarry Smith 
1763273d9f13SBarry Smith   PetscFunctionBegin;
17644dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1765273d9f13SBarry Smith   A->data   = (void *)b;
1766aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1767273d9f13SBarry Smith 
1768800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1769ef66eb69SBarry Smith   b->vshift              = 0.0;
1770ef66eb69SBarry Smith   b->vscale              = 1.0;
17710c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1772273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1773210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17742205254eSKarl Rupp 
17759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
17769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1777800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
17789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
17799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
1780b9c875b8SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetScalingShifts_C", MatShellGetScalingShifts_Shell));
17819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
17829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
17839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
17849566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
17853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1786273d9f13SBarry Smith }
1787e51e0e81SBarry Smith 
17884b828684SBarry Smith /*@C
178911a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
1790ff756334SLois Curfman McInnes   private data storage format.
1791e51e0e81SBarry Smith 
1792d083f849SBarry Smith   Collective
1793c7fcc2eaSBarry Smith 
1794e51e0e81SBarry Smith   Input Parameters:
1795c7fcc2eaSBarry Smith + comm - MPI communicator
179645f401ebSJose E. Roman . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
179745f401ebSJose E. Roman . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
179845f401ebSJose E. Roman . M    - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given)
179945f401ebSJose E. Roman . N    - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given)
1800c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1801e51e0e81SBarry Smith 
1802ff756334SLois Curfman McInnes   Output Parameter:
180344cd7ae7SLois Curfman McInnes . A - the matrix
1804e51e0e81SBarry Smith 
1805ff2fd236SBarry Smith   Level: advanced
1806ff2fd236SBarry Smith 
18072920cce0SJacob Faibussowitsch   Example Usage:
180827430b45SBarry Smith .vb
180927430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
18102920cce0SJacob Faibussowitsch 
181127430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
181227430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
18132920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
181427430b45SBarry Smith   MatDestroy(mat);
181527430b45SBarry Smith .ve
1816f39d1f56SLois Curfman McInnes 
1817ff756334SLois Curfman McInnes   Notes:
1818ff756334SLois Curfman McInnes   The shell matrix type is intended to provide a simple class to use
181911a5261eSBarry Smith   with `KSP` (such as, for use with matrix-free methods). You should not
1820ff756334SLois Curfman McInnes   use the shell type if you plan to define a complete matrix class.
1821e51e0e81SBarry Smith 
1822f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1823f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
18242ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
182511a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1826645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1827645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1828645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1829645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1830645985a0SLois Curfman McInnes   For example,
1831f39d1f56SLois Curfman McInnes 
183227430b45SBarry Smith .vb
183327430b45SBarry Smith      Vec x, y
183427430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
183527430b45SBarry Smith      Mat A
183627430b45SBarry Smith 
183727430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
183827430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
183927430b45SBarry Smith      VecGetLocalSize(y,&m);
184027430b45SBarry Smith      VecGetLocalSize(x,&n);
184127430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
184227430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
184327430b45SBarry Smith      MatMult(A,x,y);
184427430b45SBarry Smith      MatDestroy(&A);
184527430b45SBarry Smith      VecDestroy(&y);
184627430b45SBarry Smith      VecDestroy(&x);
184727430b45SBarry Smith .ve
1848e51e0e81SBarry Smith 
18492ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
18502ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
18510c0fd78eSBarry Smith 
185227430b45SBarry Smith   Developer Notes:
18532ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
18542ef1f0ffSBarry Smith 
185595452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
18560c0fd78eSBarry Smith 
18570c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
18580c0fd78eSBarry Smith 
18590c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
18600c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
18610c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
18620c0fd78eSBarry Smith 
18630c0fd78eSBarry Smith   A is the user provided function.
18640c0fd78eSBarry Smith 
186527430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1866c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
186711a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
186811a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1869ad2f5c3fSBarry Smith 
187011a5261eSBarry Smith   Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()`
1871b77ba244SStefano Zampini 
187211a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
187311a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1874ad2f5c3fSBarry Smith 
1875fe59aa6dSJacob Faibussowitsch   Fortran Notes:
18762ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
187711a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
18782ef1f0ffSBarry Smith   in as the `ctx` argument.
187911a5261eSBarry Smith 
1880fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1881e51e0e81SBarry Smith @*/
1882d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A)
1883d71ae5a4SJacob Faibussowitsch {
18843a40ed3dSBarry Smith   PetscFunctionBegin;
18859566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
18869566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
18879566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
18889566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
18899566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
18903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1891c7fcc2eaSBarry Smith }
1892c7fcc2eaSBarry Smith 
1893c6866cfdSSatish Balay /*@
189411a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1895c7fcc2eaSBarry Smith 
1896c3339decSBarry Smith   Logically Collective
1897c7fcc2eaSBarry Smith 
1898273d9f13SBarry Smith   Input Parameters:
189911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1900273d9f13SBarry Smith - ctx - the context
1901273d9f13SBarry Smith 
1902273d9f13SBarry Smith   Level: advanced
1903273d9f13SBarry Smith 
1904fe59aa6dSJacob Faibussowitsch   Fortran Notes:
190527430b45SBarry Smith   You must write a Fortran interface definition for this
19062ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1907273d9f13SBarry Smith 
19081cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
19090bc0a719SBarry Smith @*/
1910d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx)
1911d71ae5a4SJacob Faibussowitsch {
1912273d9f13SBarry Smith   PetscFunctionBegin;
19130700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1914cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
19153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1916e51e0e81SBarry Smith }
1917e51e0e81SBarry Smith 
1918fe59aa6dSJacob Faibussowitsch /*@C
191911a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1920800f99ffSJeremy L Thompson 
1921c3339decSBarry Smith   Logically Collective
1922800f99ffSJeremy L Thompson 
1923800f99ffSJeremy L Thompson   Input Parameters:
1924800f99ffSJeremy L Thompson + mat - the shell matrix
1925800f99ffSJeremy L Thompson - f   - the context destroy function
1926800f99ffSJeremy L Thompson 
192727430b45SBarry Smith   Level: advanced
192827430b45SBarry Smith 
1929800f99ffSJeremy L Thompson   Note:
1930800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
193111a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1932800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
193311a5261eSBarry Smith   the `MATSHELL` is duplicated.
1934800f99ffSJeremy L Thompson 
19351cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`
1936800f99ffSJeremy L Thompson @*/
1937d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *))
1938d71ae5a4SJacob Faibussowitsch {
1939800f99ffSJeremy L Thompson   PetscFunctionBegin;
1940800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1941800f99ffSJeremy L Thompson   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f));
19423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1943800f99ffSJeremy L Thompson }
1944800f99ffSJeremy L Thompson 
1945db77db73SJeremy L Thompson /*@C
19462ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1947db77db73SJeremy L Thompson 
19482ef1f0ffSBarry Smith   Logically Collective
1949db77db73SJeremy L Thompson 
1950db77db73SJeremy L Thompson   Input Parameters:
195111a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1952db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1953db77db73SJeremy L Thompson 
1954db77db73SJeremy L Thompson   Level: advanced
1955db77db73SJeremy L Thompson 
19561cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1957db77db73SJeremy L Thompson @*/
1958d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1959d71ae5a4SJacob Faibussowitsch {
1960db77db73SJeremy L Thompson   PetscFunctionBegin;
1961cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
19623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1963db77db73SJeremy L Thompson }
1964db77db73SJeremy L Thompson 
19650c0fd78eSBarry Smith /*@
196611a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
196711a5261eSBarry Smith   after `MatCreateShell()`
19680c0fd78eSBarry Smith 
196927430b45SBarry Smith   Logically Collective
19700c0fd78eSBarry Smith 
19710c0fd78eSBarry Smith   Input Parameter:
1972fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
19730c0fd78eSBarry Smith 
19740c0fd78eSBarry Smith   Level: advanced
19750c0fd78eSBarry Smith 
19761cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
19770c0fd78eSBarry Smith @*/
1978d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1979d71ae5a4SJacob Faibussowitsch {
19800c0fd78eSBarry Smith   PetscFunctionBegin;
19810c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1982cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
19833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19840c0fd78eSBarry Smith }
19850c0fd78eSBarry Smith 
1986b9c875b8SPierre Jolivet /*@C
1987b9c875b8SPierre Jolivet   MatShellGetScalingShifts - Gets members of a `MATSHELL` used internally for scaling and
1988b9c875b8SPierre Jolivet   shifting the `Mat` or calling `MatAXPY()`, `MatZeroRows()`, or `MatZeroRowsColumns()` with it
1989b9c875b8SPierre Jolivet 
1990b9c875b8SPierre Jolivet   Logically Collective
1991b9c875b8SPierre Jolivet 
1992b9c875b8SPierre Jolivet   Input Parameter:
1993b9c875b8SPierre Jolivet . A - the `MATSHELL` shell matrix
1994b9c875b8SPierre Jolivet 
1995b9c875b8SPierre Jolivet   Output Parameters:
1996b9c875b8SPierre Jolivet + vshift - `PetscScalar` pointer (can be `NULL`), see `MatShift()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be 0
1997b9c875b8SPierre Jolivet . vscale - `PetscScalar` pointer (can be `NULL`), see `MatScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be 1
1998b9c875b8SPierre Jolivet . dshift - `Vec` pointer (can be `NULL`), see `MatDiagonalSet()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be `NULL`
1999b9c875b8SPierre Jolivet . left   - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL`
2000b9c875b8SPierre Jolivet . right  - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL`
2001b9c875b8SPierre Jolivet . axpy   - `Mat` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatAXPY()` should have not been called on `A`
2002b9c875b8SPierre Jolivet . zrows  - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRows()` should have not been called on `A`
2003b9c875b8SPierre Jolivet - zcols  - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRowsColumns()` should have not been called on `A`
2004b9c875b8SPierre Jolivet 
2005b9c875b8SPierre Jolivet   Level: advanced
2006b9c875b8SPierre Jolivet 
2007b9c875b8SPierre Jolivet   Developer Notes:
2008b9c875b8SPierre Jolivet   This is mostly useful to check for corner-cases in `MatType` deriving from
2009*a3f1d042SPierre Jolivet   `MATSHELL`, e.g, `MATCOMPOSITE` or `MATTRANSPOSEVIRTUAL`, since scaling and
2010b9c875b8SPierre Jolivet   shifts often require extra work which is not always implemented.
2011b9c875b8SPierre Jolivet 
2012b9c875b8SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShift()`, `MatScale()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatShellSetManageScalingShifts()`
2013b9c875b8SPierre Jolivet @*/
2014b9c875b8SPierre Jolivet PetscErrorCode MatShellGetScalingShifts(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols)
2015b9c875b8SPierre Jolivet {
2016b9c875b8SPierre Jolivet   PetscFunctionBegin;
2017b9c875b8SPierre Jolivet   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2018b9c875b8SPierre Jolivet   PetscTryMethod(A, "MatShellGetScalingShifts_C", (Mat, PetscScalar *, PetscScalar *, Vec *, Vec *, Vec *, Mat *, IS *, IS *), (A, vshift, vscale, dshift, left, right, axpy, zrows, zcols));
2019b9c875b8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
2020b9c875b8SPierre Jolivet }
2021b9c875b8SPierre Jolivet 
2022c16cb8f2SBarry Smith /*@C
202311a5261eSBarry Smith   MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
2024f3b1f45cSBarry Smith 
2025cf53795eSBarry Smith   Logically Collective; No Fortran Support
2026f3b1f45cSBarry Smith 
2027f3b1f45cSBarry Smith   Input Parameters:
202811a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
2029f3b1f45cSBarry Smith . f    - the function
203011a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
2031f3b1f45cSBarry Smith - ctx  - an optional context for the function
2032f3b1f45cSBarry Smith 
2033f3b1f45cSBarry Smith   Output Parameter:
203411a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
2035f3b1f45cSBarry Smith 
20363c7db156SBarry Smith   Options Database Key:
2037f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
2038f3b1f45cSBarry Smith 
2039f3b1f45cSBarry Smith   Level: advanced
2040f3b1f45cSBarry Smith 
20411cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
2042f3b1f45cSBarry Smith @*/
2043d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
2044d71ae5a4SJacob Faibussowitsch {
2045f3b1f45cSBarry Smith   PetscInt  m, n;
2046f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
2047f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
204874e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2049f3b1f45cSBarry Smith 
2050f3b1f45cSBarry Smith   PetscFunctionBegin;
2051f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
20529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
20539566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20549566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
20559566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
20569566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
2057f3b1f45cSBarry Smith 
20589566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
20599566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
2060f3b1f45cSBarry Smith 
20619566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
20629566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
20639566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
20649566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2065f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2066f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2067f3b1f45cSBarry Smith     if (v) {
206801c1178eSBarry 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)));
20699566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
20709566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
20719566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
2072f3b1f45cSBarry Smith     }
2073f3b1f45cSBarry Smith   } else if (v) {
207401c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n"));
2075f3b1f45cSBarry Smith   }
2076f3b1f45cSBarry Smith   if (flg) *flg = flag;
20779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
20789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
20799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
20809566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
20813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2082f3b1f45cSBarry Smith }
2083f3b1f45cSBarry Smith 
2084f3b1f45cSBarry Smith /*@C
208511a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
2086f3b1f45cSBarry Smith 
2087cf53795eSBarry Smith   Logically Collective; No Fortran Support
2088f3b1f45cSBarry Smith 
2089f3b1f45cSBarry Smith   Input Parameters:
209011a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
2091f3b1f45cSBarry Smith . f    - the function
209211a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
2093f3b1f45cSBarry Smith - ctx  - an optional context for the function
2094f3b1f45cSBarry Smith 
2095f3b1f45cSBarry Smith   Output Parameter:
209611a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
2097f3b1f45cSBarry Smith 
20983c7db156SBarry Smith   Options Database Key:
2099f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
2100f3b1f45cSBarry Smith 
2101f3b1f45cSBarry Smith   Level: advanced
2102f3b1f45cSBarry Smith 
21031cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
2104f3b1f45cSBarry Smith @*/
2105d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg)
2106d71ae5a4SJacob Faibussowitsch {
2107f3b1f45cSBarry Smith   Vec       x, y, z;
2108f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
2109f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
2110f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
211174e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2112f3b1f45cSBarry Smith 
2113f3b1f45cSBarry Smith   PetscFunctionBegin;
2114f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
21159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
21169566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
21179566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
21189566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
21199566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
21209566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
21219566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
21229566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
21239566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
21249566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
21259566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
2126f3b1f45cSBarry Smith 
21279566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
21289566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
21299566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
21309566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2131f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2132f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2133f3b1f45cSBarry Smith     if (v) {
213401c1178eSBarry 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)));
21359566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
21369566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
21379566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
2138f3b1f45cSBarry Smith     }
2139f3b1f45cSBarry Smith   } else if (v) {
214001c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n"));
2141f3b1f45cSBarry Smith   }
2142f3b1f45cSBarry Smith   if (flg) *flg = flag;
21439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
21449566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
21459566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
21469566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
21479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
21489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
21499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
21503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2151f3b1f45cSBarry Smith }
2152f3b1f45cSBarry Smith 
2153f3b1f45cSBarry Smith /*@C
215411a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
2155e51e0e81SBarry Smith 
2156c3339decSBarry Smith   Logically Collective
2157fee21e36SBarry Smith 
2158c7fcc2eaSBarry Smith   Input Parameters:
215911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2160c7fcc2eaSBarry Smith . op  - the name of the operation
2161789d8953SBarry Smith - g   - the function that provides the operation.
2162c7fcc2eaSBarry Smith 
216315091d37SBarry Smith   Level: advanced
216415091d37SBarry Smith 
21652920cce0SJacob Faibussowitsch   Example Usage:
2166c3339decSBarry Smith .vb
2167c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
21682920cce0SJacob Faibussowitsch 
2169c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
2170c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
2171c3339decSBarry Smith .ve
21720b627109SLois Curfman McInnes 
2173a62d957aSLois Curfman McInnes   Notes:
2174e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
21751c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2176a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
217711a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2178a62d957aSLois Curfman McInnes 
217911a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2180deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2181deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2182deebb3c3SLois Curfman McInnes   routines, e.g.,
2183a62d957aSLois Curfman McInnes $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2184a62d957aSLois Curfman McInnes 
21854aa34b0aSBarry Smith   In particular each function MUST return an error code of 0 on success and
21864aa34b0aSBarry Smith   nonzero on failure.
21874aa34b0aSBarry Smith 
2188a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
218911a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
219011a5261eSBarry Smith   set by `MatCreateShell()`.
2191a62d957aSLois Curfman McInnes 
21922ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
21932ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2194b77ba244SStefano Zampini 
2195fe59aa6dSJacob Faibussowitsch   Fortran Notes:
219611a5261eSBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not
2197c4762a1bSJed Brown   generate a matrix. See src/mat/tests/ex120f.F
2198501d9185SBarry Smith 
21991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2200e51e0e81SBarry Smith @*/
2201d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void))
2202d71ae5a4SJacob Faibussowitsch {
22033a40ed3dSBarry Smith   PetscFunctionBegin;
22040700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2205cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g));
22063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2207e51e0e81SBarry Smith }
2208f0479e8cSBarry Smith 
2209d4bb536fSBarry Smith /*@C
221011a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2211d4bb536fSBarry Smith 
2212c7fcc2eaSBarry Smith   Not Collective
2213c7fcc2eaSBarry Smith 
2214d4bb536fSBarry Smith   Input Parameters:
221511a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2216c7fcc2eaSBarry Smith - op  - the name of the operation
2217d4bb536fSBarry Smith 
2218d4bb536fSBarry Smith   Output Parameter:
2219789d8953SBarry Smith . g - the function that provides the operation.
2220d4bb536fSBarry Smith 
222115091d37SBarry Smith   Level: advanced
222215091d37SBarry Smith 
222327430b45SBarry Smith   Notes:
2224e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2225d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2226d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
222711a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2228d4bb536fSBarry Smith 
2229d4bb536fSBarry Smith   All user-provided functions have the same calling
2230d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2231d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2232d4bb536fSBarry Smith   routines, e.g.,
2233d4bb536fSBarry Smith $       MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2234d4bb536fSBarry Smith 
2235d4bb536fSBarry Smith   Within each user-defined routine, the user should call
223611a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
223711a5261eSBarry Smith   set by `MatCreateShell()`.
2238d4bb536fSBarry Smith 
22391cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2240d4bb536fSBarry Smith @*/
2241d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void))
2242d71ae5a4SJacob Faibussowitsch {
22433a40ed3dSBarry Smith   PetscFunctionBegin;
22440700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2245cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g));
22463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2247d4bb536fSBarry Smith }
2248b77ba244SStefano Zampini 
2249b77ba244SStefano Zampini /*@
225011a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2251b77ba244SStefano Zampini 
2252b77ba244SStefano Zampini   Input Parameter:
2253b77ba244SStefano Zampini . mat - the matrix
2254b77ba244SStefano Zampini 
2255b77ba244SStefano Zampini   Output Parameter:
225622299d08SPierre Jolivet . flg - the Boolean value
2257b77ba244SStefano Zampini 
2258b77ba244SStefano Zampini   Level: developer
2259b77ba244SStefano Zampini 
22601cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2261b77ba244SStefano Zampini @*/
2262d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2263d71ae5a4SJacob Faibussowitsch {
2264b77ba244SStefano Zampini   PetscFunctionBegin;
2265b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
22664f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
2267b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
22683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2269b77ba244SStefano Zampini }
2270