xref: /petsc/src/mat/impls/shell/shell.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
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 */
MatShellPreZeroRight(Mat A,Vec x,Vec * xx)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 */
MatShellPostZeroLeft(Mat A,Vec x)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 */
MatShellPreZeroLeft(Mat A,Vec x,Vec * xx)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 */
MatShellPostZeroRight(Mat A,Vec x)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 */
MatShellPreScaleLeft(Mat A,Vec x,Vec * xx,PetscBool conjugate)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 */
MatShellPreScaleRight(Mat A,Vec x,Vec * xx)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 */
MatShellPostScaleLeft(Mat A,Vec x)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 */
MatShellPostScaleRight(Mat A,Vec x,PetscBool conjugate)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 */
MatShellShiftAndScale(Mat A,Vec X,Vec Y,PetscBool conjugate)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 
MatShellGetContext_Shell(Mat mat,PetscCtxRt ctx)209*2a8381b2SBarry Smith static PetscErrorCode MatShellGetContext_Shell(Mat mat, PetscCtxRt ctx)
210d71ae5a4SJacob Faibussowitsch {
211800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
212800f99ffSJeremy L Thompson 
213789d8953SBarry Smith   PetscFunctionBegin;
214*2a8381b2SBarry Smith   if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, 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:
233*2a8381b2SBarry Smith   This only works when the context is a Fortran derived type or a `PetscObject`. Declare `ctx` with
234*2a8381b2SBarry Smith .vb
235*2a8381b2SBarry Smith   type(tUsertype), pointer :: ctx
236*2a8381b2SBarry Smith .ve
237a62d957aSLois Curfman McInnes 
2381cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()`
2390bc0a719SBarry Smith @*/
MatShellGetContext(Mat mat,PetscCtxRt ctx)240*2a8381b2SBarry Smith PetscErrorCode MatShellGetContext(Mat mat, PetscCtxRt ctx)
241d71ae5a4SJacob Faibussowitsch {
2423a40ed3dSBarry Smith   PetscFunctionBegin;
2430700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2444f572ea9SToby Isaac   PetscAssertPointer(ctx, 2);
245cac4c232SBarry Smith   PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx));
2463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
247b4fd4287SBarry Smith }
248b4fd4287SBarry Smith 
MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)249d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc)
250d71ae5a4SJacob Faibussowitsch {
25145960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell *)mat->data;
25245960306SStefano Zampini   Vec             x = NULL, b = NULL;
25345960306SStefano Zampini   IS              is1, is2;
25445960306SStefano Zampini   const PetscInt *ridxs;
25545960306SStefano Zampini   PetscInt       *idxs, *gidxs;
25645960306SStefano Zampini   PetscInt        cum, rst, cst, i;
25745960306SStefano Zampini 
25845960306SStefano Zampini   PetscFunctionBegin;
25948a46eb9SPierre Jolivet   if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals));
26048a46eb9SPierre Jolivet   if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w));
2619566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(mat, &rst, NULL));
2629566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL));
26345960306SStefano Zampini 
26445960306SStefano Zampini   /* Expand/create index set of zeroed rows */
2659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &idxs));
26645960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
267bd72c1ddSStefano Zampini   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nr, idxs, PETSC_OWN_POINTER, &is1));
2689566063dSJacob Faibussowitsch   PetscCall(ISSort(is1));
2699566063dSJacob Faibussowitsch   PetscCall(VecISSet(shell->zvals, is1, diag));
27045960306SStefano Zampini   if (shell->zrows) {
2719566063dSJacob Faibussowitsch     PetscCall(ISSum(shell->zrows, is1, &is2));
2729566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
2739566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is1));
27445960306SStefano Zampini     shell->zrows = is2;
27545960306SStefano Zampini   } else shell->zrows = is1;
27645960306SStefano Zampini 
27745960306SStefano Zampini   /* Create scatters for diagonal values communications */
2789566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
2799566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
28045960306SStefano Zampini 
28145960306SStefano Zampini   /* row scatter: from/to left vector */
2829566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &b));
2839566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r));
28445960306SStefano Zampini 
28545960306SStefano Zampini   /* col scatter: from right vector to left vector */
2869566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(shell->zrows, &ridxs));
2879566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(shell->zrows, &nr));
2889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &gidxs));
28945960306SStefano Zampini   for (i = 0, cum = 0; i < nr; i++) {
29045960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
29145960306SStefano Zampini     gidxs[cum] = ridxs[i];
29245960306SStefano Zampini     cum++;
29345960306SStefano Zampini   }
2949566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1));
2959566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c));
2969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is1));
2979566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
2989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b));
29945960306SStefano Zampini 
30045960306SStefano Zampini   /* Expand/create index set of zeroed columns */
30145960306SStefano Zampini   if (rc) {
3029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc, &idxs));
30345960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
304bd72c1ddSStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nc, idxs, PETSC_OWN_POINTER, &is1));
3059566063dSJacob Faibussowitsch     PetscCall(ISSort(is1));
30645960306SStefano Zampini     if (shell->zcols) {
3079566063dSJacob Faibussowitsch       PetscCall(ISSum(shell->zcols, is1, &is2));
3089566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&shell->zcols));
3099566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is1));
31045960306SStefano Zampini       shell->zcols = is2;
31145960306SStefano Zampini     } else shell->zcols = is1;
31245960306SStefano Zampini   }
3133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31445960306SStefano Zampini }
31545960306SStefano Zampini 
MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)316d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
317d71ae5a4SJacob Faibussowitsch {
318ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
31945960306SStefano Zampini   PetscInt   nr, *lrows;
32045960306SStefano Zampini 
32145960306SStefano Zampini   PetscFunctionBegin;
32245960306SStefano Zampini   if (x && b) {
32345960306SStefano Zampini     Vec          xt;
32445960306SStefano Zampini     PetscScalar *vals;
32545960306SStefano Zampini     PetscInt    *gcols, i, st, nl, nc;
32645960306SStefano Zampini 
3279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &gcols));
3289371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3299371c9d4SSatish Balay       if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
33045960306SStefano Zampini 
3319566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, NULL));
3329566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3339566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nc, &vals));
3349566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3359566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
3369566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3389566063dSJacob Faibussowitsch     PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */
33945960306SStefano Zampini 
3409566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3419566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
3429566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
34345960306SStefano Zampini     for (i = 0; i < nl; i++) {
34445960306SStefano Zampini       PetscInt g = i + st;
34545960306SStefano Zampini       if (g > mat->rmap->N) continue;
34645960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
3479566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES));
34845960306SStefano Zampini     }
3499566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
3509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
3519566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1, x2 * diag] */
3529566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
3539566063dSJacob Faibussowitsch     PetscCall(PetscFree(gcols));
35445960306SStefano Zampini   }
3559566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL));
3569566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE));
3571baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL));
3589566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
3593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36045960306SStefano Zampini }
36145960306SStefano Zampini 
MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)362d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b)
363d71ae5a4SJacob Faibussowitsch {
364ef5c7bd2SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)mat->data;
36545960306SStefano Zampini   PetscInt  *lrows, *lcols;
36645960306SStefano Zampini   PetscInt   nr, nc;
36745960306SStefano Zampini   PetscBool  congruent;
36845960306SStefano Zampini 
36945960306SStefano Zampini   PetscFunctionBegin;
37045960306SStefano Zampini   if (x && b) {
37145960306SStefano Zampini     Vec          xt, bt;
37245960306SStefano Zampini     PetscScalar *vals;
37345960306SStefano Zampini     PetscInt    *grows, *gcols, i, st, nl;
37445960306SStefano Zampini 
3759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(n, &grows, n, &gcols));
3769371c9d4SSatish Balay     for (i = 0, nr = 0; i < n; i++)
3779371c9d4SSatish Balay       if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
3789371c9d4SSatish Balay     for (i = 0, nc = 0; i < n; i++)
3799371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
3809566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(n, &vals));
38145960306SStefano Zampini 
3829566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &xt, &bt));
3839566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, xt));
3849566063dSJacob Faibussowitsch     PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */
3859566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(xt));
3869566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(xt));
3879566063dSJacob Faibussowitsch     PetscCall(VecAXPY(xt, -1.0, x));                             /* xt = [0, -x2] */
3889566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, xt, bt));                             /* bt = [-A12*x2,-A22*x2] */
3899566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */
3909566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
3919566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
3929566063dSJacob Faibussowitsch     PetscCall(VecAXPY(b, 1.0, bt));                              /* b  = [b1 - A12*x2, b2] */
3939566063dSJacob Faibussowitsch     PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b  = [b1 - A12*x2, 0] */
3949566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(bt));
3959566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(bt));
3969566063dSJacob Faibussowitsch     PetscCall(PetscFree(vals));
39745960306SStefano Zampini 
3989566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(xt, &st, NULL));
3999566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(xt, &nl));
4009566063dSJacob Faibussowitsch     PetscCall(VecGetArray(xt, &vals));
40145960306SStefano Zampini     for (i = 0; i < nl; i++) {
40245960306SStefano Zampini       PetscInt g = i + st;
40345960306SStefano Zampini       if (g > mat->rmap->N) continue;
40445960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
4059566063dSJacob Faibussowitsch       PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES));
40645960306SStefano Zampini     }
4079566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(xt, &vals));
4089566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(b));
4099566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(b)); /* b  = [b1 - A12*x2, x2 * diag] */
4109566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xt));
4119566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bt));
4129566063dSJacob Faibussowitsch     PetscCall(PetscFree2(grows, gcols));
41345960306SStefano Zampini   }
4149566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL));
4159566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(mat, &congruent));
41645960306SStefano Zampini   if (congruent) {
41745960306SStefano Zampini     nc    = nr;
41845960306SStefano Zampini     lcols = lrows;
41945960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
42045960306SStefano Zampini     PetscInt i, nt, *t;
42145960306SStefano Zampini 
4229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &t));
4239371c9d4SSatish Balay     for (i = 0, nt = 0; i < n; i++)
4249371c9d4SSatish Balay       if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
4259566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL));
4269566063dSJacob Faibussowitsch     PetscCall(PetscFree(t));
42745960306SStefano Zampini   }
4289566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE));
42948a46eb9SPierre Jolivet   if (!congruent) PetscCall(PetscFree(lcols));
4309566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
4311baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL));
4323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43345960306SStefano Zampini }
43445960306SStefano Zampini 
MatDestroy_Shell(Mat mat)435d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat)
436d71ae5a4SJacob Faibussowitsch {
437bf0cc555SLisandro Dalcin   Mat_Shell              *shell = (Mat_Shell *)mat->data;
438b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
439ed3cc1f0SBarry Smith 
4403a40ed3dSBarry Smith   PetscFunctionBegin;
4411baa6e33SBarry Smith   if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat));
4429566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps)));
4439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
4449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
4459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->dshift));
4469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_work));
4479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_work));
4489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left_add_work));
4499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right_add_work));
4509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_left));
4519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->axpy_right));
4529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shell->axpy));
4539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals_w));
4549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->zvals));
4559566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
4569566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
4579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zrows));
4589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&shell->zcols));
459b77ba244SStefano Zampini 
460b77ba244SStefano Zampini   matmat = shell->matmat;
461b77ba244SStefano Zampini   while (matmat) {
462b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
463b77ba244SStefano Zampini 
4649566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL));
4659566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->composedname));
4669566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat->resultname));
4679566063dSJacob Faibussowitsch     PetscCall(PetscFree(matmat));
468b77ba244SStefano Zampini     matmat = next;
469b77ba244SStefano Zampini   }
470800f99ffSJeremy L Thompson   PetscCall(MatShellSetContext(mat, NULL));
4719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL));
4729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL));
473800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL));
4749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL));
4759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL));
476b9c875b8SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetScalingShifts_C", NULL));
4779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL));
4789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL));
4799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL));
4809566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
4813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
482b77ba244SStefano Zampini }
483b77ba244SStefano Zampini 
484b77ba244SStefano Zampini typedef struct {
485b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat, Mat, Mat, void *);
486cc1eb50dSBarry Smith   PetscCtxDestroyFn *destroy;
487*2a8381b2SBarry Smith   void              *ctx;
488b77ba244SStefano Zampini   Mat                B;
489b77ba244SStefano Zampini   Mat                Bt;
490b77ba244SStefano Zampini   Mat                axpy;
491cc1eb50dSBarry Smith } MatProductCtx_MatMatShell;
492b77ba244SStefano Zampini 
MatProductCtxDestroy_MatMatShell(PetscCtxRt data)493*2a8381b2SBarry Smith static PetscErrorCode MatProductCtxDestroy_MatMatShell(PetscCtxRt data)
494d71ae5a4SJacob Faibussowitsch {
495cc1eb50dSBarry Smith   MatProductCtx_MatMatShell *mmdata = *(MatProductCtx_MatMatShell **)data;
496b77ba244SStefano Zampini 
497b77ba244SStefano Zampini   PetscFunctionBegin;
498*2a8381b2SBarry Smith   if (mmdata->destroy) PetscCall((*mmdata->destroy)(&mmdata->ctx));
4999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->B));
5009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->Bt));
5019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->axpy));
5029566063dSJacob Faibussowitsch   PetscCall(PetscFree(mmdata));
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504b77ba244SStefano Zampini }
505b77ba244SStefano Zampini 
MatProductNumeric_Shell_X(Mat D)506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
507d71ae5a4SJacob Faibussowitsch {
508b77ba244SStefano Zampini   Mat_Product               *product;
509b77ba244SStefano Zampini   Mat                        A, B;
510cc1eb50dSBarry Smith   MatProductCtx_MatMatShell *mdata;
511966bd95aSPierre Jolivet   Mat_Shell                 *shell;
512966bd95aSPierre Jolivet   PetscBool                  useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
513966bd95aSPierre Jolivet   PetscErrorCode (*stashsym)(Mat), (*stashnum)(Mat);
514b77ba244SStefano Zampini 
515b77ba244SStefano Zampini   PetscFunctionBegin;
516b77ba244SStefano Zampini   MatCheckProduct(D, 1);
517b77ba244SStefano Zampini   product = D->product;
51828b400f6SJacob Faibussowitsch   PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
519b77ba244SStefano Zampini   A     = product->A;
520b77ba244SStefano Zampini   B     = product->B;
521cc1eb50dSBarry Smith   mdata = (MatProductCtx_MatMatShell *)product->data;
522966bd95aSPierre Jolivet   PetscCheck(mdata->numeric, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation");
523966bd95aSPierre Jolivet   shell    = (Mat_Shell *)A->data;
524966bd95aSPierre Jolivet   stashsym = D->ops->productsymbolic;
525966bd95aSPierre Jolivet   stashnum = D->ops->productnumeric;
526b77ba244SStefano Zampini   if (shell->managescalingshifts) {
52708401ef6SPierre Jolivet     PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns");
528b77ba244SStefano Zampini     if (shell->right || shell->left) {
529b77ba244SStefano Zampini       useBmdata = PETSC_TRUE;
530b77ba244SStefano Zampini       if (!mdata->B) {
5319566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B));
532b77ba244SStefano Zampini       } else {
533b77ba244SStefano Zampini         newB = PETSC_FALSE;
534b77ba244SStefano Zampini       }
5359566063dSJacob Faibussowitsch       PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN));
536b77ba244SStefano Zampini     }
537b77ba244SStefano Zampini     switch (product->type) {
538b77ba244SStefano Zampini     case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
5391baa6e33SBarry Smith       if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
540b77ba244SStefano Zampini       break;
541b77ba244SStefano Zampini     case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
5421baa6e33SBarry Smith       if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL));
543b77ba244SStefano Zampini       break;
544b77ba244SStefano Zampini     case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
5451baa6e33SBarry Smith       if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
546b77ba244SStefano Zampini       break;
547b77ba244SStefano Zampini     case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
548b77ba244SStefano Zampini       if (shell->right && shell->left) {
549b77ba244SStefano Zampini         PetscBool flg;
550b77ba244SStefano Zampini 
5519566063dSJacob Faibussowitsch         PetscCall(VecEqual(shell->right, shell->left, &flg));
5529371c9d4SSatish 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,
5539371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
554b77ba244SStefano Zampini       }
5551baa6e33SBarry Smith       if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right));
556b77ba244SStefano Zampini       break;
557b77ba244SStefano Zampini     case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
558b77ba244SStefano Zampini       if (shell->right && shell->left) {
559b77ba244SStefano Zampini         PetscBool flg;
560b77ba244SStefano Zampini 
5619566063dSJacob Faibussowitsch         PetscCall(VecEqual(shell->right, shell->left, &flg));
5629371c9d4SSatish 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,
5639371c9d4SSatish Balay                    ((PetscObject)B)->type_name);
564b77ba244SStefano Zampini       }
5651baa6e33SBarry Smith       if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL));
566b77ba244SStefano Zampini       break;
567d71ae5a4SJacob Faibussowitsch     default:
568d71ae5a4SJacob 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);
569b77ba244SStefano Zampini     }
570b77ba244SStefano Zampini   }
571b77ba244SStefano Zampini   /* allow the user to call MatMat operations on D */
572b77ba244SStefano Zampini   D->product              = NULL;
573b77ba244SStefano Zampini   D->ops->productsymbolic = NULL;
574b77ba244SStefano Zampini   D->ops->productnumeric  = NULL;
575b77ba244SStefano Zampini 
576*2a8381b2SBarry Smith   PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->ctx));
577b77ba244SStefano Zampini 
578b77ba244SStefano Zampini   /* clear any leftover user data and restore D pointers */
5799566063dSJacob Faibussowitsch   PetscCall(MatProductClear(D));
580b77ba244SStefano Zampini   D->ops->productsymbolic = stashsym;
581b77ba244SStefano Zampini   D->ops->productnumeric  = stashnum;
582b77ba244SStefano Zampini   D->product              = product;
583b77ba244SStefano Zampini 
584b77ba244SStefano Zampini   if (shell->managescalingshifts) {
5859566063dSJacob Faibussowitsch     PetscCall(MatScale(D, shell->vscale));
586b77ba244SStefano Zampini     switch (product->type) {
587b77ba244SStefano Zampini     case MATPRODUCT_AB:  /* s L A R B + v L R B + L D R B */
588b77ba244SStefano Zampini     case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
589b77ba244SStefano Zampini       if (shell->left) {
5909566063dSJacob Faibussowitsch         PetscCall(MatDiagonalScale(D, shell->left, NULL));
591966bd95aSPierre Jolivet         if (shell->dshift || shell->vshift != 0.0) {
5929566063dSJacob Faibussowitsch           if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work));
593b77ba244SStefano Zampini           if (shell->dshift) {
5949566063dSJacob Faibussowitsch             PetscCall(VecCopy(shell->dshift, shell->left_work));
5959566063dSJacob Faibussowitsch             PetscCall(VecShift(shell->left_work, shell->vshift));
5969566063dSJacob Faibussowitsch             PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left));
597b77ba244SStefano Zampini           } else {
5989566063dSJacob Faibussowitsch             PetscCall(VecSet(shell->left_work, shell->vshift));
599b77ba244SStefano Zampini           }
600b77ba244SStefano Zampini           if (product->type == MATPRODUCT_ABt) {
601b77ba244SStefano Zampini             MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
602b77ba244SStefano Zampini             MatStructure str   = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
603b77ba244SStefano Zampini 
6049566063dSJacob Faibussowitsch             PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt));
6059566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL));
6069566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->Bt, str));
607b77ba244SStefano Zampini           } else {
608b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
609b77ba244SStefano Zampini 
6109566063dSJacob Faibussowitsch             PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL));
6119566063dSJacob Faibussowitsch             PetscCall(MatAXPY(D, 1.0, mdata->B, str));
612b77ba244SStefano Zampini           }
613b77ba244SStefano Zampini         }
614b77ba244SStefano Zampini       }
615b77ba244SStefano Zampini       break;
616b77ba244SStefano Zampini     case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
617b77ba244SStefano Zampini       if (shell->right) {
6189566063dSJacob Faibussowitsch         PetscCall(MatDiagonalScale(D, shell->right, NULL));
619966bd95aSPierre Jolivet         if (shell->dshift || shell->vshift != 0.0) {
620b77ba244SStefano Zampini           MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
621b77ba244SStefano Zampini 
6229566063dSJacob Faibussowitsch           if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL));
623b77ba244SStefano Zampini           if (shell->dshift) {
6249566063dSJacob Faibussowitsch             PetscCall(VecCopy(shell->dshift, shell->right_work));
6259566063dSJacob Faibussowitsch             PetscCall(VecShift(shell->right_work, shell->vshift));
6269566063dSJacob Faibussowitsch             PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right));
627b77ba244SStefano Zampini           } else {
6289566063dSJacob Faibussowitsch             PetscCall(VecSet(shell->right_work, shell->vshift));
629b77ba244SStefano Zampini           }
6309566063dSJacob Faibussowitsch           PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL));
6319566063dSJacob Faibussowitsch           PetscCall(MatAXPY(D, 1.0, mdata->B, str));
632b77ba244SStefano Zampini         }
633b77ba244SStefano Zampini       }
634b77ba244SStefano Zampini       break;
635b77ba244SStefano Zampini     case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
636b77ba244SStefano Zampini     case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
637966bd95aSPierre Jolivet       PetscCheck(!shell->dshift && shell->vshift == 0.0, 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,
6389371c9d4SSatish Balay                  ((PetscObject)B)->type_name);
639b77ba244SStefano Zampini       break;
640d71ae5a4SJacob Faibussowitsch     default:
641d71ae5a4SJacob 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);
642b77ba244SStefano Zampini     }
643966bd95aSPierre Jolivet     if (shell->axpy && shell->axpy_vscale != 0.0) {
644b77ba244SStefano Zampini       Mat              X;
645b77ba244SStefano Zampini       PetscObjectState axpy_state;
646b77ba244SStefano Zampini       MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
647b77ba244SStefano Zampini 
6489566063dSJacob Faibussowitsch       PetscCall(MatShellGetContext(shell->axpy, &X));
6499566063dSJacob Faibussowitsch       PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
65008401ef6SPierre 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,...)");
651b77ba244SStefano Zampini       if (!mdata->axpy) {
652b77ba244SStefano Zampini         str = DIFFERENT_NONZERO_PATTERN;
6539566063dSJacob Faibussowitsch         PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy));
6549566063dSJacob Faibussowitsch         PetscCall(MatProductSetType(mdata->axpy, product->type));
6559566063dSJacob Faibussowitsch         PetscCall(MatProductSetFromOptions(mdata->axpy));
6569566063dSJacob Faibussowitsch         PetscCall(MatProductSymbolic(mdata->axpy));
657b77ba244SStefano Zampini       } else { /* May be that shell->axpy has changed */
658b77ba244SStefano Zampini         PetscBool flg;
659b77ba244SStefano Zampini 
6609566063dSJacob Faibussowitsch         PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy));
6619566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg));
662b77ba244SStefano Zampini         if (!flg) {
663b77ba244SStefano Zampini           str = DIFFERENT_NONZERO_PATTERN;
6649566063dSJacob Faibussowitsch           PetscCall(MatProductSetFromOptions(mdata->axpy));
6659566063dSJacob Faibussowitsch           PetscCall(MatProductSymbolic(mdata->axpy));
666b77ba244SStefano Zampini         }
667b77ba244SStefano Zampini       }
6689566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(mdata->axpy));
6699566063dSJacob Faibussowitsch       PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str));
670b77ba244SStefano Zampini     }
671b77ba244SStefano Zampini   }
6723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
673b77ba244SStefano Zampini }
674b77ba244SStefano Zampini 
MatProductSymbolic_Shell_X(Mat D)675d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
676d71ae5a4SJacob Faibussowitsch {
677b77ba244SStefano Zampini   Mat_Product               *product;
678b77ba244SStefano Zampini   Mat                        A, B;
679b77ba244SStefano Zampini   MatShellMatFunctionList    matmat;
680b77ba244SStefano Zampini   Mat_Shell                 *shell;
681eae3dc7dSJacob Faibussowitsch   PetscBool                  flg = PETSC_FALSE;
682b77ba244SStefano Zampini   char                       composedname[256];
683cc1eb50dSBarry Smith   MatProductCtx_MatMatShell *mdata;
684b77ba244SStefano Zampini 
685b77ba244SStefano Zampini   PetscFunctionBegin;
686b77ba244SStefano Zampini   MatCheckProduct(D, 1);
687b77ba244SStefano Zampini   product = D->product;
68828b400f6SJacob Faibussowitsch   PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
689b77ba244SStefano Zampini   A      = product->A;
690b77ba244SStefano Zampini   B      = product->B;
691b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
692b77ba244SStefano Zampini   matmat = shell->matmat;
6939566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
694b77ba244SStefano Zampini   while (matmat) {
6959566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
696b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
697b77ba244SStefano Zampini     if (flg) break;
698b77ba244SStefano Zampini     matmat = matmat->next;
699b77ba244SStefano Zampini   }
70028b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]);
701b77ba244SStefano Zampini   switch (product->type) {
702d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
703d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
704d71ae5a4SJacob Faibussowitsch     break;
705d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
706d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
707d71ae5a4SJacob Faibussowitsch     break;
708d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
709d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
710d71ae5a4SJacob Faibussowitsch     break;
711d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
712d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N));
713d71ae5a4SJacob Faibussowitsch     break;
714d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
715d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N));
716d71ae5a4SJacob Faibussowitsch     break;
717d71ae5a4SJacob Faibussowitsch   default:
718d71ae5a4SJacob 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);
719b77ba244SStefano Zampini   }
720b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
721b77ba244SStefano Zampini   if (matmat->resultname) {
7229566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg));
72348a46eb9SPierre Jolivet     if (!flg) PetscCall(MatSetType(D, matmat->resultname));
724b77ba244SStefano Zampini   }
725b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
726b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
727b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
728b77ba244SStefano Zampini   /* attach product data */
7299566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mdata));
730b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
731b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
732b77ba244SStefano Zampini   if (matmat->symbolic) {
733*2a8381b2SBarry Smith     PetscCall((*matmat->symbolic)(A, B, D, &mdata->ctx));
734b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
7359566063dSJacob Faibussowitsch     PetscCall(MatSetUp(D));
736b77ba244SStefano Zampini   }
73728b400f6SJacob Faibussowitsch   PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase");
73828b400f6SJacob Faibussowitsch   PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase");
739b77ba244SStefano Zampini   D->product->data    = mdata;
740cc1eb50dSBarry Smith   D->product->destroy = MatProductCtxDestroy_MatMatShell;
741b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
742b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
743b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
7443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
745b77ba244SStefano Zampini }
746b77ba244SStefano Zampini 
MatProductSetFromOptions_Shell_X(Mat D)747d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
748d71ae5a4SJacob Faibussowitsch {
749b77ba244SStefano Zampini   Mat_Product            *product;
750b77ba244SStefano Zampini   Mat                     A, B;
751b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
752b77ba244SStefano Zampini   Mat_Shell              *shell;
753b77ba244SStefano Zampini   PetscBool               flg;
754b77ba244SStefano Zampini   char                    composedname[256];
755b77ba244SStefano Zampini 
756b77ba244SStefano Zampini   PetscFunctionBegin;
757b77ba244SStefano Zampini   MatCheckProduct(D, 1);
758b77ba244SStefano Zampini   product = D->product;
759b77ba244SStefano Zampini   A       = product->A;
760b77ba244SStefano Zampini   B       = product->B;
7619566063dSJacob Faibussowitsch   PetscCall(MatIsShell(A, &flg));
7623ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
763b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
764b77ba244SStefano Zampini   matmat = shell->matmat;
7659566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name));
766b77ba244SStefano Zampini   while (matmat) {
7679566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg));
768b77ba244SStefano Zampini     flg = (PetscBool)(flg && (matmat->ptype == product->type));
769b77ba244SStefano Zampini     if (flg) break;
770b77ba244SStefano Zampini     matmat = matmat->next;
771b77ba244SStefano Zampini   }
7729371c9d4SSatish Balay   if (flg) {
7739371c9d4SSatish Balay     D->ops->productsymbolic = MatProductSymbolic_Shell_X;
7749371c9d4SSatish Balay   } else PetscCall(PetscInfo(D, "  symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type]));
7753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
776b77ba244SStefano Zampini }
777b77ba244SStefano Zampini 
MatShellSetMatProductOperation_Private(Mat A,MatProductType ptype,PetscErrorCode (* symbolic)(Mat,Mat,Mat,void **),PetscErrorCode (* numeric)(Mat,Mat,Mat,void *),PetscCtxDestroyFn * destroy,char * composedname,const char * resultname)778cc1eb50dSBarry Smith static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscCtxDestroyFn *destroy, char *composedname, const char *resultname)
779d71ae5a4SJacob Faibussowitsch {
780b77ba244SStefano Zampini   PetscBool               flg;
781b77ba244SStefano Zampini   Mat_Shell              *shell;
782b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
783b77ba244SStefano Zampini 
784b77ba244SStefano Zampini   PetscFunctionBegin;
78528b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine");
78628b400f6SJacob Faibussowitsch   PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name");
787b77ba244SStefano Zampini 
788b77ba244SStefano Zampini   /* add product callback */
789b77ba244SStefano Zampini   shell  = (Mat_Shell *)A->data;
790b77ba244SStefano Zampini   matmat = shell->matmat;
791b77ba244SStefano Zampini   if (!matmat) {
7929566063dSJacob Faibussowitsch     PetscCall(PetscNew(&shell->matmat));
793b77ba244SStefano Zampini     matmat = shell->matmat;
794b77ba244SStefano Zampini   } else {
795b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
796b77ba244SStefano Zampini     while (entry) {
7979566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(composedname, entry->composedname, &flg));
798b77ba244SStefano Zampini       flg    = (PetscBool)(flg && (entry->ptype == ptype));
799b77ba244SStefano Zampini       matmat = entry;
8002e956fe4SStefano Zampini       if (flg) goto set;
801b77ba244SStefano Zampini       entry = entry->next;
802b77ba244SStefano Zampini     }
8039566063dSJacob Faibussowitsch     PetscCall(PetscNew(&matmat->next));
804b77ba244SStefano Zampini     matmat = matmat->next;
805b77ba244SStefano Zampini   }
806b77ba244SStefano Zampini 
807843d480fSStefano Zampini set:
808b77ba244SStefano Zampini   matmat->symbolic = symbolic;
809b77ba244SStefano Zampini   matmat->numeric  = numeric;
810b77ba244SStefano Zampini   matmat->destroy  = destroy;
811b77ba244SStefano Zampini   matmat->ptype    = ptype;
8129566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->composedname));
8139566063dSJacob Faibussowitsch   PetscCall(PetscFree(matmat->resultname));
8149566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(composedname, &matmat->composedname));
8159566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(resultname, &matmat->resultname));
8169566063dSJacob 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"));
8179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X));
8183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
819b77ba244SStefano Zampini }
820b77ba244SStefano Zampini 
821b77ba244SStefano Zampini /*@C
82211a5261eSBarry Smith   MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix.
823b77ba244SStefano Zampini 
82427430b45SBarry Smith   Logically Collective; No Fortran Support
825b77ba244SStefano Zampini 
826b77ba244SStefano Zampini   Input Parameters:
82711a5261eSBarry Smith + A        - the `MATSHELL` shell matrix
828b77ba244SStefano Zampini . ptype    - the product type
8292ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`)
830b77ba244SStefano Zampini . numeric  - the function for the numerical phase
8312ef1f0ffSBarry Smith . destroy  - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`)
832b77ba244SStefano Zampini . Btype    - the matrix type for the matrix to be multiplied against
8332ef1f0ffSBarry Smith - Ctype    - the matrix type for the result (can be `NULL`)
834b77ba244SStefano Zampini 
835b77ba244SStefano Zampini   Level: advanced
836b77ba244SStefano Zampini 
8372920cce0SJacob Faibussowitsch   Example Usage:
838cf53795eSBarry Smith .vb
839cf53795eSBarry Smith   extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**);
840cf53795eSBarry Smith   extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*);
841cc1eb50dSBarry Smith   PetscCtxDestroyFn *ctxdestroy;
8422920cce0SJacob Faibussowitsch 
843cf53795eSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
8442920cce0SJacob Faibussowitsch   MatShellSetMatProductOperation(
84549abdd8aSBarry Smith     A, MATPRODUCT_AB, usersymbolic, usernumeric, ctxdestroy,MATSEQAIJ, MATDENSE
8462920cce0SJacob Faibussowitsch   );
8472920cce0SJacob Faibussowitsch   // create B of type SEQAIJ etc..
8482920cce0SJacob Faibussowitsch   MatProductCreate(A, B, PETSC_NULLPTR, &C);
849cf53795eSBarry Smith   MatProductSetType(C, MATPRODUCT_AB);
850cf53795eSBarry Smith   MatProductSetFromOptions(C);
8512920cce0SJacob Faibussowitsch   MatProductSymbolic(C); // actually runs the user defined symbolic operation
8522920cce0SJacob Faibussowitsch   MatProductNumeric(C); // actually runs the user defined numeric operation
8532920cce0SJacob Faibussowitsch   // use C = A * B
854cf53795eSBarry Smith .ve
855b77ba244SStefano Zampini 
856b77ba244SStefano Zampini   Notes:
857cf53795eSBarry Smith   `MATPRODUCT_ABC` is not supported yet.
85811a5261eSBarry Smith 
859cc1eb50dSBarry 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`.
86011a5261eSBarry Smith 
861b77ba244SStefano Zampini   Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
862b77ba244SStefano Zampini   PETSc will take care of calling the user-defined callbacks.
863cc1eb50dSBarry Smith   It is allowed to specify the same callbacks for different `Btype` matrix types.
864cc1eb50dSBarry Smith   The couple (`Btype`,`ptype`) uniquely identifies the operation, the last specified callbacks takes precedence.
865b77ba244SStefano Zampini 
8661cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()`
867b77ba244SStefano Zampini @*/
MatShellSetMatProductOperation(Mat A,MatProductType ptype,PetscErrorCode (* symbolic)(Mat,Mat,Mat,void **),PetscErrorCode (* numeric)(Mat,Mat,Mat,void *),PetscCtxDestroyFn * destroy,MatType Btype,MatType Ctype)868cc1eb50dSBarry Smith PetscErrorCode MatShellSetMatProductOperation(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscCtxDestroyFn *destroy, MatType Btype, MatType Ctype)
869d71ae5a4SJacob Faibussowitsch {
870b77ba244SStefano Zampini   PetscFunctionBegin;
871b77ba244SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
872b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A, ptype, 2);
87308401ef6SPierre Jolivet   PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]);
87428b400f6SJacob Faibussowitsch   PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4");
8754f572ea9SToby Isaac   PetscAssertPointer(Btype, 6);
8764f572ea9SToby Isaac   if (Ctype) PetscAssertPointer(Ctype, 7);
877cc1eb50dSBarry Smith   PetscTryMethod(A, "MatShellSetMatProductOperation_C", (Mat, MatProductType, PetscErrorCode (*)(Mat, Mat, Mat, void **), PetscErrorCode (*)(Mat, Mat, Mat, void *), PetscCtxDestroyFn *, MatType, MatType), (A, ptype, symbolic, numeric, destroy, Btype, Ctype));
8783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
879b77ba244SStefano Zampini }
880b77ba244SStefano Zampini 
MatShellSetMatProductOperation_Shell(Mat A,MatProductType ptype,PetscErrorCode (* symbolic)(Mat,Mat,Mat,void **),PetscErrorCode (* numeric)(Mat,Mat,Mat,void *),PetscCtxDestroyFn * destroy,MatType Btype,MatType Ctype)881cc1eb50dSBarry Smith static PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscCtxDestroyFn *destroy, MatType Btype, MatType Ctype)
882d71ae5a4SJacob Faibussowitsch {
883b77ba244SStefano Zampini   PetscBool   flg;
884b77ba244SStefano Zampini   char        composedname[256];
885b77ba244SStefano Zampini   MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList;
886b77ba244SStefano Zampini   PetscMPIInt size;
887b77ba244SStefano Zampini 
888b77ba244SStefano Zampini   PetscFunctionBegin;
889b77ba244SStefano Zampini   PetscValidType(A, 1);
890b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
8919566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg));
892b77ba244SStefano Zampini     if (flg) break;
893b77ba244SStefano Zampini     Bnames = Bnames->next;
894b77ba244SStefano Zampini   }
895b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
8969566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg));
897b77ba244SStefano Zampini     if (flg) break;
898b77ba244SStefano Zampini     Cnames = Cnames->next;
899b77ba244SStefano Zampini   }
9009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
901b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
902b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
9039566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype));
9049566063dSJacob Faibussowitsch   PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype));
9053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
906e51e0e81SBarry Smith }
907e51e0e81SBarry Smith 
MatCopy_Shell(Mat A,Mat B,MatStructure str)908d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str)
909d71ae5a4SJacob Faibussowitsch {
91028f357e3SAlex Fikl   Mat_Shell              *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data;
911cb8c8a77SBarry Smith   PetscBool               matflg;
912b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9137fabda3fSAlex Fikl 
9147fabda3fSAlex Fikl   PetscFunctionBegin;
9159566063dSJacob Faibussowitsch   PetscCall(MatIsShell(B, &matflg));
91628b400f6SJacob Faibussowitsch   PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name);
9177fabda3fSAlex Fikl 
918aea10558SJacob Faibussowitsch   B->ops[0]      = A->ops[0];
919aea10558SJacob Faibussowitsch   shellB->ops[0] = shellA->ops[0];
9207fabda3fSAlex Fikl 
9211baa6e33SBarry Smith   if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str));
9227fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9237fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9240c0fd78eSBarry Smith   if (shellA->dshift) {
92548a46eb9SPierre Jolivet     if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift));
9269566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->dshift, shellB->dshift));
9277fabda3fSAlex Fikl   } else {
9289566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->dshift));
9297fabda3fSAlex Fikl   }
9300c0fd78eSBarry Smith   if (shellA->left) {
93148a46eb9SPierre Jolivet     if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left));
9329566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->left, shellB->left));
9337fabda3fSAlex Fikl   } else {
9349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->left));
9357fabda3fSAlex Fikl   }
9360c0fd78eSBarry Smith   if (shellA->right) {
93748a46eb9SPierre Jolivet     if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right));
9389566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->right, shellB->right));
9397fabda3fSAlex Fikl   } else {
9409566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shellB->right));
9417fabda3fSAlex Fikl   }
9429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&shellB->axpy));
943ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
944ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
94540e381c3SBarry Smith   if (shellA->axpy) {
9469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->axpy));
94740e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
94840e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
949ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
95040e381c3SBarry Smith   }
95145960306SStefano Zampini   if (shellA->zrows) {
9529566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows));
95348a46eb9SPierre Jolivet     if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols));
9549566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals));
9559566063dSJacob Faibussowitsch     PetscCall(VecCopy(shellA->zvals, shellB->zvals));
9569566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w));
9579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r));
9589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c));
95945960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
96045960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
96145960306SStefano Zampini   }
962b77ba244SStefano Zampini 
963b77ba244SStefano Zampini   matmatA = shellA->matmat;
964b77ba244SStefano Zampini   if (matmatA) {
965b77ba244SStefano Zampini     while (matmatA->next) {
9669566063dSJacob Faibussowitsch       PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname));
967b77ba244SStefano Zampini       matmatA = matmatA->next;
968b77ba244SStefano Zampini     }
969b77ba244SStefano Zampini   }
9703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9717fabda3fSAlex Fikl }
9727fabda3fSAlex Fikl 
MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat * M)973d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M)
974d71ae5a4SJacob Faibussowitsch {
975cb8c8a77SBarry Smith   PetscFunctionBegin;
976800f99ffSJeremy L Thompson   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M));
977800f99ffSJeremy L Thompson   ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer;
978f4f49eeaSPierre Jolivet   PetscCall(PetscObjectCompose((PetscObject)*M, "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer));
979f4f49eeaSPierre Jolivet   PetscCall(PetscObjectChangeTypeName((PetscObject)*M, ((PetscObject)mat)->type_name));
980623b4cf3SPierre Jolivet   if (op == MAT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
98101f93aa2SJose E. Roman   PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M));
9823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
983cb8c8a77SBarry Smith }
984cb8c8a77SBarry Smith 
MatMult_Shell(Mat A,Vec x,Vec y)98566976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y)
986d71ae5a4SJacob Faibussowitsch {
987ef66eb69SBarry Smith   Mat_Shell       *shell = (Mat_Shell *)A->data;
98825578ef6SJed Brown   Vec              xx;
989e3f487b0SBarry Smith   PetscObjectState instate, outstate;
990ef66eb69SBarry Smith 
991ef66eb69SBarry Smith   PetscFunctionBegin;
9929566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroRight(A, x, &xx));
9939566063dSJacob Faibussowitsch   PetscCall(MatShellPreScaleRight(A, xx, &xx));
9949566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
9959566063dSJacob Faibussowitsch   PetscCall((*shell->ops->mult)(A, xx, y));
9969566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
997e3f487b0SBarry Smith   if (instate == outstate) {
998e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
9999566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1000e3f487b0SBarry Smith   }
1001f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
10029566063dSJacob Faibussowitsch   PetscCall(MatShellPostScaleLeft(A, y));
10039566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroLeft(A, y));
10049f137db4SBarry Smith 
10059f137db4SBarry Smith   if (shell->axpy) {
1006ef5c7bd2SStefano Zampini     Mat              X;
1007ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1008ef5c7bd2SStefano Zampini 
10099566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10109566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
101108401ef6SPierre 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,...)");
1012b77ba244SStefano Zampini 
10139566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10149566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_right));
10159566063dSJacob Faibussowitsch     PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left));
10169566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left));
10179f137db4SBarry Smith   }
10183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1019ef66eb69SBarry Smith }
1020ef66eb69SBarry Smith 
MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)1021d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1022d71ae5a4SJacob Faibussowitsch {
10235edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
10245edf6516SJed Brown 
10255edf6516SJed Brown   PetscFunctionBegin;
10265edf6516SJed Brown   if (y == z) {
10279566063dSJacob Faibussowitsch     if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work));
10289566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->right_add_work));
10299566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->right_add_work));
10305edf6516SJed Brown   } else {
10319566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
10329566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
10335edf6516SJed Brown   }
10343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10355edf6516SJed Brown }
10365edf6516SJed Brown 
MatMultTranspose_Shell(Mat A,Vec x,Vec y)1037d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y)
1038d71ae5a4SJacob Faibussowitsch {
103918be62a5SSatish Balay   Mat_Shell       *shell = (Mat_Shell *)A->data;
104025578ef6SJed Brown   Vec              xx;
1041e3f487b0SBarry Smith   PetscObjectState instate, outstate;
104218be62a5SSatish Balay 
104318be62a5SSatish Balay   PetscFunctionBegin;
10449566063dSJacob Faibussowitsch   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1045f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE));
10469566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
10479566063dSJacob Faibussowitsch   PetscCall((*shell->ops->multtranspose)(A, xx, y));
10489566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1049e3f487b0SBarry Smith   if (instate == outstate) {
1050e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
10519566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1052e3f487b0SBarry Smith   }
1053f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE));
1054f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE));
10559566063dSJacob Faibussowitsch   PetscCall(MatShellPostZeroRight(A, y));
1056350ec83bSStefano Zampini 
1057350ec83bSStefano Zampini   if (shell->axpy) {
1058ef5c7bd2SStefano Zampini     Mat              X;
1059ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1060ef5c7bd2SStefano Zampini 
10619566063dSJacob Faibussowitsch     PetscCall(MatShellGetContext(shell->axpy, &X));
10629566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
106308401ef6SPierre 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,...)");
10649566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
10659566063dSJacob Faibussowitsch     PetscCall(VecCopy(x, shell->axpy_left));
10669566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
10679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right));
1068350ec83bSStefano Zampini   }
10693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
107018be62a5SSatish Balay }
107118be62a5SSatish Balay 
MatMultHermitianTranspose_Shell(Mat A,Vec x,Vec y)1072f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y)
1073f8e07d23SBlanca Mellado Pinto {
1074f8e07d23SBlanca Mellado Pinto   Mat_Shell       *shell = (Mat_Shell *)A->data;
1075f8e07d23SBlanca Mellado Pinto   Vec              xx;
1076f8e07d23SBlanca Mellado Pinto   PetscObjectState instate, outstate;
1077f8e07d23SBlanca Mellado Pinto 
1078f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1079f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreZeroLeft(A, x, &xx));
1080f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE));
1081f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &instate));
1082f8e07d23SBlanca Mellado Pinto   PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y));
1083f8e07d23SBlanca Mellado Pinto   PetscCall(PetscObjectStateGet((PetscObject)y, &outstate));
1084f8e07d23SBlanca Mellado Pinto   if (instate == outstate) {
1085f8e07d23SBlanca Mellado Pinto     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1086f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateIncrease((PetscObject)y));
1087f8e07d23SBlanca Mellado Pinto   }
1088f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE));
1089f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE));
1090f8e07d23SBlanca Mellado Pinto   PetscCall(MatShellPostZeroRight(A, y));
1091f8e07d23SBlanca Mellado Pinto 
1092f8e07d23SBlanca Mellado Pinto   if (shell->axpy) {
1093f8e07d23SBlanca Mellado Pinto     Mat              X;
1094f8e07d23SBlanca Mellado Pinto     PetscObjectState axpy_state;
1095f8e07d23SBlanca Mellado Pinto 
1096f8e07d23SBlanca Mellado Pinto     PetscCall(MatShellGetContext(shell->axpy, &X));
1097f8e07d23SBlanca Mellado Pinto     PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state));
1098f8e07d23SBlanca 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,...)");
1099f8e07d23SBlanca Mellado Pinto     PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left));
1100f8e07d23SBlanca Mellado Pinto     PetscCall(VecCopy(x, shell->axpy_left));
1101f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right));
1102f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right));
1103f8e07d23SBlanca Mellado Pinto   }
1104f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1105f8e07d23SBlanca Mellado Pinto }
1106f8e07d23SBlanca Mellado Pinto 
MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)1107d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1108d71ae5a4SJacob Faibussowitsch {
11095edf6516SJed Brown   Mat_Shell *shell = (Mat_Shell *)A->data;
11105edf6516SJed Brown 
11115edf6516SJed Brown   PetscFunctionBegin;
11125edf6516SJed Brown   if (y == z) {
11139566063dSJacob Faibussowitsch     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
11149566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->left_add_work));
11159566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
11165edf6516SJed Brown   } else {
11179566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
11189566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
11195edf6516SJed Brown   }
11203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11215edf6516SJed Brown }
11225edf6516SJed Brown 
MatMultHermitianTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)1123f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z)
1124f8e07d23SBlanca Mellado Pinto {
1125f8e07d23SBlanca Mellado Pinto   Mat_Shell *shell = (Mat_Shell *)A->data;
1126f8e07d23SBlanca Mellado Pinto 
1127f8e07d23SBlanca Mellado Pinto   PetscFunctionBegin;
1128f8e07d23SBlanca Mellado Pinto   if (y == z) {
1129f8e07d23SBlanca Mellado Pinto     if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work));
1130f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work));
1131f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, shell->left_add_work));
1132f8e07d23SBlanca Mellado Pinto   } else {
1133f8e07d23SBlanca Mellado Pinto     PetscCall(MatMultHermitianTranspose(A, x, z));
1134f8e07d23SBlanca Mellado Pinto     PetscCall(VecAXPY(z, 1.0, y));
1135f8e07d23SBlanca Mellado Pinto   }
1136f8e07d23SBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
1137f8e07d23SBlanca Mellado Pinto }
1138f8e07d23SBlanca Mellado Pinto 
11390c0fd78eSBarry Smith /*
11400c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11410c0fd78eSBarry Smith */
MatGetDiagonal_Shell(Mat A,Vec v)1142d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v)
1143d71ae5a4SJacob Faibussowitsch {
114418be62a5SSatish Balay   Mat_Shell *shell = (Mat_Shell *)A->data;
114518be62a5SSatish Balay 
114618be62a5SSatish Balay   PetscFunctionBegin;
1147966bd95aSPierre Jolivet   PetscCheck(shell->ops->getdiagonal, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal using MatShellSetOperation(S, MATOP_GET_DIAGONAL...)");
11489566063dSJacob Faibussowitsch   PetscCall((*shell->ops->getdiagonal)(A, v));
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 
MatGetDiagonalBlock_Shell(Mat A,Mat * b)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
1181966bd95aSPierre Jolivet   PetscCheck(shell->ops->getdiagonalblock, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal block using MatShellSetOperation(S, MATOP_GET_DIAGONAL_BLOCK...)");
1182a29b93afSAudic XU   PetscCall((*shell->ops->getdiagonalblock)(A, b));
1183a29b93afSAudic XU   PetscCall(MatScale(*b, shell->vscale));
1184a29b93afSAudic XU   PetscCall(MatShift(*b, shell->vshift));
1185a29b93afSAudic XU   if (shell->left) {
1186a29b93afSAudic XU     PetscCall(VecCreateLocalVector(shell->left, &left));
1187a29b93afSAudic XU     PetscCall(VecGetLocalVectorRead(shell->left, left));
1188a29b93afSAudic XU   }
1189a29b93afSAudic XU   if (shell->right) {
1190a29b93afSAudic XU     PetscCall(VecCreateLocalVector(shell->right, &right));
1191a29b93afSAudic XU     PetscCall(VecGetLocalVectorRead(shell->right, right));
1192a29b93afSAudic XU   }
1193a29b93afSAudic XU   PetscCall(MatDiagonalScale(*b, left, right));
1194a29b93afSAudic XU   if (shell->left) {
1195a29b93afSAudic XU     PetscCall(VecRestoreLocalVectorRead(shell->left, left));
1196a29b93afSAudic XU     PetscCall(VecDestroy(&left));
1197a29b93afSAudic XU   }
1198a29b93afSAudic XU   if (shell->right) {
1199a29b93afSAudic XU     PetscCall(VecRestoreLocalVectorRead(shell->right, right));
1200a29b93afSAudic XU     PetscCall(VecDestroy(&right));
1201a29b93afSAudic XU   }
1202a29b93afSAudic XU   PetscFunctionReturn(PETSC_SUCCESS);
1203a29b93afSAudic XU }
1204a29b93afSAudic XU 
MatShift_Shell(Mat Y,PetscScalar a)1205d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a)
1206d71ae5a4SJacob Faibussowitsch {
1207ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1208789d8953SBarry Smith   PetscBool  flg;
1209b24ad042SBarry Smith 
1210ef66eb69SBarry Smith   PetscFunctionBegin;
12119566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(Y, &flg));
121228b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent");
12130c0fd78eSBarry Smith   if (shell->left || shell->right) {
12148fe8eb27SJed Brown     if (!shell->dshift) {
12159566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift));
12169566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->dshift, a));
12170c0fd78eSBarry Smith     } else {
12189566063dSJacob Faibussowitsch       if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left));
12199566063dSJacob Faibussowitsch       if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right));
12209566063dSJacob Faibussowitsch       PetscCall(VecShift(shell->dshift, a));
12210c0fd78eSBarry Smith     }
12229566063dSJacob Faibussowitsch     if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left));
12239566063dSJacob Faibussowitsch     if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right));
12248fe8eb27SJed Brown   } else shell->vshift += a;
12251baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecShift(shell->zvals, a));
12263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1227ef66eb69SBarry Smith }
1228ef66eb69SBarry Smith 
MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)1229d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s)
1230d71ae5a4SJacob Faibussowitsch {
12316464bf51SAlex Fikl   Mat_Shell *shell = (Mat_Shell *)A->data;
12326464bf51SAlex Fikl 
12336464bf51SAlex Fikl   PetscFunctionBegin;
12349566063dSJacob Faibussowitsch   if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift));
12350c0fd78eSBarry Smith   if (shell->left || shell->right) {
12369566063dSJacob Faibussowitsch     if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work));
12379f137db4SBarry Smith     if (shell->left && shell->right) {
12389566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12399566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right));
12409f137db4SBarry Smith     } else if (shell->left) {
12419566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left));
12429f137db4SBarry Smith     } else {
12439566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right));
12449f137db4SBarry Smith     }
12459566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, shell->right_work));
12460c0fd78eSBarry Smith   } else {
12479566063dSJacob Faibussowitsch     PetscCall(VecAXPY(shell->dshift, s, D));
1248b253ae0bS“Marek   }
12493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1250b253ae0bS“Marek }
1251b253ae0bS“Marek 
MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)125266976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins)
1253d71ae5a4SJacob Faibussowitsch {
125445960306SStefano Zampini   Mat_Shell *shell = (Mat_Shell *)A->data;
1255b253ae0bS“Marek   Vec        d;
1256789d8953SBarry Smith   PetscBool  flg;
1257b253ae0bS“Marek 
1258b253ae0bS“Marek   PetscFunctionBegin;
12599566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &flg));
126028b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent");
1261b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12629566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(D, &d));
12639566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(A, d));
12649566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.));
12659566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12669566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&d));
12671baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecCopy(D, shell->zvals));
1268b253ae0bS“Marek   } else {
12699566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.));
12701baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D));
12716464bf51SAlex Fikl   }
12723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12736464bf51SAlex Fikl }
12746464bf51SAlex Fikl 
MatScale_Shell(Mat Y,PetscScalar a)1275d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a)
1276d71ae5a4SJacob Faibussowitsch {
1277ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1278b24ad042SBarry Smith 
1279ef66eb69SBarry Smith   PetscFunctionBegin;
1280f4df32b1SMatthew Knepley   shell->vscale *= a;
12810c0fd78eSBarry Smith   shell->vshift *= a;
12821baa6e33SBarry Smith   if (shell->dshift) PetscCall(VecScale(shell->dshift, a));
128381c02519SBarry Smith   shell->axpy_vscale *= a;
12841baa6e33SBarry Smith   if (shell->zrows) PetscCall(VecScale(shell->zvals, a));
12853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128618be62a5SSatish Balay }
12878fe8eb27SJed Brown 
MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)1288d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right)
1289d71ae5a4SJacob Faibussowitsch {
12908fe8eb27SJed Brown   Mat_Shell *shell = (Mat_Shell *)Y->data;
12918fe8eb27SJed Brown 
12928fe8eb27SJed Brown   PetscFunctionBegin;
12938fe8eb27SJed Brown   if (left) {
12940c0fd78eSBarry Smith     if (!shell->left) {
12959566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &shell->left));
12969566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, shell->left));
12970c0fd78eSBarry Smith     } else {
12989566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->left, shell->left, left));
129918be62a5SSatish Balay     }
13001baa6e33SBarry Smith     if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left));
1301ef66eb69SBarry Smith   }
13028fe8eb27SJed Brown   if (right) {
13030c0fd78eSBarry Smith     if (!shell->right) {
13049566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &shell->right));
13059566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, shell->right));
13060c0fd78eSBarry Smith     } else {
13079566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->right, shell->right, right));
13088fe8eb27SJed Brown     }
130945960306SStefano Zampini     if (shell->zrows) {
131048a46eb9SPierre Jolivet       if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work));
13119566063dSJacob Faibussowitsch       PetscCall(VecSet(shell->zvals_w, 1.0));
13129566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13139566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD));
13149566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w));
131545960306SStefano Zampini     }
13168fe8eb27SJed Brown   }
13171baa6e33SBarry Smith   if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right));
13183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1319ef66eb69SBarry Smith }
1320ef66eb69SBarry Smith 
MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)132186a9fd05SPierre Jolivet PETSC_INTERN PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t)
1322d71ae5a4SJacob Faibussowitsch {
1323ef66eb69SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
1324ef66eb69SBarry Smith 
1325ef66eb69SBarry Smith   PetscFunctionBegin;
13268fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1327ef66eb69SBarry Smith     shell->vshift      = 0.0;
1328ef66eb69SBarry Smith     shell->vscale      = 1.0;
1329ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1330ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13319566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->dshift));
13329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->left));
13339566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->right));
13349566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&shell->axpy));
13359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_left));
13369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->axpy_right));
13379566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_c));
13389566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->zvals_sct_r));
13399566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zrows));
13409566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&shell->zcols));
1341ef66eb69SBarry Smith   }
13423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1343ef66eb69SBarry Smith }
1344ef66eb69SBarry Smith 
MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)134566976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str)
1346d71ae5a4SJacob Faibussowitsch {
13479f137db4SBarry Smith   Mat_Shell *shell = (Mat_Shell *)Y->data;
13489f137db4SBarry Smith 
13499f137db4SBarry Smith   PetscFunctionBegin;
1350ef5c7bd2SStefano Zampini   if (X == Y) {
13519566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
13523ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1353ef5c7bd2SStefano Zampini   }
1354ef5c7bd2SStefano Zampini   if (!shell->axpy) {
13559566063dSJacob Faibussowitsch     PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy));
13569f137db4SBarry Smith     shell->axpy_vscale = a;
13579566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state));
1358ef5c7bd2SStefano Zampini   } else {
13599566063dSJacob Faibussowitsch     PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str));
1360ef5c7bd2SStefano Zampini   }
13613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13629f137db4SBarry Smith }
13639f137db4SBarry Smith 
1364f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1365f4259b30SLisandro Dalcin                                        NULL,
1366f4259b30SLisandro Dalcin                                        NULL,
1367f4259b30SLisandro Dalcin                                        NULL,
13680c0fd78eSBarry Smith                                        /* 4*/ MatMultAdd_Shell,
1369f4259b30SLisandro Dalcin                                        NULL,
13700c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1371f4259b30SLisandro Dalcin                                        NULL,
1372f4259b30SLisandro Dalcin                                        NULL,
1373f4259b30SLisandro Dalcin                                        NULL,
1374f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1375f4259b30SLisandro Dalcin                                        NULL,
1376f4259b30SLisandro Dalcin                                        NULL,
1377f4259b30SLisandro Dalcin                                        NULL,
1378f4259b30SLisandro Dalcin                                        NULL,
1379f4259b30SLisandro Dalcin                                        /*15*/ NULL,
1380f4259b30SLisandro Dalcin                                        NULL,
1381f4259b30SLisandro Dalcin                                        NULL,
13828fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1383f4259b30SLisandro Dalcin                                        NULL,
1384f4259b30SLisandro Dalcin                                        /*20*/ NULL,
1385ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1386f4259b30SLisandro Dalcin                                        NULL,
1387f4259b30SLisandro Dalcin                                        NULL,
138845960306SStefano Zampini                                        /*24*/ MatZeroRows_Shell,
1389f4259b30SLisandro Dalcin                                        NULL,
1390f4259b30SLisandro Dalcin                                        NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        /*29*/ NULL,
1394f4259b30SLisandro Dalcin                                        NULL,
1395f4259b30SLisandro Dalcin                                        NULL,
1396a29b93afSAudic XU                                        /*32*/ NULL,
1397f4259b30SLisandro Dalcin                                        NULL,
1398cb8c8a77SBarry Smith                                        /*34*/ MatDuplicate_Shell,
1399f4259b30SLisandro Dalcin                                        NULL,
1400f4259b30SLisandro Dalcin                                        NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
14039f137db4SBarry Smith                                        /*39*/ MatAXPY_Shell,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                        NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407cb8c8a77SBarry Smith                                        MatCopy_Shell,
1408f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1409ef66eb69SBarry Smith                                        MatScale_Shell,
1410ef66eb69SBarry Smith                                        MatShift_Shell,
14116464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
141245960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1413f4259b30SLisandro Dalcin                                        /*49*/ NULL,
1414f4259b30SLisandro Dalcin                                        NULL,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        /*54*/ NULL,
1419f4259b30SLisandro Dalcin                                        NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1424b9b97703SBarry Smith                                        MatDestroy_Shell,
1425f4259b30SLisandro Dalcin                                        NULL,
1426251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1429f4259b30SLisandro Dalcin                                        NULL,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1434c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1435f4259b30SLisandro Dalcin                                        NULL,
1436f4259b30SLisandro Dalcin                                        NULL,
14378bb0f5c6SPierre Jolivet                                        NULL,
1438f4259b30SLisandro Dalcin                                        /*74*/ NULL,
1439f4259b30SLisandro Dalcin                                        NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        /*79*/ NULL,
1444f4259b30SLisandro Dalcin                                        NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        /*84*/ NULL,
1449f4259b30SLisandro Dalcin                                        NULL,
1450f4259b30SLisandro Dalcin                                        NULL,
1451f4259b30SLisandro Dalcin                                        NULL,
1452f4259b30SLisandro Dalcin                                        NULL,
1453f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1454f4259b30SLisandro Dalcin                                        NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456f4259b30SLisandro Dalcin                                        NULL,
1457f4259b30SLisandro Dalcin                                        NULL,
1458f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1459f4259b30SLisandro Dalcin                                        NULL,
1460f4259b30SLisandro Dalcin                                        NULL,
1461f4259b30SLisandro Dalcin                                        NULL,
1462f4259b30SLisandro Dalcin                                        NULL,
1463f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1464f4259b30SLisandro Dalcin                                        NULL,
1465f4259b30SLisandro Dalcin                                        NULL,
1466f4259b30SLisandro Dalcin                                        NULL,
1467f4259b30SLisandro Dalcin                                        NULL,
1468421480d9SBarry Smith                                        /*104*/ NULL,
1469f4259b30SLisandro Dalcin                                        NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        NULL,
1472f4259b30SLisandro Dalcin                                        NULL,
1473f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1474f4259b30SLisandro Dalcin                                        NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
14768bb0f5c6SPierre Jolivet                                        MatMultHermitianTransposeAdd_Shell,
1477421480d9SBarry Smith                                        NULL,
1478f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1479f4259b30SLisandro Dalcin                                        NULL,
1480f4259b30SLisandro Dalcin                                        NULL,
1481f4259b30SLisandro Dalcin                                        NULL,
1482f4259b30SLisandro Dalcin                                        NULL,
1483f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1484f4259b30SLisandro Dalcin                                        NULL,
1485f4259b30SLisandro Dalcin                                        NULL,
14868bb0f5c6SPierre Jolivet                                        NULL,
1487f4259b30SLisandro Dalcin                                        NULL,
1488f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1489f4259b30SLisandro Dalcin                                        NULL,
1490f4259b30SLisandro Dalcin                                        NULL,
1491f4259b30SLisandro Dalcin                                        NULL,
1492f4259b30SLisandro Dalcin                                        NULL,
1493f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1494f4259b30SLisandro Dalcin                                        NULL,
1495f4259b30SLisandro Dalcin                                        NULL,
1496f4259b30SLisandro Dalcin                                        NULL,
1497f4259b30SLisandro Dalcin                                        NULL,
1498f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1499f4259b30SLisandro Dalcin                                        NULL,
1500f4259b30SLisandro Dalcin                                        NULL,
1501f4259b30SLisandro Dalcin                                        NULL,
1502f4259b30SLisandro Dalcin                                        NULL,
1503f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1504f4259b30SLisandro Dalcin                                        NULL,
1505d70f29a3SPierre Jolivet                                        NULL,
150603db1824SAlex Lindsay                                        NULL,
1507dec0b466SHong Zhang                                        NULL};
1508273d9f13SBarry Smith 
MatShellSetContext_Shell(Mat mat,PetscCtx ctx)1509*2a8381b2SBarry Smith static PetscErrorCode MatShellSetContext_Shell(Mat mat, PetscCtx ctx)
1510d71ae5a4SJacob Faibussowitsch {
1511789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1512789d8953SBarry Smith 
1513789d8953SBarry Smith   PetscFunctionBegin;
1514800f99ffSJeremy L Thompson   if (ctx) {
1515800f99ffSJeremy L Thompson     PetscContainer ctxcontainer;
1516800f99ffSJeremy L Thompson     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer));
1517800f99ffSJeremy L Thompson     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1518800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer));
1519800f99ffSJeremy L Thompson     shell->ctxcontainer = ctxcontainer;
1520800f99ffSJeremy L Thompson     PetscCall(PetscContainerDestroy(&ctxcontainer));
1521800f99ffSJeremy L Thompson   } else {
1522800f99ffSJeremy L Thompson     PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL));
1523800f99ffSJeremy L Thompson     shell->ctxcontainer = NULL;
1524800f99ffSJeremy L Thompson   }
15253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1526800f99ffSJeremy L Thompson }
1527800f99ffSJeremy L Thompson 
MatShellSetContextDestroy_Shell(Mat mat,PetscCtxDestroyFn * f)152849abdd8aSBarry Smith static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscCtxDestroyFn *f)
1529d71ae5a4SJacob Faibussowitsch {
1530800f99ffSJeremy L Thompson   Mat_Shell *shell = (Mat_Shell *)mat->data;
1531800f99ffSJeremy L Thompson 
1532800f99ffSJeremy L Thompson   PetscFunctionBegin;
153349abdd8aSBarry Smith   if (shell->ctxcontainer) PetscCall(PetscContainerSetCtxDestroy(shell->ctxcontainer, f));
15343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1535789d8953SBarry Smith }
1536789d8953SBarry Smith 
MatShellSetContext_Immutable(Mat mat,PetscCtx ctx)1537*2a8381b2SBarry Smith PetscErrorCode MatShellSetContext_Immutable(Mat mat, PetscCtx ctx)
153886a9fd05SPierre Jolivet {
153986a9fd05SPierre Jolivet   PetscFunctionBegin;
154086a9fd05SPierre 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);
154186a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
154286a9fd05SPierre Jolivet }
154386a9fd05SPierre Jolivet 
MatShellSetContextDestroy_Immutable(Mat mat,PetscCtxDestroyFn * f)1544d1319cabSBarry Smith PetscErrorCode MatShellSetContextDestroy_Immutable(Mat mat, PetscCtxDestroyFn *f)
154586a9fd05SPierre Jolivet {
154686a9fd05SPierre Jolivet   PetscFunctionBegin;
154786a9fd05SPierre 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);
154886a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
154986a9fd05SPierre Jolivet }
155086a9fd05SPierre Jolivet 
MatShellSetManageScalingShifts_Immutable(Mat mat)155186a9fd05SPierre Jolivet PetscErrorCode MatShellSetManageScalingShifts_Immutable(Mat mat)
155286a9fd05SPierre Jolivet {
155386a9fd05SPierre Jolivet   PetscFunctionBegin;
155486a9fd05SPierre 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);
155586a9fd05SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
155686a9fd05SPierre Jolivet }
155786a9fd05SPierre Jolivet 
MatShellSetVecType_Shell(Mat mat,VecType vtype)1558d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype)
1559d71ae5a4SJacob Faibussowitsch {
1560db77db73SJeremy L Thompson   PetscFunctionBegin;
15619566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->defaultvectype));
15629566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype));
15633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1564db77db73SJeremy L Thompson }
1565db77db73SJeremy L Thompson 
MatShellSetManageScalingShifts_Shell(Mat A)156666976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1567d71ae5a4SJacob Faibussowitsch {
1568789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)A->data;
1569789d8953SBarry Smith 
1570789d8953SBarry Smith   PetscFunctionBegin;
1571789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1572789d8953SBarry Smith   A->ops->diagonalset        = NULL;
1573789d8953SBarry Smith   A->ops->diagonalscale      = NULL;
1574789d8953SBarry Smith   A->ops->scale              = NULL;
1575789d8953SBarry Smith   A->ops->shift              = NULL;
1576789d8953SBarry Smith   A->ops->axpy               = NULL;
15773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1578789d8953SBarry Smith }
1579789d8953SBarry Smith 
MatShellGetScalingShifts_Shell(Mat A,PetscScalar * vshift,PetscScalar * vscale,Vec * dshift,Vec * left,Vec * right,Mat * axpy,IS * zrows,IS * zcols)1580b9c875b8SPierre Jolivet static PetscErrorCode MatShellGetScalingShifts_Shell(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols)
1581b9c875b8SPierre Jolivet {
1582b9c875b8SPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)A->data;
1583b9c875b8SPierre Jolivet 
1584b9c875b8SPierre Jolivet   PetscFunctionBegin;
1585b9c875b8SPierre Jolivet   PetscCheck(shell->managescalingshifts, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot get scaling and shifts if MatShellSetManageScalingShifts() has been called");
1586b9c875b8SPierre 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()");
1587b9c875b8SPierre Jolivet   else if (vshift) *vshift = shell->vshift;
1588b9c875b8SPierre 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()");
1589b9c875b8SPierre Jolivet   else if (vscale) *vscale = shell->vscale;
1590b9c875b8SPierre 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()");
1591b9c875b8SPierre Jolivet   else if (dshift) *dshift = shell->dshift;
1592b9c875b8SPierre 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()");
1593b9c875b8SPierre Jolivet   else if (left) *left = shell->left;
1594b9c875b8SPierre 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()");
1595b9c875b8SPierre Jolivet   else if (right) *right = shell->right;
1596b9c875b8SPierre 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()");
1597b9c875b8SPierre Jolivet   else if (axpy) *axpy = shell->axpy;
1598b9c875b8SPierre 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()");
1599b9c875b8SPierre Jolivet   else if (zrows) *zrows = shell->zrows;
1600b9c875b8SPierre 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()");
1601b9c875b8SPierre Jolivet   else if (zcols) *zcols = shell->zcols;
1602b9c875b8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
1603b9c875b8SPierre Jolivet }
1604b9c875b8SPierre Jolivet 
MatShellSetOperation_Shell(Mat mat,MatOperation op,PetscErrorCodeFn * f)160557d50842SBarry Smith static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, PetscErrorCodeFn *f)
1606d71ae5a4SJacob Faibussowitsch {
1607feb237baSPierre Jolivet   Mat_Shell *shell = (Mat_Shell *)mat->data;
1608789d8953SBarry Smith 
1609789d8953SBarry Smith   PetscFunctionBegin;
1610789d8953SBarry Smith   switch (op) {
1611d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
1612d71ae5a4SJacob Faibussowitsch     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1613d71ae5a4SJacob Faibussowitsch     break;
1614789d8953SBarry Smith   case MATOP_VIEW:
1615ad540459SPierre Jolivet     if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view;
1616789d8953SBarry Smith     mat->ops->view = (PetscErrorCode (*)(Mat, PetscViewer))f;
1617789d8953SBarry Smith     break;
1618d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
1619d71ae5a4SJacob Faibussowitsch     shell->ops->copy = (PetscErrorCode (*)(Mat, Mat, MatStructure))f;
1620d71ae5a4SJacob Faibussowitsch     break;
1621789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1622789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1623789d8953SBarry Smith   case MATOP_SHIFT:
1624789d8953SBarry Smith   case MATOP_SCALE:
1625789d8953SBarry Smith   case MATOP_AXPY:
1626789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1627789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1628c2be7ffeSStefano Zampini   case MATOP_ZERO_ROWS_LOCAL:
1629c2be7ffeSStefano Zampini   case MATOP_ZERO_ROWS_COLUMNS_LOCAL:
163028b400f6SJacob Faibussowitsch     PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
163157d50842SBarry Smith     (((PetscErrorCodeFn **)mat->ops)[op]) = f;
1632789d8953SBarry Smith     break;
1633789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1634789d8953SBarry Smith     if (shell->managescalingshifts) {
1635789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat, Vec))f;
1636789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1637789d8953SBarry Smith     } else {
1638789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1639789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat, Vec))f;
1640789d8953SBarry Smith     }
1641789d8953SBarry Smith     break;
1642a29b93afSAudic XU   case MATOP_GET_DIAGONAL_BLOCK:
1643a29b93afSAudic XU     if (shell->managescalingshifts) {
1644a29b93afSAudic XU       shell->ops->getdiagonalblock = (PetscErrorCode (*)(Mat, Mat *))f;
1645a29b93afSAudic XU       mat->ops->getdiagonalblock   = MatGetDiagonalBlock_Shell;
1646a29b93afSAudic XU     } else {
1647a29b93afSAudic XU       shell->ops->getdiagonalblock = NULL;
1648a29b93afSAudic XU       mat->ops->getdiagonalblock   = (PetscErrorCode (*)(Mat, Mat *))f;
1649a29b93afSAudic XU     }
1650a29b93afSAudic XU     break;
1651789d8953SBarry Smith   case MATOP_MULT:
1652789d8953SBarry Smith     if (shell->managescalingshifts) {
1653789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1654789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1655789d8953SBarry Smith     } else {
1656789d8953SBarry Smith       shell->ops->mult = NULL;
1657789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1658789d8953SBarry Smith     }
1659789d8953SBarry Smith     break;
1660789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1661789d8953SBarry Smith     if (shell->managescalingshifts) {
1662789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1663789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1664789d8953SBarry Smith     } else {
1665789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1666789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1667789d8953SBarry Smith     }
1668789d8953SBarry Smith     break;
1669f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
1670f8e07d23SBlanca Mellado Pinto     if (shell->managescalingshifts) {
1671f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1672f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = MatMultHermitianTranspose_Shell;
1673f8e07d23SBlanca Mellado Pinto     } else {
1674f8e07d23SBlanca Mellado Pinto       shell->ops->multhermitiantranspose = NULL;
1675f8e07d23SBlanca Mellado Pinto       mat->ops->multhermitiantranspose   = (PetscErrorCode (*)(Mat, Vec, Vec))f;
1676f8e07d23SBlanca Mellado Pinto     }
1677f8e07d23SBlanca Mellado Pinto     break;
1678d71ae5a4SJacob Faibussowitsch   default:
167957d50842SBarry Smith     (((PetscErrorCodeFn **)mat->ops)[op]) = f;
1680d71ae5a4SJacob Faibussowitsch     break;
1681789d8953SBarry Smith   }
16823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1683789d8953SBarry Smith }
1684789d8953SBarry Smith 
MatShellGetOperation_Shell(Mat mat,MatOperation op,PetscErrorCodeFn ** f)168557d50842SBarry Smith static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, PetscErrorCodeFn **f)
1686d71ae5a4SJacob Faibussowitsch {
1687789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell *)mat->data;
1688789d8953SBarry Smith 
1689789d8953SBarry Smith   PetscFunctionBegin;
1690789d8953SBarry Smith   switch (op) {
1691d71ae5a4SJacob Faibussowitsch   case MATOP_DESTROY:
169257d50842SBarry Smith     *f = (PetscErrorCodeFn *)shell->ops->destroy;
1693d71ae5a4SJacob Faibussowitsch     break;
1694d71ae5a4SJacob Faibussowitsch   case MATOP_VIEW:
169557d50842SBarry Smith     *f = (PetscErrorCodeFn *)mat->ops->view;
1696d71ae5a4SJacob Faibussowitsch     break;
1697d71ae5a4SJacob Faibussowitsch   case MATOP_COPY:
169857d50842SBarry Smith     *f = (PetscErrorCodeFn *)shell->ops->copy;
1699d71ae5a4SJacob Faibussowitsch     break;
1700789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1701789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1702789d8953SBarry Smith   case MATOP_SHIFT:
1703789d8953SBarry Smith   case MATOP_SCALE:
1704789d8953SBarry Smith   case MATOP_AXPY:
1705789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1706d71ae5a4SJacob Faibussowitsch   case MATOP_ZERO_ROWS_COLUMNS:
170757d50842SBarry Smith     *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1708d71ae5a4SJacob Faibussowitsch     break;
1709789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
171057d50842SBarry Smith     if (shell->ops->getdiagonal) *f = (PetscErrorCodeFn *)shell->ops->getdiagonal;
171157d50842SBarry Smith     else *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1712789d8953SBarry Smith     break;
1713a29b93afSAudic XU   case MATOP_GET_DIAGONAL_BLOCK:
171457d50842SBarry Smith     if (shell->ops->getdiagonalblock) *f = (PetscErrorCodeFn *)shell->ops->getdiagonalblock;
171557d50842SBarry Smith     else *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1716a29b93afSAudic XU     break;
1717789d8953SBarry Smith   case MATOP_MULT:
171857d50842SBarry Smith     if (shell->ops->mult) *f = (PetscErrorCodeFn *)shell->ops->mult;
171957d50842SBarry Smith     else *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1720789d8953SBarry Smith     break;
1721789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
172257d50842SBarry Smith     if (shell->ops->multtranspose) *f = (PetscErrorCodeFn *)shell->ops->multtranspose;
172357d50842SBarry Smith     else *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1724789d8953SBarry Smith     break;
1725f8e07d23SBlanca Mellado Pinto   case MATOP_MULT_HERMITIAN_TRANSPOSE:
172657d50842SBarry Smith     if (shell->ops->multhermitiantranspose) *f = (PetscErrorCodeFn *)shell->ops->multhermitiantranspose;
172757d50842SBarry Smith     else *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1728f8e07d23SBlanca Mellado Pinto     break;
1729d71ae5a4SJacob Faibussowitsch   default:
173057d50842SBarry Smith     *f = (((PetscErrorCodeFn **)mat->ops)[op]);
1731789d8953SBarry Smith   }
17323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1733789d8953SBarry Smith }
1734789d8953SBarry Smith 
17350bad9183SKris Buschelman /*MC
17360b4b7b1cSBarry Smith   MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type with its own data structure -- perhaps matrix-free.
17370bad9183SKris Buschelman 
17380bad9183SKris Buschelman   Level: advanced
17390bad9183SKris Buschelman 
17400b4b7b1cSBarry Smith   Notes:
17410b4b7b1cSBarry Smith   See `MatCreateShell()` for details on the usage of `MATSHELL`
17420b4b7b1cSBarry Smith 
17430b4b7b1cSBarry Smith   `PCSHELL` can be used in conjunction with `MATSHELL` to provide a custom preconditioner appropriate for your `MATSHELL`. Since
17440b4b7b1cSBarry Smith   many standard preconditioners such as `PCILU` depend on having an explicit representation of the matrix entries they cannot be used
17450b4b7b1cSBarry Smith   directly with `MATSHELL`.
17460b4b7b1cSBarry Smith 
17470b4b7b1cSBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `PCSHELL`
17480bad9183SKris Buschelman M*/
17490bad9183SKris Buschelman 
MatCreate_Shell(Mat A)1750d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1751d71ae5a4SJacob Faibussowitsch {
1752273d9f13SBarry Smith   Mat_Shell *b;
1753273d9f13SBarry Smith 
1754273d9f13SBarry Smith   PetscFunctionBegin;
17554dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1756273d9f13SBarry Smith   A->data   = (void *)b;
1757aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
1758273d9f13SBarry Smith 
1759800f99ffSJeremy L Thompson   b->ctxcontainer        = NULL;
1760ef66eb69SBarry Smith   b->vshift              = 0.0;
1761ef66eb69SBarry Smith   b->vscale              = 1.0;
17620c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1763273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1764210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17652205254eSKarl Rupp 
17669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell));
17679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell));
1768800f99ffSJeremy L Thompson   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell));
17699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell));
17709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell));
1771b9c875b8SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetScalingShifts_C", MatShellGetScalingShifts_Shell));
17729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell));
17739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell));
17749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell));
17759566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL));
17763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1777273d9f13SBarry Smith }
1778e51e0e81SBarry Smith 
17794b828684SBarry Smith /*@C
178011a5261eSBarry Smith   MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined
17810b4b7b1cSBarry Smith   private matrix data storage format.
1782e51e0e81SBarry Smith 
1783d083f849SBarry Smith   Collective
1784c7fcc2eaSBarry Smith 
1785e51e0e81SBarry Smith   Input Parameters:
1786c7fcc2eaSBarry Smith + comm - MPI communicator
178745f401ebSJose E. Roman . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
178845f401ebSJose E. Roman . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
178945f401ebSJose E. Roman . M    - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given)
179045f401ebSJose E. Roman . N    - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given)
1791c7fcc2eaSBarry Smith - ctx  - pointer to data needed by the shell matrix routines
1792e51e0e81SBarry Smith 
1793ff756334SLois Curfman McInnes   Output Parameter:
179444cd7ae7SLois Curfman McInnes . A - the matrix
1795e51e0e81SBarry Smith 
1796ff2fd236SBarry Smith   Level: advanced
1797ff2fd236SBarry Smith 
17982920cce0SJacob Faibussowitsch   Example Usage:
179927430b45SBarry Smith .vb
180027430b45SBarry Smith   extern PetscErrorCode mult(Mat, Vec, Vec);
18012920cce0SJacob Faibussowitsch 
180227430b45SBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &mat);
180327430b45SBarry Smith   MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult);
18040b4b7b1cSBarry Smith   MatShellSetContext(mat,ctx);
18052920cce0SJacob Faibussowitsch   // Use matrix for operations that have been set
180627430b45SBarry Smith   MatDestroy(mat);
180727430b45SBarry Smith .ve
1808f39d1f56SLois Curfman McInnes 
1809ff756334SLois Curfman McInnes   Notes:
18100b4b7b1cSBarry Smith   The shell matrix type is intended to provide a simple way for users to write a custom matrix specifically for their application.
18110b4b7b1cSBarry Smith 
18120b4b7b1cSBarry Smith   `MatCreateShell()` is used in conjunction with `MatShellSetContext()` and `MatShellSetOperation()`.
1813e51e0e81SBarry Smith 
1814f39d1f56SLois Curfman McInnes   PETSc requires that matrices and vectors being used for certain
1815f39d1f56SLois Curfman McInnes   operations are partitioned accordingly.  For example, when
18162ef1f0ffSBarry Smith   creating a shell matrix, `A`, that supports parallel matrix-vector
181711a5261eSBarry Smith   products using `MatMult`(A,x,y) the user should set the number
1818645985a0SLois Curfman McInnes   of local matrix rows to be the number of local elements of the
1819645985a0SLois Curfman McInnes   corresponding result vector, y. Note that this is information is
1820645985a0SLois Curfman McInnes   required for use of the matrix interface routines, even though
1821645985a0SLois Curfman McInnes   the shell matrix may not actually be physically partitioned.
1822645985a0SLois Curfman McInnes   For example,
1823f39d1f56SLois Curfman McInnes 
182427430b45SBarry Smith .vb
182527430b45SBarry Smith      Vec x, y
182627430b45SBarry Smith      extern PetscErrorCode mult(Mat,Vec,Vec);
182727430b45SBarry Smith      Mat A
182827430b45SBarry Smith 
182927430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,M,&y);
183027430b45SBarry Smith      VecCreateMPI(comm,PETSC_DECIDE,N,&x);
183127430b45SBarry Smith      VecGetLocalSize(y,&m);
183227430b45SBarry Smith      VecGetLocalSize(x,&n);
183327430b45SBarry Smith      MatCreateShell(comm,m,n,M,N,ctx,&A);
183427430b45SBarry Smith      MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
183527430b45SBarry Smith      MatMult(A,x,y);
183627430b45SBarry Smith      MatDestroy(&A);
183727430b45SBarry Smith      VecDestroy(&y);
183827430b45SBarry Smith      VecDestroy(&x);
183927430b45SBarry Smith .ve
1840e51e0e81SBarry Smith 
18412ef1f0ffSBarry Smith   `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()`
18422ef1f0ffSBarry Smith   internally, so these  operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called.
18430c0fd78eSBarry Smith 
184427430b45SBarry Smith   Developer Notes:
18452ef1f0ffSBarry Smith   For rectangular matrices do all the scalings and shifts make sense?
18462ef1f0ffSBarry Smith 
184795452b02SPatrick Sanan   Regarding shifting and scaling. The general form is
18480c0fd78eSBarry Smith 
18490c0fd78eSBarry Smith   diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
18500c0fd78eSBarry Smith 
18510c0fd78eSBarry Smith   The order you apply the operations is important. For example if you have a dshift then
18520c0fd78eSBarry Smith   apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
18530c0fd78eSBarry Smith   you get s*vscale*A + diag(shift)
18540c0fd78eSBarry Smith 
18550c0fd78eSBarry Smith   A is the user provided function.
18560c0fd78eSBarry Smith 
185727430b45SBarry Smith   `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for
1858c5dec841SPierre Jolivet   for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger
185911a5261eSBarry Smith   an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat);
186011a5261eSBarry Smith   each time the `MATSHELL` matrix has changed.
1861ad2f5c3fSBarry Smith 
18620b4b7b1cSBarry Smith   Matrix-matrix product operations can be specified using `MatShellSetMatProductOperation()`
1863b77ba244SStefano Zampini 
186411a5261eSBarry Smith   Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided
186511a5261eSBarry Smith   with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`.
1866ad2f5c3fSBarry Smith 
1867fe59aa6dSJacob Faibussowitsch   Fortran Notes:
18682ef1f0ffSBarry Smith   To use this from Fortran with a `ctx` you must write an interface definition for this
186911a5261eSBarry Smith   function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing
18702ef1f0ffSBarry Smith   in as the `ctx` argument.
187111a5261eSBarry Smith 
1872fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
1873e51e0e81SBarry Smith @*/
MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscCtx ctx,Mat * A)1874*2a8381b2SBarry Smith PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, PetscCtx ctx, Mat *A)
1875d71ae5a4SJacob Faibussowitsch {
18763a40ed3dSBarry Smith   PetscFunctionBegin;
18779566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
18789566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
18799566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATSHELL));
18809566063dSJacob Faibussowitsch   PetscCall(MatShellSetContext(*A, ctx));
18819566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*A));
18823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1883c7fcc2eaSBarry Smith }
1884c7fcc2eaSBarry Smith 
1885c6866cfdSSatish Balay /*@
188611a5261eSBarry Smith   MatShellSetContext - sets the context for a `MATSHELL` shell matrix
1887c7fcc2eaSBarry Smith 
1888c3339decSBarry Smith   Logically Collective
1889c7fcc2eaSBarry Smith 
1890273d9f13SBarry Smith   Input Parameters:
189111a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
1892273d9f13SBarry Smith - ctx - the context
1893273d9f13SBarry Smith 
1894273d9f13SBarry Smith   Level: advanced
1895273d9f13SBarry Smith 
18960b4b7b1cSBarry Smith   Note:
18970b4b7b1cSBarry Smith   This provides an easy way, along with `MatCreateShell()` and `MatShellSetOperation()` to provide a custom matrix format
18980b4b7b1cSBarry Smith   specifically for your application.
18990b4b7b1cSBarry Smith 
1900fe59aa6dSJacob Faibussowitsch   Fortran Notes:
190127430b45SBarry Smith   You must write a Fortran interface definition for this
19022ef1f0ffSBarry Smith   function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument.
1903273d9f13SBarry Smith 
19041cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
19050bc0a719SBarry Smith @*/
MatShellSetContext(Mat mat,PetscCtx ctx)1906*2a8381b2SBarry Smith PetscErrorCode MatShellSetContext(Mat mat, PetscCtx ctx)
1907d71ae5a4SJacob Faibussowitsch {
1908273d9f13SBarry Smith   PetscFunctionBegin;
19090700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1910cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx));
19113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1912e51e0e81SBarry Smith }
1913e51e0e81SBarry Smith 
1914fe59aa6dSJacob Faibussowitsch /*@C
191511a5261eSBarry Smith   MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context
1916800f99ffSJeremy L Thompson 
1917c3339decSBarry Smith   Logically Collective
1918800f99ffSJeremy L Thompson 
1919800f99ffSJeremy L Thompson   Input Parameters:
1920800f99ffSJeremy L Thompson + mat - the shell matrix
1921d1319cabSBarry Smith - f   - the context destroy function, see `PetscCtxDestroyFn` for calling sequence
1922800f99ffSJeremy L Thompson 
192327430b45SBarry Smith   Level: advanced
192427430b45SBarry Smith 
1925800f99ffSJeremy L Thompson   Note:
1926800f99ffSJeremy L Thompson   If the `MatShell` is never duplicated, the behavior of this function is equivalent
192711a5261eSBarry Smith   to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()`
1928800f99ffSJeremy L Thompson   ensures proper reference counting for the user provided context data in the case that
192911a5261eSBarry Smith   the `MATSHELL` is duplicated.
1930800f99ffSJeremy L Thompson 
1931d1319cabSBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()`,
1932d1319cabSBarry Smith           `PetscCtxDestroyFn`
1933800f99ffSJeremy L Thompson @*/
MatShellSetContextDestroy(Mat mat,PetscCtxDestroyFn * f)1934d1319cabSBarry Smith PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscCtxDestroyFn *f)
1935d71ae5a4SJacob Faibussowitsch {
1936800f99ffSJeremy L Thompson   PetscFunctionBegin;
1937800f99ffSJeremy L Thompson   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1938d1319cabSBarry Smith   PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscCtxDestroyFn *), (mat, f));
19393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1940800f99ffSJeremy L Thompson }
1941800f99ffSJeremy L Thompson 
1942db77db73SJeremy L Thompson /*@C
19432ef1f0ffSBarry Smith   MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()`
1944db77db73SJeremy L Thompson 
19452ef1f0ffSBarry Smith   Logically Collective
1946db77db73SJeremy L Thompson 
1947db77db73SJeremy L Thompson   Input Parameters:
194811a5261eSBarry Smith + mat   - the `MATSHELL` shell matrix
1949db77db73SJeremy L Thompson - vtype - type to use for creating vectors
1950db77db73SJeremy L Thompson 
1951db77db73SJeremy L Thompson   Level: advanced
1952db77db73SJeremy L Thompson 
19531cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()`
1954db77db73SJeremy L Thompson @*/
MatShellSetVecType(Mat mat,VecType vtype)1955d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype)
1956d71ae5a4SJacob Faibussowitsch {
1957db77db73SJeremy L Thompson   PetscFunctionBegin;
1958cac4c232SBarry Smith   PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype));
19593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1960db77db73SJeremy L Thompson }
1961db77db73SJeremy L Thompson 
19620c0fd78eSBarry Smith /*@
196311a5261eSBarry Smith   MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately
196411a5261eSBarry Smith   after `MatCreateShell()`
19650c0fd78eSBarry Smith 
196627430b45SBarry Smith   Logically Collective
19670c0fd78eSBarry Smith 
19680c0fd78eSBarry Smith   Input Parameter:
1969fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix
19700c0fd78eSBarry Smith 
19710c0fd78eSBarry Smith   Level: advanced
19720c0fd78eSBarry Smith 
19731cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()`
19740c0fd78eSBarry Smith @*/
MatShellSetManageScalingShifts(Mat A)1975d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A)
1976d71ae5a4SJacob Faibussowitsch {
19770c0fd78eSBarry Smith   PetscFunctionBegin;
19780c0fd78eSBarry Smith   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1979cac4c232SBarry Smith   PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A));
19803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19810c0fd78eSBarry Smith }
19820c0fd78eSBarry Smith 
1983b9c875b8SPierre Jolivet /*@C
1984b9c875b8SPierre Jolivet   MatShellGetScalingShifts - Gets members of a `MATSHELL` used internally for scaling and
1985b9c875b8SPierre Jolivet   shifting the `Mat` or calling `MatAXPY()`, `MatZeroRows()`, or `MatZeroRowsColumns()` with it
1986b9c875b8SPierre Jolivet 
1987b9c875b8SPierre Jolivet   Logically Collective
1988b9c875b8SPierre Jolivet 
1989b9c875b8SPierre Jolivet   Input Parameter:
1990b9c875b8SPierre Jolivet . A - the `MATSHELL` shell matrix
1991b9c875b8SPierre Jolivet 
1992b9c875b8SPierre Jolivet   Output Parameters:
1993b9c875b8SPierre Jolivet + vshift - `PetscScalar` pointer (can be `NULL`), see `MatShift()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be 0
1994b9c875b8SPierre Jolivet . vscale - `PetscScalar` pointer (can be `NULL`), see `MatScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be 1
1995b9c875b8SPierre Jolivet . dshift - `Vec` pointer (can be `NULL`), see `MatDiagonalSet()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be `NULL`
1996b9c875b8SPierre Jolivet . left   - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL`
1997b9c875b8SPierre Jolivet . right  - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL`
1998b9c875b8SPierre Jolivet . axpy   - `Mat` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatAXPY()` should have not been called on `A`
1999b9c875b8SPierre Jolivet . zrows  - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRows()` should have not been called on `A`
2000b9c875b8SPierre Jolivet - zcols  - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRowsColumns()` should have not been called on `A`
2001b9c875b8SPierre Jolivet 
2002b9c875b8SPierre Jolivet   Level: advanced
2003b9c875b8SPierre Jolivet 
2004b9c875b8SPierre Jolivet   Developer Notes:
2005b9c875b8SPierre Jolivet   This is mostly useful to check for corner-cases in `MatType` deriving from
2006a3f1d042SPierre Jolivet   `MATSHELL`, e.g, `MATCOMPOSITE` or `MATTRANSPOSEVIRTUAL`, since scaling and
2007b9c875b8SPierre Jolivet   shifts often require extra work which is not always implemented.
2008b9c875b8SPierre Jolivet 
2009b9c875b8SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShift()`, `MatScale()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatShellSetManageScalingShifts()`
2010b9c875b8SPierre Jolivet @*/
MatShellGetScalingShifts(Mat A,PetscScalar * vshift,PetscScalar * vscale,Vec * dshift,Vec * left,Vec * right,Mat * axpy,IS * zrows,IS * zcols)2011b9c875b8SPierre Jolivet PetscErrorCode MatShellGetScalingShifts(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols)
2012b9c875b8SPierre Jolivet {
2013b9c875b8SPierre Jolivet   PetscFunctionBegin;
2014b9c875b8SPierre Jolivet   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2015b9c875b8SPierre Jolivet   PetscTryMethod(A, "MatShellGetScalingShifts_C", (Mat, PetscScalar *, PetscScalar *, Vec *, Vec *, Vec *, Mat *, IS *, IS *), (A, vshift, vscale, dshift, left, right, axpy, zrows, zcols));
2016b9c875b8SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
2017b9c875b8SPierre Jolivet }
2018b9c875b8SPierre Jolivet 
2019c16cb8f2SBarry Smith /*@C
202011a5261eSBarry Smith   MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function.
2021f3b1f45cSBarry Smith 
2022cf53795eSBarry Smith   Logically Collective; No Fortran Support
2023f3b1f45cSBarry Smith 
2024f3b1f45cSBarry Smith   Input Parameters:
202511a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
2026f3b1f45cSBarry Smith . f    - the function
202711a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
2028f3b1f45cSBarry Smith - ctx  - an optional context for the function
2029f3b1f45cSBarry Smith 
2030f3b1f45cSBarry Smith   Output Parameter:
203111a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
2032f3b1f45cSBarry Smith 
20333c7db156SBarry Smith   Options Database Key:
2034f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
2035f3b1f45cSBarry Smith 
2036f3b1f45cSBarry Smith   Level: advanced
2037f3b1f45cSBarry Smith 
20381cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()`
2039f3b1f45cSBarry Smith @*/
MatShellTestMult(Mat mat,PetscErrorCode (* f)(void *,Vec,Vec),Vec base,PetscCtx ctx,PetscBool * flg)2040*2a8381b2SBarry Smith PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, PetscCtx ctx, PetscBool *flg)
2041d71ae5a4SJacob Faibussowitsch {
2042f3b1f45cSBarry Smith   PetscInt  m, n;
2043f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
2044f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
204574e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2046f3b1f45cSBarry Smith 
2047f3b1f45cSBarry Smith   PetscFunctionBegin;
2048f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
20499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v));
20509566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20519566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf));
20529566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
20539566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
2054f3b1f45cSBarry Smith 
20559566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
20569566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat));
2057f3b1f45cSBarry Smith 
20589566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
20599566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
20609566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
20619566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2062f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2063f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2064f3b1f45cSBarry Smith     if (v) {
206501c1178eSBarry 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)));
20669566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view"));
20679566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view"));
20689566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view"));
2069f3b1f45cSBarry Smith     }
2070f3b1f45cSBarry Smith   } else if (v) {
207101c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n"));
2072f3b1f45cSBarry Smith   }
2073f3b1f45cSBarry Smith   if (flg) *flg = flag;
20749566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
20759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
20769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
20779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
20783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2079f3b1f45cSBarry Smith }
2080f3b1f45cSBarry Smith 
2081f3b1f45cSBarry Smith /*@C
208211a5261eSBarry Smith   MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function.
2083f3b1f45cSBarry Smith 
2084cf53795eSBarry Smith   Logically Collective; No Fortran Support
2085f3b1f45cSBarry Smith 
2086f3b1f45cSBarry Smith   Input Parameters:
208711a5261eSBarry Smith + mat  - the `MATSHELL` shell matrix
2088f3b1f45cSBarry Smith . f    - the function
208911a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated
2090f3b1f45cSBarry Smith - ctx  - an optional context for the function
2091f3b1f45cSBarry Smith 
2092f3b1f45cSBarry Smith   Output Parameter:
209311a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct
2094f3b1f45cSBarry Smith 
20953c7db156SBarry Smith   Options Database Key:
2096f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
2097f3b1f45cSBarry Smith 
2098f3b1f45cSBarry Smith   Level: advanced
2099f3b1f45cSBarry Smith 
21001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()`
2101f3b1f45cSBarry Smith @*/
MatShellTestMultTranspose(Mat mat,PetscErrorCode (* f)(void *,Vec,Vec),Vec base,PetscCtx ctx,PetscBool * flg)2102*2a8381b2SBarry Smith PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, PetscCtx ctx, PetscBool *flg)
2103d71ae5a4SJacob Faibussowitsch {
2104f3b1f45cSBarry Smith   Vec       x, y, z;
2105f3b1f45cSBarry Smith   PetscInt  m, n, M, N;
2106f3b1f45cSBarry Smith   Mat       mf, Dmf, Dmat, Ddiff;
2107f3b1f45cSBarry Smith   PetscReal Diffnorm, Dmfnorm;
210874e5cdcaSBarry Smith   PetscBool v = PETSC_FALSE, flag = PETSC_TRUE;
2109f3b1f45cSBarry Smith 
2110f3b1f45cSBarry Smith   PetscFunctionBegin;
2111f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
21129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v));
21139566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(mat, &x, &y));
21149566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(y, &z));
21159566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
21169566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
21179566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf));
21189566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetFunction(mf, f, ctx));
21199566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase(mf, base, NULL));
21209566063dSJacob Faibussowitsch   PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf));
21219566063dSJacob Faibussowitsch   PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf));
21229566063dSJacob Faibussowitsch   PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat));
2123f3b1f45cSBarry Smith 
21249566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff));
21259566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN));
21269566063dSJacob Faibussowitsch   PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm));
21279566063dSJacob Faibussowitsch   PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm));
2128f3b1f45cSBarry Smith   if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) {
2129f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2130f3b1f45cSBarry Smith     if (v) {
213101c1178eSBarry 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)));
21329566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
21339566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
21349566063dSJacob Faibussowitsch       PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view"));
2135f3b1f45cSBarry Smith     }
2136f3b1f45cSBarry Smith   } else if (v) {
213701c1178eSBarry Smith     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n"));
2138f3b1f45cSBarry Smith   }
2139f3b1f45cSBarry Smith   if (flg) *flg = flag;
21409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mf));
21419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmat));
21429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ddiff));
21439566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Dmf));
21449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
21459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&y));
21469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&z));
21473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2148f3b1f45cSBarry Smith }
2149f3b1f45cSBarry Smith 
2150f3b1f45cSBarry Smith /*@C
215111a5261eSBarry Smith   MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix.
2152e51e0e81SBarry Smith 
2153c3339decSBarry Smith   Logically Collective
2154fee21e36SBarry Smith 
2155c7fcc2eaSBarry Smith   Input Parameters:
215611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2157c7fcc2eaSBarry Smith . op  - the name of the operation
2158789d8953SBarry Smith - g   - the function that provides the operation.
2159c7fcc2eaSBarry Smith 
216015091d37SBarry Smith   Level: advanced
216115091d37SBarry Smith 
21622920cce0SJacob Faibussowitsch   Example Usage:
2163c3339decSBarry Smith .vb
2164c3339decSBarry Smith   extern PetscErrorCode usermult(Mat, Vec, Vec);
21652920cce0SJacob Faibussowitsch 
2166c3339decSBarry Smith   MatCreateShell(comm, m, n, M, N, ctx, &A);
2167c3339decSBarry Smith   MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult);
2168c3339decSBarry Smith .ve
21690b627109SLois Curfman McInnes 
2170a62d957aSLois Curfman McInnes   Notes:
2171e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
21721c1c02c0SLois Curfman McInnes   operations, which all have the form MATOP_<OPERATION>, where
2173a62d957aSLois Curfman McInnes   <OPERATION> is the name (in all capital letters) of the
217411a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2175a62d957aSLois Curfman McInnes 
217611a5261eSBarry Smith   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
2177deebb3c3SLois Curfman McInnes   sequence as the usual matrix interface routines, since they
2178deebb3c3SLois Curfman McInnes   are intended to be accessed via the usual matrix interface
2179deebb3c3SLois Curfman McInnes   routines, e.g.,
2180b44f4de4SBarry Smith .vb
2181b44f4de4SBarry Smith   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2182b44f4de4SBarry Smith .ve
2183a62d957aSLois Curfman McInnes 
218457d50842SBarry Smith   In particular each function MUST return an error code of `PETSC_SUCCESS` on success and
21854aa34b0aSBarry Smith   nonzero on failure.
21864aa34b0aSBarry Smith 
2187a62d957aSLois Curfman McInnes   Within each user-defined routine, the user should call
218811a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
218911a5261eSBarry Smith   set by `MatCreateShell()`.
2190a62d957aSLois Curfman McInnes 
21912ef1f0ffSBarry Smith   Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc)
21922ef1f0ffSBarry Smith   use `MatShellSetMatProductOperation()`
2193b77ba244SStefano Zampini 
2194feaf08eaSBarry Smith   Fortran Note:
219557d50842SBarry Smith   For `MatCreateVecs()` the user code should check if the input left or right vector is -1 and in that case not
219657d50842SBarry Smith   generate a vector. See `src/mat/tests/ex120f.F`
2197501d9185SBarry Smith 
21981cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()`
2199e51e0e81SBarry Smith @*/
MatShellSetOperation(Mat mat,MatOperation op,PetscErrorCodeFn * g)220057d50842SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, PetscErrorCodeFn *g)
2201d71ae5a4SJacob Faibussowitsch {
22023a40ed3dSBarry Smith   PetscFunctionBegin;
22030700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
220457d50842SBarry Smith   PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, PetscErrorCodeFn *), (mat, op, g));
22053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2206e51e0e81SBarry Smith }
2207f0479e8cSBarry Smith 
2208d4bb536fSBarry Smith /*@C
220911a5261eSBarry Smith   MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix.
2210d4bb536fSBarry Smith 
2211c7fcc2eaSBarry Smith   Not Collective
2212c7fcc2eaSBarry Smith 
2213d4bb536fSBarry Smith   Input Parameters:
221411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix
2215c7fcc2eaSBarry Smith - op  - the name of the operation
2216d4bb536fSBarry Smith 
2217d4bb536fSBarry Smith   Output Parameter:
2218789d8953SBarry Smith . g - the function that provides the operation.
2219d4bb536fSBarry Smith 
222015091d37SBarry Smith   Level: advanced
222115091d37SBarry Smith 
222227430b45SBarry Smith   Notes:
2223e090d566SSatish Balay   See the file include/petscmat.h for a complete list of matrix
2224d4bb536fSBarry Smith   operations, which all have the form MATOP_<OPERATION>, where
2225d4bb536fSBarry Smith   <OPERATION> is the name (in all capital letters) of the
222611a5261eSBarry Smith   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
2227d4bb536fSBarry Smith 
2228d4bb536fSBarry Smith   All user-provided functions have the same calling
2229d4bb536fSBarry Smith   sequence as the usual matrix interface routines, since they
2230d4bb536fSBarry Smith   are intended to be accessed via the usual matrix interface
2231d4bb536fSBarry Smith   routines, e.g.,
2232b44f4de4SBarry Smith .vb
2233b44f4de4SBarry Smith   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
2234b44f4de4SBarry Smith .ve
2235d4bb536fSBarry Smith 
2236d4bb536fSBarry Smith   Within each user-defined routine, the user should call
223711a5261eSBarry Smith   `MatShellGetContext()` to obtain the user-defined context that was
223811a5261eSBarry Smith   set by `MatCreateShell()`.
2239d4bb536fSBarry Smith 
22401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()`
2241d4bb536fSBarry Smith @*/
MatShellGetOperation(Mat mat,MatOperation op,PetscErrorCodeFn ** g)224257d50842SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, PetscErrorCodeFn **g)
2243d71ae5a4SJacob Faibussowitsch {
22443a40ed3dSBarry Smith   PetscFunctionBegin;
22450700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224657d50842SBarry Smith   PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, PetscErrorCodeFn **), (mat, op, g));
22473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2248d4bb536fSBarry Smith }
2249b77ba244SStefano Zampini 
2250b77ba244SStefano Zampini /*@
225111a5261eSBarry Smith   MatIsShell - Inquires if a matrix is derived from `MATSHELL`
2252b77ba244SStefano Zampini 
2253b77ba244SStefano Zampini   Input Parameter:
2254b77ba244SStefano Zampini . mat - the matrix
2255b77ba244SStefano Zampini 
2256b77ba244SStefano Zampini   Output Parameter:
225722299d08SPierre Jolivet . flg - the Boolean value
2258b77ba244SStefano Zampini 
2259b77ba244SStefano Zampini   Level: developer
2260b77ba244SStefano Zampini 
22611cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT`
2262b77ba244SStefano Zampini @*/
MatIsShell(Mat mat,PetscBool * flg)2263d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2264d71ae5a4SJacob Faibussowitsch {
2265b77ba244SStefano Zampini   PetscFunctionBegin;
2266b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
22674f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
2268b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
22693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2270b77ba244SStefano Zampini }
2271