1e51e0e81SBarry Smith /* 220563c6bSBarry Smith This provides a simple shell for Fortran (and C programmers) to 320563c6bSBarry Smith create a very simple matrix class for use with KSP without coding 4ed3cc1f0SBarry Smith much of anything. 5e51e0e81SBarry Smith */ 6e51e0e81SBarry Smith 786a9fd05SPierre Jolivet #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/ 80c0fd78eSBarry Smith 945960306SStefano Zampini /* 1045960306SStefano Zampini Store and scale values on zeroed rows 1145960306SStefano Zampini xx = [x_1, 0], 0 on zeroed columns 1245960306SStefano Zampini */ 13d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx) 14d71ae5a4SJacob Faibussowitsch { 1545960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1645960306SStefano Zampini 1745960306SStefano Zampini PetscFunctionBegin; 1845960306SStefano Zampini *xx = x; 1945960306SStefano Zampini if (shell->zrows) { 209566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 219566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 229566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 239566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 2445960306SStefano Zampini } 2545960306SStefano Zampini if (shell->zcols) { 2648a46eb9SPierre Jolivet if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 279566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->right_work)); 289566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0)); 2945960306SStefano Zampini *xx = shell->right_work; 3045960306SStefano Zampini } 313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3245960306SStefano Zampini } 3345960306SStefano Zampini 3445960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 35d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x) 36d71ae5a4SJacob Faibussowitsch { 3745960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 3845960306SStefano Zampini 3945960306SStefano Zampini PetscFunctionBegin; 4045960306SStefano Zampini if (shell->zrows) { 419566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 429566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 4345960306SStefano Zampini } 443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4545960306SStefano Zampini } 4645960306SStefano Zampini 4745960306SStefano Zampini /* 4845960306SStefano Zampini Store and scale values on zeroed rows 4945960306SStefano Zampini xx = [x_1, 0], 0 on zeroed rows 5045960306SStefano Zampini */ 51d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx) 52d71ae5a4SJacob Faibussowitsch { 5345960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 5445960306SStefano Zampini 5545960306SStefano Zampini PetscFunctionBegin; 5645960306SStefano Zampini *xx = NULL; 5745960306SStefano Zampini if (!shell->zrows) { 5845960306SStefano Zampini *xx = x; 5945960306SStefano Zampini } else { 6048a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 619566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->left_work)); 629566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 639566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 649566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 659566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 669566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 679566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 6845960306SStefano Zampini *xx = shell->left_work; 6945960306SStefano Zampini } 703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7145960306SStefano Zampini } 7245960306SStefano Zampini 7345960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 74d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x) 75d71ae5a4SJacob Faibussowitsch { 7645960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 7745960306SStefano Zampini 7845960306SStefano Zampini PetscFunctionBegin; 791baa6e33SBarry Smith if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0)); 8045960306SStefano Zampini if (shell->zrows) { 819566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 829566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 8345960306SStefano Zampini } 843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8545960306SStefano Zampini } 8645960306SStefano Zampini 878fe8eb27SJed Brown /* 880c0fd78eSBarry Smith xx = diag(left)*x 898fe8eb27SJed Brown */ 90f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx, PetscBool conjugate) 91d71ae5a4SJacob Faibussowitsch { 928fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 938fe8eb27SJed Brown 948fe8eb27SJed Brown PetscFunctionBegin; 950298fd71SBarry Smith *xx = NULL; 968fe8eb27SJed Brown if (!shell->left) { 978fe8eb27SJed Brown *xx = x; 988fe8eb27SJed Brown } else { 999566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work)); 100f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 101f8e07d23SBlanca Mellado Pinto PetscInt i, m; 102f8e07d23SBlanca Mellado Pinto const PetscScalar *d, *xarray; 103f8e07d23SBlanca Mellado Pinto PetscScalar *w; 104f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 105f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->left, &d)); 106f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(x, &xarray)); 107f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayWrite(shell->left_work, &w)); 108f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) w[i] = PetscConj(d[i]) * xarray[i]; 109f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 110f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(x, &xarray)); 111f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayWrite(shell->left_work, &w)); 112f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(shell->left_work, x, shell->left)); 1138fe8eb27SJed Brown *xx = shell->left_work; 1148fe8eb27SJed Brown } 1153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1168fe8eb27SJed Brown } 1178fe8eb27SJed Brown 1180c0fd78eSBarry Smith /* 1190c0fd78eSBarry Smith xx = diag(right)*x 1200c0fd78eSBarry Smith */ 121d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx) 122d71ae5a4SJacob Faibussowitsch { 1238fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1248fe8eb27SJed Brown 1258fe8eb27SJed Brown PetscFunctionBegin; 1260298fd71SBarry Smith *xx = NULL; 1278fe8eb27SJed Brown if (!shell->right) { 1288fe8eb27SJed Brown *xx = x; 1298fe8eb27SJed Brown } else { 1309566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work)); 1319566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, x, shell->right)); 1328fe8eb27SJed Brown *xx = shell->right_work; 1338fe8eb27SJed Brown } 1343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1358fe8eb27SJed Brown } 1368fe8eb27SJed Brown 1370c0fd78eSBarry Smith /* 1380c0fd78eSBarry Smith x = diag(left)*x 1390c0fd78eSBarry Smith */ 140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x) 141d71ae5a4SJacob Faibussowitsch { 1428fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1438fe8eb27SJed Brown 1448fe8eb27SJed Brown PetscFunctionBegin; 1459566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left)); 1463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1478fe8eb27SJed Brown } 1488fe8eb27SJed Brown 1490c0fd78eSBarry Smith /* 1500c0fd78eSBarry Smith x = diag(right)*x 1510c0fd78eSBarry Smith */ 152f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x, PetscBool conjugate) 153d71ae5a4SJacob Faibussowitsch { 1548fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1558fe8eb27SJed Brown 1568fe8eb27SJed Brown PetscFunctionBegin; 157f8e07d23SBlanca Mellado Pinto if (shell->right) { 158f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 159f8e07d23SBlanca Mellado Pinto PetscInt i, m; 160f8e07d23SBlanca Mellado Pinto const PetscScalar *d; 161f8e07d23SBlanca Mellado Pinto PetscScalar *xarray; 162f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 163f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->right, &d)); 164f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArray(x, &xarray)); 165f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) xarray[i] = PetscConj(d[i]) * xarray[i]; 166f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 167f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArray(x, &xarray)); 168f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(x, x, shell->right)); 169f8e07d23SBlanca Mellado Pinto } 1703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1718fe8eb27SJed Brown } 1728fe8eb27SJed Brown 1730c0fd78eSBarry Smith /* 1740c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 1750c0fd78eSBarry Smith 1760c0fd78eSBarry Smith On input Y already contains A*x 177f8e07d23SBlanca Mellado Pinto 178f8e07d23SBlanca Mellado Pinto If conjugate=PETSC_TRUE then vscale, dshift, and vshift are conjugated 1790c0fd78eSBarry Smith */ 180f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y, PetscBool conjugate) 181d71ae5a4SJacob Faibussowitsch { 1828fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 183f8e07d23SBlanca Mellado Pinto PetscScalar vscale = conjugate ? PetscConj(shell->vscale) : shell->vscale; 184f8e07d23SBlanca Mellado Pinto PetscScalar vshift = conjugate ? PetscConj(shell->vshift) : shell->vshift; 1858fe8eb27SJed Brown 1868fe8eb27SJed Brown PetscFunctionBegin; 1878fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 1888fe8eb27SJed Brown PetscInt i, m; 1898fe8eb27SJed Brown const PetscScalar *x, *d; 1908fe8eb27SJed Brown PetscScalar *y; 1919566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &m)); 1929566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift, &d)); 1939566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 1949566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y, &y)); 195f8e07d23SBlanca Mellado Pinto if (conjugate) 196f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + PetscConj(d[i]) * x[i]; 197f8e07d23SBlanca Mellado Pinto else 198f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + d[i] * x[i]; 1999566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 2009566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 2019566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y, &y)); 2020c0fd78eSBarry Smith } else { 203f8e07d23SBlanca Mellado Pinto PetscCall(VecScale(Y, vscale)); 2048fe8eb27SJed Brown } 205f8e07d23SBlanca Mellado Pinto if (vshift != 0.0) PetscCall(VecAXPY(Y, vshift, X)); /* if test is for non-square matrices */ 2063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2078fe8eb27SJed Brown } 208e51e0e81SBarry Smith 209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx) 210d71ae5a4SJacob Faibussowitsch { 211800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 212800f99ffSJeremy L Thompson 213789d8953SBarry Smith PetscFunctionBegin; 214800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx)); 215800f99ffSJeremy L Thompson else *(void **)ctx = NULL; 2163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 217789d8953SBarry Smith } 218789d8953SBarry Smith 2199d225801SJed Brown /*@ 22011a5261eSBarry Smith MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix. 221b4fd4287SBarry Smith 222c7fcc2eaSBarry Smith Not Collective 223c7fcc2eaSBarry Smith 224b4fd4287SBarry Smith Input Parameter: 22511a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()` 226b4fd4287SBarry Smith 227b4fd4287SBarry Smith Output Parameter: 228b4fd4287SBarry Smith . ctx - the user provided context 229b4fd4287SBarry Smith 23015091d37SBarry Smith Level: advanced 23115091d37SBarry Smith 232fe59aa6dSJacob Faibussowitsch Fortran Notes: 23327430b45SBarry Smith You must write a Fortran interface definition for this 234daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 235a62d957aSLois Curfman McInnes 2361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()` 2370bc0a719SBarry Smith @*/ 238d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx) 239d71ae5a4SJacob Faibussowitsch { 2403a40ed3dSBarry Smith PetscFunctionBegin; 2410700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2424f572ea9SToby Isaac PetscAssertPointer(ctx, 2); 243cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx)); 2443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 245b4fd4287SBarry Smith } 246b4fd4287SBarry Smith 247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc) 248d71ae5a4SJacob Faibussowitsch { 24945960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 25045960306SStefano Zampini Vec x = NULL, b = NULL; 25145960306SStefano Zampini IS is1, is2; 25245960306SStefano Zampini const PetscInt *ridxs; 25345960306SStefano Zampini PetscInt *idxs, *gidxs; 25445960306SStefano Zampini PetscInt cum, rst, cst, i; 25545960306SStefano Zampini 25645960306SStefano Zampini PetscFunctionBegin; 25748a46eb9SPierre Jolivet if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals)); 25848a46eb9SPierre Jolivet if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w)); 2599566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &rst, NULL)); 2609566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL)); 26145960306SStefano Zampini 26245960306SStefano Zampini /* Expand/create index set of zeroed rows */ 2639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &idxs)); 26445960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 2659566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1)); 2669566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 2679566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals, is1, diag)); 26845960306SStefano Zampini if (shell->zrows) { 2699566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows, is1, &is2)); 2709566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 2719566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 27245960306SStefano Zampini shell->zrows = is2; 27345960306SStefano Zampini } else shell->zrows = is1; 27445960306SStefano Zampini 27545960306SStefano Zampini /* Create scatters for diagonal values communications */ 2769566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 2779566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 27845960306SStefano Zampini 27945960306SStefano Zampini /* row scatter: from/to left vector */ 2809566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &b)); 2819566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r)); 28245960306SStefano Zampini 28345960306SStefano Zampini /* col scatter: from right vector to left vector */ 2849566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows, &ridxs)); 2859566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows, &nr)); 2869566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &gidxs)); 28745960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 28845960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 28945960306SStefano Zampini gidxs[cum] = ridxs[i]; 29045960306SStefano Zampini cum++; 29145960306SStefano Zampini } 2929566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1)); 2939566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c)); 2949566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 2959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 2969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 29745960306SStefano Zampini 29845960306SStefano Zampini /* Expand/create index set of zeroed columns */ 29945960306SStefano Zampini if (rc) { 3009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &idxs)); 30145960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 3029566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1)); 3039566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 30445960306SStefano Zampini if (shell->zcols) { 3059566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols, is1, &is2)); 3069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 30845960306SStefano Zampini shell->zcols = is2; 30945960306SStefano Zampini } else shell->zcols = is1; 31045960306SStefano Zampini } 3113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 31245960306SStefano Zampini } 31345960306SStefano Zampini 314d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 315d71ae5a4SJacob Faibussowitsch { 316ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 31745960306SStefano Zampini PetscInt nr, *lrows; 31845960306SStefano Zampini 31945960306SStefano Zampini PetscFunctionBegin; 32045960306SStefano Zampini if (x && b) { 32145960306SStefano Zampini Vec xt; 32245960306SStefano Zampini PetscScalar *vals; 32345960306SStefano Zampini PetscInt *gcols, i, st, nl, nc; 32445960306SStefano Zampini 3259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &gcols)); 3269371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3279371c9d4SSatish Balay if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 32845960306SStefano Zampini 3299566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, NULL)); 3309566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc, &vals)); 3329566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3339566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3349566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3359566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3369566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */ 33745960306SStefano Zampini 3389566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3399566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3409566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 34145960306SStefano Zampini for (i = 0; i < nl; i++) { 34245960306SStefano Zampini PetscInt g = i + st; 34345960306SStefano Zampini if (g > mat->rmap->N) continue; 34445960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 3459566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES)); 34645960306SStefano Zampini } 3479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 3489566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 3499566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 3509566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 3519566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 35245960306SStefano Zampini } 3539566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL)); 3549566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE)); 3551baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL)); 3569566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 3573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35845960306SStefano Zampini } 35945960306SStefano Zampini 360d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b) 361d71ae5a4SJacob Faibussowitsch { 362ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 36345960306SStefano Zampini PetscInt *lrows, *lcols; 36445960306SStefano Zampini PetscInt nr, nc; 36545960306SStefano Zampini PetscBool congruent; 36645960306SStefano Zampini 36745960306SStefano Zampini PetscFunctionBegin; 36845960306SStefano Zampini if (x && b) { 36945960306SStefano Zampini Vec xt, bt; 37045960306SStefano Zampini PetscScalar *vals; 37145960306SStefano Zampini PetscInt *grows, *gcols, i, st, nl; 37245960306SStefano Zampini 3739566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &grows, n, &gcols)); 3749371c9d4SSatish Balay for (i = 0, nr = 0; i < n; i++) 3759371c9d4SSatish Balay if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 3769371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3779371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 3789566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n, &vals)); 37945960306SStefano Zampini 3809566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, &bt)); 3819566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3829566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3839566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3849566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3859566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt, -1.0, x)); /* xt = [0, -x2] */ 3869566063dSJacob Faibussowitsch PetscCall(MatMult(mat, xt, bt)); /* bt = [-A12*x2,-A22*x2] */ 3879566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */ 3889566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 3899566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 3909566063dSJacob Faibussowitsch PetscCall(VecAXPY(b, 1.0, bt)); /* b = [b1 - A12*x2, b2] */ 3919566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 3929566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 3939566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 3949566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 39545960306SStefano Zampini 3969566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3979566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3989566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 39945960306SStefano Zampini for (i = 0; i < nl; i++) { 40045960306SStefano Zampini PetscInt g = i + st; 40145960306SStefano Zampini if (g > mat->rmap->N) continue; 40245960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4039566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES)); 40445960306SStefano Zampini } 4059566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4069566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4079566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4109566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows, gcols)); 41145960306SStefano Zampini } 4129566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL)); 4139566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat, &congruent)); 41445960306SStefano Zampini if (congruent) { 41545960306SStefano Zampini nc = nr; 41645960306SStefano Zampini lcols = lrows; 41745960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 41845960306SStefano Zampini PetscInt i, nt, *t; 41945960306SStefano Zampini 4209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &t)); 4219371c9d4SSatish Balay for (i = 0, nt = 0; i < n; i++) 4229371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4239566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL)); 4249566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 42545960306SStefano Zampini } 4269566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE)); 42748a46eb9SPierre Jolivet if (!congruent) PetscCall(PetscFree(lcols)); 4289566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4291baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL)); 4303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43145960306SStefano Zampini } 43245960306SStefano Zampini 433d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat) 434d71ae5a4SJacob Faibussowitsch { 435bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell *)mat->data; 436b77ba244SStefano Zampini MatShellMatFunctionList matmat; 437ed3cc1f0SBarry Smith 4383a40ed3dSBarry Smith PetscFunctionBegin; 4391baa6e33SBarry Smith if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat)); 4409566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps))); 4419566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4429566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4439566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 4449566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 4459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 4469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 4479566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 4489566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 4499566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 4509566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 4519566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 4529566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 4539566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 4549566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 4559566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 4569566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 457b77ba244SStefano Zampini 458b77ba244SStefano Zampini matmat = shell->matmat; 459b77ba244SStefano Zampini while (matmat) { 460b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 461b77ba244SStefano Zampini 4629566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL)); 4639566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 4649566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 4659566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 466b77ba244SStefano Zampini matmat = next; 467b77ba244SStefano Zampini } 468800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(mat, NULL)); 4699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL)); 4709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 471800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL)); 4729566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL)); 4739566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL)); 474*b9c875b8SPierre Jolivet PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetScalingShifts_C", NULL)); 4759566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL)); 4769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL)); 4779566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL)); 4789566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 4793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 480b77ba244SStefano Zampini } 481b77ba244SStefano Zampini 482b77ba244SStefano Zampini typedef struct { 483b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 484b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 485b77ba244SStefano Zampini void *userdata; 486b77ba244SStefano Zampini Mat B; 487b77ba244SStefano Zampini Mat Bt; 488b77ba244SStefano Zampini Mat axpy; 489b77ba244SStefano Zampini } MatMatDataShell; 490b77ba244SStefano Zampini 491d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data) 492d71ae5a4SJacob Faibussowitsch { 493b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 494b77ba244SStefano Zampini 495b77ba244SStefano Zampini PetscFunctionBegin; 4961baa6e33SBarry Smith if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata)); 4979566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 4989566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 4999566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 5009566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 5013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 502b77ba244SStefano Zampini } 503b77ba244SStefano Zampini 504d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 505d71ae5a4SJacob Faibussowitsch { 506b77ba244SStefano Zampini Mat_Product *product; 507b77ba244SStefano Zampini Mat A, B; 508b77ba244SStefano Zampini MatMatDataShell *mdata; 509b77ba244SStefano Zampini PetscScalar zero = 0.0; 510b77ba244SStefano Zampini 511b77ba244SStefano Zampini PetscFunctionBegin; 512b77ba244SStefano Zampini MatCheckProduct(D, 1); 513b77ba244SStefano Zampini product = D->product; 51428b400f6SJacob Faibussowitsch PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty"); 515b77ba244SStefano Zampini A = product->A; 516b77ba244SStefano Zampini B = product->B; 517b77ba244SStefano Zampini mdata = (MatMatDataShell *)product->data; 518b77ba244SStefano Zampini if (mdata->numeric) { 519b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 520b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 521b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 522b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 523b77ba244SStefano Zampini 524b77ba244SStefano Zampini if (shell->managescalingshifts) { 52508401ef6SPierre Jolivet PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns"); 526b77ba244SStefano Zampini if (shell->right || shell->left) { 527b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 528b77ba244SStefano Zampini if (!mdata->B) { 5299566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B)); 530b77ba244SStefano Zampini } else { 531b77ba244SStefano Zampini newB = PETSC_FALSE; 532b77ba244SStefano Zampini } 5339566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN)); 534b77ba244SStefano Zampini } 535b77ba244SStefano Zampini switch (product->type) { 536b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 5371baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 538b77ba244SStefano Zampini break; 539b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 5401baa6e33SBarry Smith if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL)); 541b77ba244SStefano Zampini break; 542b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 5431baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 544b77ba244SStefano Zampini break; 545b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 546b77ba244SStefano Zampini if (shell->right && shell->left) { 547b77ba244SStefano Zampini PetscBool flg; 548b77ba244SStefano Zampini 5499566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5509371c9d4SSatish Balay PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name, 5519371c9d4SSatish Balay ((PetscObject)B)->type_name); 552b77ba244SStefano Zampini } 5531baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 554b77ba244SStefano Zampini break; 555b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 556b77ba244SStefano Zampini if (shell->right && shell->left) { 557b77ba244SStefano Zampini PetscBool flg; 558b77ba244SStefano Zampini 5599566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5609371c9d4SSatish Balay PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name, 5619371c9d4SSatish Balay ((PetscObject)B)->type_name); 562b77ba244SStefano Zampini } 5631baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 564b77ba244SStefano Zampini break; 565d71ae5a4SJacob Faibussowitsch default: 566d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 567b77ba244SStefano Zampini } 568b77ba244SStefano Zampini } 569b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 570b77ba244SStefano Zampini D->product = NULL; 571b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 572b77ba244SStefano Zampini D->ops->productnumeric = NULL; 573b77ba244SStefano Zampini 5749566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata)); 575b77ba244SStefano Zampini 576b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 5779566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 578b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 579b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 580b77ba244SStefano Zampini D->product = product; 581b77ba244SStefano Zampini 582b77ba244SStefano Zampini if (shell->managescalingshifts) { 5839566063dSJacob Faibussowitsch PetscCall(MatScale(D, shell->vscale)); 584b77ba244SStefano Zampini switch (product->type) { 585b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 586b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 587b77ba244SStefano Zampini if (shell->left) { 5889566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->left, NULL)); 589b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 5909566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 591b77ba244SStefano Zampini if (shell->dshift) { 5929566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->left_work)); 5939566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work, shell->vshift)); 5949566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left)); 595b77ba244SStefano Zampini } else { 5969566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work, shell->vshift)); 597b77ba244SStefano Zampini } 598b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 599b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 600b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 601b77ba244SStefano Zampini 6029566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt)); 6039566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL)); 6049566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->Bt, str)); 605b77ba244SStefano Zampini } else { 606b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 607b77ba244SStefano Zampini 6089566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL)); 6099566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 610b77ba244SStefano Zampini } 611b77ba244SStefano Zampini } 612b77ba244SStefano Zampini } 613b77ba244SStefano Zampini break; 614b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 615b77ba244SStefano Zampini if (shell->right) { 6169566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->right, NULL)); 617b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 618b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 619b77ba244SStefano Zampini 6209566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 621b77ba244SStefano Zampini if (shell->dshift) { 6229566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->right_work)); 6239566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work, shell->vshift)); 6249566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right)); 625b77ba244SStefano Zampini } else { 6269566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work, shell->vshift)); 627b77ba244SStefano Zampini } 6289566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL)); 6299566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 630b77ba244SStefano Zampini } 631b77ba244SStefano Zampini } 632b77ba244SStefano Zampini break; 633b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 634b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6359371c9d4SSatish Balay PetscCheck(!shell->dshift && shell->vshift == zero, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices with diagonal shift", MatProductTypes[product->type], ((PetscObject)A)->type_name, 6369371c9d4SSatish Balay ((PetscObject)B)->type_name); 637b77ba244SStefano Zampini break; 638d71ae5a4SJacob Faibussowitsch default: 639d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 640b77ba244SStefano Zampini } 641b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 642b77ba244SStefano Zampini Mat X; 643b77ba244SStefano Zampini PetscObjectState axpy_state; 644b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 645b77ba244SStefano Zampini 6469566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 6479566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 64808401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 649b77ba244SStefano Zampini if (!mdata->axpy) { 650b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6519566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy)); 6529566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy, product->type)); 6539566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6549566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 655b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 656b77ba244SStefano Zampini PetscBool flg; 657b77ba244SStefano Zampini 6589566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy)); 6599566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg)); 660b77ba244SStefano Zampini if (!flg) { 661b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6629566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6639566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 664b77ba244SStefano Zampini } 665b77ba244SStefano Zampini } 6669566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 6679566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str)); 668b77ba244SStefano Zampini } 669b77ba244SStefano Zampini } 670b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation"); 6713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 672b77ba244SStefano Zampini } 673b77ba244SStefano Zampini 674d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 675d71ae5a4SJacob Faibussowitsch { 676b77ba244SStefano Zampini Mat_Product *product; 677b77ba244SStefano Zampini Mat A, B; 678b77ba244SStefano Zampini MatShellMatFunctionList matmat; 679b77ba244SStefano Zampini Mat_Shell *shell; 680eae3dc7dSJacob Faibussowitsch PetscBool flg = PETSC_FALSE; 681b77ba244SStefano Zampini char composedname[256]; 682b77ba244SStefano Zampini MatMatDataShell *mdata; 683b77ba244SStefano Zampini 684b77ba244SStefano Zampini PetscFunctionBegin; 685b77ba244SStefano Zampini MatCheckProduct(D, 1); 686b77ba244SStefano Zampini product = D->product; 68728b400f6SJacob Faibussowitsch PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty"); 688b77ba244SStefano Zampini A = product->A; 689b77ba244SStefano Zampini B = product->B; 690b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 691b77ba244SStefano Zampini matmat = shell->matmat; 6929566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 693b77ba244SStefano Zampini while (matmat) { 6949566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 695b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 696b77ba244SStefano Zampini if (flg) break; 697b77ba244SStefano Zampini matmat = matmat->next; 698b77ba244SStefano Zampini } 69928b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]); 700b77ba244SStefano Zampini switch (product->type) { 701d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AB: 702d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); 703d71ae5a4SJacob Faibussowitsch break; 704d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AtB: 705d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); 706d71ae5a4SJacob Faibussowitsch break; 707d71ae5a4SJacob Faibussowitsch case MATPRODUCT_ABt: 708d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N)); 709d71ae5a4SJacob Faibussowitsch break; 710d71ae5a4SJacob Faibussowitsch case MATPRODUCT_RARt: 711d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N)); 712d71ae5a4SJacob Faibussowitsch break; 713d71ae5a4SJacob Faibussowitsch case MATPRODUCT_PtAP: 714d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N)); 715d71ae5a4SJacob Faibussowitsch break; 716d71ae5a4SJacob Faibussowitsch default: 717d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 718b77ba244SStefano Zampini } 719b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 720b77ba244SStefano Zampini if (matmat->resultname) { 7219566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg)); 72248a46eb9SPierre Jolivet if (!flg) PetscCall(MatSetType(D, matmat->resultname)); 723b77ba244SStefano Zampini } 724b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 725b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 726b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 727b77ba244SStefano Zampini /* attach product data */ 7289566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 729b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 730b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 731b77ba244SStefano Zampini if (matmat->symbolic) { 7329566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata)); 733b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7349566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 735b77ba244SStefano Zampini } 73628b400f6SJacob Faibussowitsch PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase"); 73728b400f6SJacob Faibussowitsch PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase"); 738b77ba244SStefano Zampini D->product->data = mdata; 739b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 740b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 741b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 742b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 7433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 744b77ba244SStefano Zampini } 745b77ba244SStefano Zampini 746d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 747d71ae5a4SJacob Faibussowitsch { 748b77ba244SStefano Zampini Mat_Product *product; 749b77ba244SStefano Zampini Mat A, B; 750b77ba244SStefano Zampini MatShellMatFunctionList matmat; 751b77ba244SStefano Zampini Mat_Shell *shell; 752b77ba244SStefano Zampini PetscBool flg; 753b77ba244SStefano Zampini char composedname[256]; 754b77ba244SStefano Zampini 755b77ba244SStefano Zampini PetscFunctionBegin; 756b77ba244SStefano Zampini MatCheckProduct(D, 1); 757b77ba244SStefano Zampini product = D->product; 758b77ba244SStefano Zampini A = product->A; 759b77ba244SStefano Zampini B = product->B; 7609566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 7613ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 762b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 763b77ba244SStefano Zampini matmat = shell->matmat; 7649566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 765b77ba244SStefano Zampini while (matmat) { 7669566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 767b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 768b77ba244SStefano Zampini if (flg) break; 769b77ba244SStefano Zampini matmat = matmat->next; 770b77ba244SStefano Zampini } 7719371c9d4SSatish Balay if (flg) { 7729371c9d4SSatish Balay D->ops->productsymbolic = MatProductSymbolic_Shell_X; 7739371c9d4SSatish Balay } else PetscCall(PetscInfo(D, " symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type])); 7743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 775b77ba244SStefano Zampini } 776b77ba244SStefano Zampini 777d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), char *composedname, const char *resultname) 778d71ae5a4SJacob Faibussowitsch { 779b77ba244SStefano Zampini PetscBool flg; 780b77ba244SStefano Zampini Mat_Shell *shell; 781b77ba244SStefano Zampini MatShellMatFunctionList matmat; 782b77ba244SStefano Zampini 783b77ba244SStefano Zampini PetscFunctionBegin; 78428b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine"); 78528b400f6SJacob Faibussowitsch PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name"); 786b77ba244SStefano Zampini 787b77ba244SStefano Zampini /* add product callback */ 788b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 789b77ba244SStefano Zampini matmat = shell->matmat; 790b77ba244SStefano Zampini if (!matmat) { 7919566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 792b77ba244SStefano Zampini matmat = shell->matmat; 793b77ba244SStefano Zampini } else { 794b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 795b77ba244SStefano Zampini while (entry) { 7969566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, entry->composedname, &flg)); 797b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 798b77ba244SStefano Zampini matmat = entry; 7992e956fe4SStefano Zampini if (flg) goto set; 800b77ba244SStefano Zampini entry = entry->next; 801b77ba244SStefano Zampini } 8029566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 803b77ba244SStefano Zampini matmat = matmat->next; 804b77ba244SStefano Zampini } 805b77ba244SStefano Zampini 806843d480fSStefano Zampini set: 807b77ba244SStefano Zampini matmat->symbolic = symbolic; 808b77ba244SStefano Zampini matmat->numeric = numeric; 809b77ba244SStefano Zampini matmat->destroy = destroy; 810b77ba244SStefano Zampini matmat->ptype = ptype; 8119566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8129566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8139566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname, &matmat->composedname)); 8149566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname, &matmat->resultname)); 8159566063dSJacob Faibussowitsch PetscCall(PetscInfo(A, "Composing %s for product type %s with result %s\n", matmat->composedname, MatProductTypes[matmat->ptype], matmat->resultname ? matmat->resultname : "not specified")); 8169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X)); 8173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 818b77ba244SStefano Zampini } 819b77ba244SStefano Zampini 820b77ba244SStefano Zampini /*@C 82111a5261eSBarry Smith MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix. 822b77ba244SStefano Zampini 82327430b45SBarry Smith Logically Collective; No Fortran Support 824b77ba244SStefano Zampini 825b77ba244SStefano Zampini Input Parameters: 82611a5261eSBarry Smith + A - the `MATSHELL` shell matrix 827b77ba244SStefano Zampini . ptype - the product type 8282ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`) 829b77ba244SStefano Zampini . numeric - the function for the numerical phase 8302ef1f0ffSBarry Smith . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`) 831b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 8322ef1f0ffSBarry Smith - Ctype - the matrix type for the result (can be `NULL`) 833b77ba244SStefano Zampini 834b77ba244SStefano Zampini Level: advanced 835b77ba244SStefano Zampini 8362920cce0SJacob Faibussowitsch Example Usage: 837cf53795eSBarry Smith .vb 838cf53795eSBarry Smith extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**); 839cf53795eSBarry Smith extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*); 840cf53795eSBarry Smith extern PetscErrorCode userdestroy(void*); 8412920cce0SJacob Faibussowitsch 842cf53795eSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 8432920cce0SJacob Faibussowitsch MatShellSetMatProductOperation( 8442920cce0SJacob Faibussowitsch A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE 8452920cce0SJacob Faibussowitsch ); 8462920cce0SJacob Faibussowitsch // create B of type SEQAIJ etc.. 8472920cce0SJacob Faibussowitsch MatProductCreate(A, B, PETSC_NULLPTR, &C); 848cf53795eSBarry Smith MatProductSetType(C, MATPRODUCT_AB); 849cf53795eSBarry Smith MatProductSetFromOptions(C); 8502920cce0SJacob Faibussowitsch MatProductSymbolic(C); // actually runs the user defined symbolic operation 8512920cce0SJacob Faibussowitsch MatProductNumeric(C); // actually runs the user defined numeric operation 8522920cce0SJacob Faibussowitsch // use C = A * B 853cf53795eSBarry Smith .ve 854b77ba244SStefano Zampini 855b77ba244SStefano Zampini Notes: 856cf53795eSBarry Smith `MATPRODUCT_ABC` is not supported yet. 85711a5261eSBarry Smith 8582ef1f0ffSBarry Smith If the symbolic phase is not specified, `MatSetUp()` is called on the result matrix that must have its type set if Ctype is `NULL`. 85911a5261eSBarry Smith 860b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 861b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 862b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 86327430b45SBarry Smith The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence. 864b77ba244SStefano Zampini 8651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()` 866b77ba244SStefano Zampini @*/ 867d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetMatProductOperation(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype) 868d71ae5a4SJacob Faibussowitsch { 869b77ba244SStefano Zampini PetscFunctionBegin; 870b77ba244SStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 871b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A, ptype, 2); 87208401ef6SPierre Jolivet PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]); 87328b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4"); 8744f572ea9SToby Isaac PetscAssertPointer(Btype, 6); 8754f572ea9SToby Isaac if (Ctype) PetscAssertPointer(Ctype, 7); 876cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetMatProductOperation_C", (Mat, MatProductType, PetscErrorCode(*)(Mat, Mat, Mat, void **), PetscErrorCode(*)(Mat, Mat, Mat, void *), PetscErrorCode(*)(void *), MatType, MatType), (A, ptype, symbolic, numeric, destroy, Btype, Ctype)); 8773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 878b77ba244SStefano Zampini } 879b77ba244SStefano Zampini 880d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype) 881d71ae5a4SJacob Faibussowitsch { 882b77ba244SStefano Zampini PetscBool flg; 883b77ba244SStefano Zampini char composedname[256]; 884b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 885b77ba244SStefano Zampini PetscMPIInt size; 886b77ba244SStefano Zampini 887b77ba244SStefano Zampini PetscFunctionBegin; 888b77ba244SStefano Zampini PetscValidType(A, 1); 889b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 8909566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg)); 891b77ba244SStefano Zampini if (flg) break; 892b77ba244SStefano Zampini Bnames = Bnames->next; 893b77ba244SStefano Zampini } 894b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 8959566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg)); 896b77ba244SStefano Zampini if (flg) break; 897b77ba244SStefano Zampini Cnames = Cnames->next; 898b77ba244SStefano Zampini } 8999566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 900b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 901b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9029566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype)); 9039566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype)); 9043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 905e51e0e81SBarry Smith } 906e51e0e81SBarry Smith 907d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str) 908d71ae5a4SJacob Faibussowitsch { 90928f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data; 910cb8c8a77SBarry Smith PetscBool matflg; 911b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9127fabda3fSAlex Fikl 9137fabda3fSAlex Fikl PetscFunctionBegin; 9149566063dSJacob Faibussowitsch PetscCall(MatIsShell(B, &matflg)); 91528b400f6SJacob Faibussowitsch PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name); 9167fabda3fSAlex Fikl 917aea10558SJacob Faibussowitsch B->ops[0] = A->ops[0]; 918aea10558SJacob Faibussowitsch shellB->ops[0] = shellA->ops[0]; 9197fabda3fSAlex Fikl 9201baa6e33SBarry Smith if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str)); 9217fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9227fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9230c0fd78eSBarry Smith if (shellA->dshift) { 92448a46eb9SPierre Jolivet if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift)); 9259566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift, shellB->dshift)); 9267fabda3fSAlex Fikl } else { 9279566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9287fabda3fSAlex Fikl } 9290c0fd78eSBarry Smith if (shellA->left) { 93048a46eb9SPierre Jolivet if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left)); 9319566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left, shellB->left)); 9327fabda3fSAlex Fikl } else { 9339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9347fabda3fSAlex Fikl } 9350c0fd78eSBarry Smith if (shellA->right) { 93648a46eb9SPierre Jolivet if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right)); 9379566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right, shellB->right)); 9387fabda3fSAlex Fikl } else { 9399566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9407fabda3fSAlex Fikl } 9419566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 942ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 943ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 94440e381c3SBarry Smith if (shellA->axpy) { 9459566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 94640e381c3SBarry Smith shellB->axpy = shellA->axpy; 94740e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 948ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 94940e381c3SBarry Smith } 95045960306SStefano Zampini if (shellA->zrows) { 9519566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows)); 95248a46eb9SPierre Jolivet if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols)); 9539566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals)); 9549566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals, shellB->zvals)); 9559566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w)); 9569566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 9579566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 95845960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 95945960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 96045960306SStefano Zampini } 961b77ba244SStefano Zampini 962b77ba244SStefano Zampini matmatA = shellA->matmat; 963b77ba244SStefano Zampini if (matmatA) { 964b77ba244SStefano Zampini while (matmatA->next) { 9659566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname)); 966b77ba244SStefano Zampini matmatA = matmatA->next; 967b77ba244SStefano Zampini } 968b77ba244SStefano Zampini } 9693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9707fabda3fSAlex Fikl } 9717fabda3fSAlex Fikl 972d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M) 973d71ae5a4SJacob Faibussowitsch { 974cb8c8a77SBarry Smith PetscFunctionBegin; 975800f99ffSJeremy L Thompson PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M)); 976800f99ffSJeremy L Thompson ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer; 977f4f49eeaSPierre Jolivet PetscCall(PetscObjectCompose((PetscObject)*M, "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer)); 978f4f49eeaSPierre Jolivet PetscCall(PetscObjectChangeTypeName((PetscObject)*M, ((PetscObject)mat)->type_name)); 979623b4cf3SPierre Jolivet if (op == MAT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN)); 98001f93aa2SJose E. Roman PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M)); 9813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 982cb8c8a77SBarry Smith } 983cb8c8a77SBarry Smith 98466976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y) 985d71ae5a4SJacob Faibussowitsch { 986ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 98725578ef6SJed Brown Vec xx; 988e3f487b0SBarry Smith PetscObjectState instate, outstate; 989ef66eb69SBarry Smith 990ef66eb69SBarry Smith PetscFunctionBegin; 9919566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A, x, &xx)); 9929566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A, xx, &xx)); 9939566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 9949566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A, xx, y)); 9959566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 996e3f487b0SBarry Smith if (instate == outstate) { 997e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 9989566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 999e3f487b0SBarry Smith } 1000f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 10019566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A, y)); 10029566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A, y)); 10039f137db4SBarry Smith 10049f137db4SBarry Smith if (shell->axpy) { 1005ef5c7bd2SStefano Zampini Mat X; 1006ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1007ef5c7bd2SStefano Zampini 10089566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10099566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 101008401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1011b77ba244SStefano Zampini 10129566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10139566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_right)); 10149566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left)); 10159566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left)); 10169f137db4SBarry Smith } 10173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1018ef66eb69SBarry Smith } 1019ef66eb69SBarry Smith 1020d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1021d71ae5a4SJacob Faibussowitsch { 10225edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10235edf6516SJed Brown 10245edf6516SJed Brown PetscFunctionBegin; 10255edf6516SJed Brown if (y == z) { 10269566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work)); 10279566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, shell->right_add_work)); 10289566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->right_add_work)); 10295edf6516SJed Brown } else { 10309566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, z)); 10319566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 10325edf6516SJed Brown } 10333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10345edf6516SJed Brown } 10355edf6516SJed Brown 1036d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y) 1037d71ae5a4SJacob Faibussowitsch { 103818be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 103925578ef6SJed Brown Vec xx; 1040e3f487b0SBarry Smith PetscObjectState instate, outstate; 104118be62a5SSatish Balay 104218be62a5SSatish Balay PetscFunctionBegin; 10439566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1044f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE)); 10459566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10469566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A, xx, y)); 10479566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1048e3f487b0SBarry Smith if (instate == outstate) { 1049e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10509566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1051e3f487b0SBarry Smith } 1052f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 1053f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE)); 10549566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A, y)); 1055350ec83bSStefano Zampini 1056350ec83bSStefano Zampini if (shell->axpy) { 1057ef5c7bd2SStefano Zampini Mat X; 1058ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1059ef5c7bd2SStefano Zampini 10609566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10619566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 106208401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 10639566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10649566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_left)); 10659566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 10669566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right)); 1067350ec83bSStefano Zampini } 10683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 106918be62a5SSatish Balay } 107018be62a5SSatish Balay 1071f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y) 1072f8e07d23SBlanca Mellado Pinto { 1073f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1074f8e07d23SBlanca Mellado Pinto Vec xx; 1075f8e07d23SBlanca Mellado Pinto PetscObjectState instate, outstate; 1076f8e07d23SBlanca Mellado Pinto 1077f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1078f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1079f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE)); 1080f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 1081f8e07d23SBlanca Mellado Pinto PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y)); 1082f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1083f8e07d23SBlanca Mellado Pinto if (instate == outstate) { 1084f8e07d23SBlanca Mellado Pinto /* increase the state of the output vector since the user did not update its state themself as should have been done */ 1085f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1086f8e07d23SBlanca Mellado Pinto } 1087f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE)); 1088f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE)); 1089f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostZeroRight(A, y)); 1090f8e07d23SBlanca Mellado Pinto 1091f8e07d23SBlanca Mellado Pinto if (shell->axpy) { 1092f8e07d23SBlanca Mellado Pinto Mat X; 1093f8e07d23SBlanca Mellado Pinto PetscObjectState axpy_state; 1094f8e07d23SBlanca Mellado Pinto 1095f8e07d23SBlanca Mellado Pinto PetscCall(MatShellGetContext(shell->axpy, &X)); 1096f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 1097f8e07d23SBlanca Mellado Pinto PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1098f8e07d23SBlanca Mellado Pinto PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 1099f8e07d23SBlanca Mellado Pinto PetscCall(VecCopy(x, shell->axpy_left)); 1100f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 1101f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right)); 1102f8e07d23SBlanca Mellado Pinto } 1103f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1104f8e07d23SBlanca Mellado Pinto } 1105f8e07d23SBlanca Mellado Pinto 1106d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1107d71ae5a4SJacob Faibussowitsch { 11085edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 11095edf6516SJed Brown 11105edf6516SJed Brown PetscFunctionBegin; 11115edf6516SJed Brown if (y == z) { 11129566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 11139566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, shell->left_add_work)); 11149566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 11155edf6516SJed Brown } else { 11169566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, z)); 11179566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 11185edf6516SJed Brown } 11193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11205edf6516SJed Brown } 11215edf6516SJed Brown 1122f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1123f8e07d23SBlanca Mellado Pinto { 1124f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1125f8e07d23SBlanca Mellado Pinto 1126f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1127f8e07d23SBlanca Mellado Pinto if (y == z) { 1128f8e07d23SBlanca Mellado Pinto if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 1129f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work)); 1130f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 1131f8e07d23SBlanca Mellado Pinto } else { 1132f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, z)); 1133f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, y)); 1134f8e07d23SBlanca Mellado Pinto } 1135f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1136f8e07d23SBlanca Mellado Pinto } 1137f8e07d23SBlanca Mellado Pinto 11380c0fd78eSBarry Smith /* 11390c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11400c0fd78eSBarry Smith */ 1141d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v) 1142d71ae5a4SJacob Faibussowitsch { 114318be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 114418be62a5SSatish Balay 114518be62a5SSatish Balay PetscFunctionBegin; 11460c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 11479566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A, v)); 1148305211d5SBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)"); 11499566063dSJacob Faibussowitsch PetscCall(VecScale(v, shell->vscale)); 11501baa6e33SBarry Smith if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift)); 11519566063dSJacob Faibussowitsch PetscCall(VecShift(v, shell->vshift)); 11529566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left)); 11539566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right)); 115445960306SStefano Zampini if (shell->zrows) { 11559566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 11569566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 115745960306SStefano Zampini } 115881c02519SBarry Smith if (shell->axpy) { 1159ef5c7bd2SStefano Zampini Mat X; 1160ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1161ef5c7bd2SStefano Zampini 11629566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 11639566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 116408401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 11659566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left)); 11669566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left)); 11679566063dSJacob Faibussowitsch PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left)); 116881c02519SBarry Smith } 11693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 117018be62a5SSatish Balay } 117118be62a5SSatish Balay 1172d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a) 1173d71ae5a4SJacob Faibussowitsch { 1174ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1175789d8953SBarry Smith PetscBool flg; 1176b24ad042SBarry Smith 1177ef66eb69SBarry Smith PetscFunctionBegin; 11789566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y, &flg)); 117928b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent"); 11800c0fd78eSBarry Smith if (shell->left || shell->right) { 11818fe8eb27SJed Brown if (!shell->dshift) { 11829566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 11839566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift, a)); 11840c0fd78eSBarry Smith } else { 11859566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left)); 11869566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right)); 11879566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift, a)); 11880c0fd78eSBarry Smith } 11899566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left)); 11909566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right)); 11918fe8eb27SJed Brown } else shell->vshift += a; 11921baa6e33SBarry Smith if (shell->zrows) PetscCall(VecShift(shell->zvals, a)); 11933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1194ef66eb69SBarry Smith } 1195ef66eb69SBarry Smith 1196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s) 1197d71ae5a4SJacob Faibussowitsch { 11986464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell *)A->data; 11996464bf51SAlex Fikl 12006464bf51SAlex Fikl PetscFunctionBegin; 12019566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift)); 12020c0fd78eSBarry Smith if (shell->left || shell->right) { 12039566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 12049f137db4SBarry Smith if (shell->left && shell->right) { 12059566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12069566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right)); 12079f137db4SBarry Smith } else if (shell->left) { 12089566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12099f137db4SBarry Smith } else { 12109566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right)); 12119f137db4SBarry Smith } 12129566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, shell->right_work)); 12130c0fd78eSBarry Smith } else { 12149566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, D)); 1215b253ae0bS“Marek } 12163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1217b253ae0bS“Marek } 1218b253ae0bS“Marek 121966976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins) 1220d71ae5a4SJacob Faibussowitsch { 122145960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1222b253ae0bS“Marek Vec d; 1223789d8953SBarry Smith PetscBool flg; 1224b253ae0bS“Marek 1225b253ae0bS“Marek PetscFunctionBegin; 12269566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &flg)); 122728b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent"); 1228b253ae0bS“Marek if (ins == INSERT_VALUES) { 12299566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D, &d)); 12309566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A, d)); 12319566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.)); 12329566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 12341baa6e33SBarry Smith if (shell->zrows) PetscCall(VecCopy(D, shell->zvals)); 1235b253ae0bS“Marek } else { 12369566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12371baa6e33SBarry Smith if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D)); 12386464bf51SAlex Fikl } 12393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12406464bf51SAlex Fikl } 12416464bf51SAlex Fikl 1242d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a) 1243d71ae5a4SJacob Faibussowitsch { 1244ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1245b24ad042SBarry Smith 1246ef66eb69SBarry Smith PetscFunctionBegin; 1247f4df32b1SMatthew Knepley shell->vscale *= a; 12480c0fd78eSBarry Smith shell->vshift *= a; 12491baa6e33SBarry Smith if (shell->dshift) PetscCall(VecScale(shell->dshift, a)); 125081c02519SBarry Smith shell->axpy_vscale *= a; 12511baa6e33SBarry Smith if (shell->zrows) PetscCall(VecScale(shell->zvals, a)); 12523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 125318be62a5SSatish Balay } 12548fe8eb27SJed Brown 1255d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right) 1256d71ae5a4SJacob Faibussowitsch { 12578fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)Y->data; 12588fe8eb27SJed Brown 12598fe8eb27SJed Brown PetscFunctionBegin; 12608fe8eb27SJed Brown if (left) { 12610c0fd78eSBarry Smith if (!shell->left) { 12629566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left, &shell->left)); 12639566063dSJacob Faibussowitsch PetscCall(VecCopy(left, shell->left)); 12640c0fd78eSBarry Smith } else { 12659566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left, shell->left, left)); 126618be62a5SSatish Balay } 12671baa6e33SBarry Smith if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left)); 1268ef66eb69SBarry Smith } 12698fe8eb27SJed Brown if (right) { 12700c0fd78eSBarry Smith if (!shell->right) { 12719566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right, &shell->right)); 12729566063dSJacob Faibussowitsch PetscCall(VecCopy(right, shell->right)); 12730c0fd78eSBarry Smith } else { 12749566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right, shell->right, right)); 12758fe8eb27SJed Brown } 127645960306SStefano Zampini if (shell->zrows) { 127748a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work)); 12789566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 1.0)); 12799566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12809566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12819566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w)); 128245960306SStefano Zampini } 12838fe8eb27SJed Brown } 12841baa6e33SBarry Smith if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right)); 12853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1286ef66eb69SBarry Smith } 1287ef66eb69SBarry Smith 128886a9fd05SPierre Jolivet PETSC_INTERN PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t) 1289d71ae5a4SJacob Faibussowitsch { 1290ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1291ef66eb69SBarry Smith 1292ef66eb69SBarry Smith PetscFunctionBegin; 12938fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1294ef66eb69SBarry Smith shell->vshift = 0.0; 1295ef66eb69SBarry Smith shell->vscale = 1.0; 1296ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1297ef5c7bd2SStefano Zampini shell->axpy_state = 0; 12989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 12999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 13009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 13019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 13029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 13039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 13049566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 13059566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 13069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 13079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1308ef66eb69SBarry Smith } 13093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1310ef66eb69SBarry Smith } 1311ef66eb69SBarry Smith 1312d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d) 1313d71ae5a4SJacob Faibussowitsch { 13143b49f96aSBarry Smith PetscFunctionBegin; 13153b49f96aSBarry Smith *missing = PETSC_FALSE; 13163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13173b49f96aSBarry Smith } 13183b49f96aSBarry Smith 131966976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str) 1320d71ae5a4SJacob Faibussowitsch { 13219f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 13229f137db4SBarry Smith 13239f137db4SBarry Smith PetscFunctionBegin; 1324ef5c7bd2SStefano Zampini if (X == Y) { 13259566063dSJacob Faibussowitsch PetscCall(MatScale(Y, 1.0 + a)); 13263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1327ef5c7bd2SStefano Zampini } 1328ef5c7bd2SStefano Zampini if (!shell->axpy) { 13299566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy)); 13309f137db4SBarry Smith shell->axpy_vscale = a; 13319566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state)); 1332ef5c7bd2SStefano Zampini } else { 13339566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str)); 1334ef5c7bd2SStefano Zampini } 13353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13369f137db4SBarry Smith } 13379f137db4SBarry Smith 1338f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1339f4259b30SLisandro Dalcin NULL, 1340f4259b30SLisandro Dalcin NULL, 1341f4259b30SLisandro Dalcin NULL, 13420c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1343f4259b30SLisandro Dalcin NULL, 13440c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1345f4259b30SLisandro Dalcin NULL, 1346f4259b30SLisandro Dalcin NULL, 1347f4259b30SLisandro Dalcin NULL, 1348f4259b30SLisandro Dalcin /*10*/ NULL, 1349f4259b30SLisandro Dalcin NULL, 1350f4259b30SLisandro Dalcin NULL, 1351f4259b30SLisandro Dalcin NULL, 1352f4259b30SLisandro Dalcin NULL, 1353f4259b30SLisandro Dalcin /*15*/ NULL, 1354f4259b30SLisandro Dalcin NULL, 1355f4259b30SLisandro Dalcin NULL, 13568fe8eb27SJed Brown MatDiagonalScale_Shell, 1357f4259b30SLisandro Dalcin NULL, 1358f4259b30SLisandro Dalcin /*20*/ NULL, 1359ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1360f4259b30SLisandro Dalcin NULL, 1361f4259b30SLisandro Dalcin NULL, 136245960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1363f4259b30SLisandro Dalcin NULL, 1364f4259b30SLisandro Dalcin NULL, 1365f4259b30SLisandro Dalcin NULL, 1366f4259b30SLisandro Dalcin NULL, 1367f4259b30SLisandro Dalcin /*29*/ NULL, 1368f4259b30SLisandro Dalcin NULL, 1369f4259b30SLisandro Dalcin NULL, 1370f4259b30SLisandro Dalcin NULL, 1371f4259b30SLisandro Dalcin NULL, 1372cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1373f4259b30SLisandro Dalcin NULL, 1374f4259b30SLisandro Dalcin NULL, 1375f4259b30SLisandro Dalcin NULL, 1376f4259b30SLisandro Dalcin NULL, 13779f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1378f4259b30SLisandro Dalcin NULL, 1379f4259b30SLisandro Dalcin NULL, 1380f4259b30SLisandro Dalcin NULL, 1381cb8c8a77SBarry Smith MatCopy_Shell, 1382f4259b30SLisandro Dalcin /*44*/ NULL, 1383ef66eb69SBarry Smith MatScale_Shell, 1384ef66eb69SBarry Smith MatShift_Shell, 13856464bf51SAlex Fikl MatDiagonalSet_Shell, 138645960306SStefano Zampini MatZeroRowsColumns_Shell, 1387f4259b30SLisandro Dalcin /*49*/ NULL, 1388f4259b30SLisandro Dalcin NULL, 1389f4259b30SLisandro Dalcin NULL, 1390f4259b30SLisandro Dalcin NULL, 1391f4259b30SLisandro Dalcin NULL, 1392f4259b30SLisandro Dalcin /*54*/ NULL, 1393f4259b30SLisandro Dalcin NULL, 1394f4259b30SLisandro Dalcin NULL, 1395f4259b30SLisandro Dalcin NULL, 1396f4259b30SLisandro Dalcin NULL, 1397f4259b30SLisandro Dalcin /*59*/ NULL, 1398b9b97703SBarry Smith MatDestroy_Shell, 1399f4259b30SLisandro Dalcin NULL, 1400251fad3fSStefano Zampini MatConvertFrom_Shell, 1401f4259b30SLisandro Dalcin NULL, 1402f4259b30SLisandro Dalcin /*64*/ NULL, 1403f4259b30SLisandro Dalcin NULL, 1404f4259b30SLisandro Dalcin NULL, 1405f4259b30SLisandro Dalcin NULL, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin /*69*/ NULL, 1408f4259b30SLisandro Dalcin NULL, 1409c87e5d42SMatthew Knepley MatConvert_Shell, 1410f4259b30SLisandro Dalcin NULL, 1411f4259b30SLisandro Dalcin NULL, 1412f4259b30SLisandro Dalcin /*74*/ NULL, 1413f4259b30SLisandro Dalcin NULL, 1414f4259b30SLisandro Dalcin NULL, 1415f4259b30SLisandro Dalcin NULL, 1416f4259b30SLisandro Dalcin NULL, 1417f4259b30SLisandro Dalcin /*79*/ NULL, 1418f4259b30SLisandro Dalcin NULL, 1419f4259b30SLisandro Dalcin NULL, 1420f4259b30SLisandro Dalcin NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin /*84*/ NULL, 1423f4259b30SLisandro Dalcin NULL, 1424f4259b30SLisandro Dalcin NULL, 1425f4259b30SLisandro Dalcin NULL, 1426f4259b30SLisandro Dalcin NULL, 1427f4259b30SLisandro Dalcin /*89*/ NULL, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin NULL, 1430f4259b30SLisandro Dalcin NULL, 1431f4259b30SLisandro Dalcin NULL, 1432f4259b30SLisandro Dalcin /*94*/ NULL, 1433f4259b30SLisandro Dalcin NULL, 1434f4259b30SLisandro Dalcin NULL, 1435f4259b30SLisandro Dalcin NULL, 1436f4259b30SLisandro Dalcin NULL, 1437f4259b30SLisandro Dalcin /*99*/ NULL, 1438f4259b30SLisandro Dalcin NULL, 1439f4259b30SLisandro Dalcin NULL, 1440f4259b30SLisandro Dalcin NULL, 1441f4259b30SLisandro Dalcin NULL, 1442f4259b30SLisandro Dalcin /*104*/ NULL, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin NULL, 1445f4259b30SLisandro Dalcin NULL, 1446f4259b30SLisandro Dalcin NULL, 1447f4259b30SLisandro Dalcin /*109*/ NULL, 1448f4259b30SLisandro Dalcin NULL, 1449f4259b30SLisandro Dalcin NULL, 1450f4259b30SLisandro Dalcin NULL, 14513b49f96aSBarry Smith MatMissingDiagonal_Shell, 1452f4259b30SLisandro Dalcin /*114*/ NULL, 1453f4259b30SLisandro Dalcin NULL, 1454f4259b30SLisandro Dalcin NULL, 1455f4259b30SLisandro Dalcin NULL, 1456f4259b30SLisandro Dalcin NULL, 1457f4259b30SLisandro Dalcin /*119*/ NULL, 1458f4259b30SLisandro Dalcin NULL, 1459f4259b30SLisandro Dalcin NULL, 1460f8e07d23SBlanca Mellado Pinto MatMultHermitianTransposeAdd_Shell, 1461f4259b30SLisandro Dalcin NULL, 1462f4259b30SLisandro Dalcin /*124*/ NULL, 1463f4259b30SLisandro Dalcin NULL, 1464f4259b30SLisandro Dalcin NULL, 1465f4259b30SLisandro Dalcin NULL, 1466f4259b30SLisandro Dalcin NULL, 1467f4259b30SLisandro Dalcin /*129*/ NULL, 1468f4259b30SLisandro Dalcin NULL, 1469f4259b30SLisandro Dalcin NULL, 1470f4259b30SLisandro Dalcin NULL, 1471f4259b30SLisandro Dalcin NULL, 1472f4259b30SLisandro Dalcin /*134*/ NULL, 1473f4259b30SLisandro Dalcin NULL, 1474f4259b30SLisandro Dalcin NULL, 1475f4259b30SLisandro Dalcin NULL, 1476f4259b30SLisandro Dalcin NULL, 1477f4259b30SLisandro Dalcin /*139*/ NULL, 1478f4259b30SLisandro Dalcin NULL, 1479d70f29a3SPierre Jolivet NULL, 1480d70f29a3SPierre Jolivet NULL, 1481d70f29a3SPierre Jolivet NULL, 1482d70f29a3SPierre Jolivet /*144*/ NULL, 1483d70f29a3SPierre Jolivet NULL, 1484d70f29a3SPierre Jolivet NULL, 148599a7f59eSMark Adams NULL, 148699a7f59eSMark Adams NULL, 14877fb60732SBarry Smith NULL, 1488dec0b466SHong Zhang /*150*/ NULL, 1489eede4a3fSMark Adams NULL, 1490dec0b466SHong Zhang NULL}; 1491273d9f13SBarry Smith 1492d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx) 1493d71ae5a4SJacob Faibussowitsch { 1494789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1495789d8953SBarry Smith 1496789d8953SBarry Smith PetscFunctionBegin; 1497800f99ffSJeremy L Thompson if (ctx) { 1498800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 1499800f99ffSJeremy L Thompson PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer)); 1500800f99ffSJeremy L Thompson PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 1501800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer)); 1502800f99ffSJeremy L Thompson shell->ctxcontainer = ctxcontainer; 1503800f99ffSJeremy L Thompson PetscCall(PetscContainerDestroy(&ctxcontainer)); 1504800f99ffSJeremy L Thompson } else { 1505800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL)); 1506800f99ffSJeremy L Thompson shell->ctxcontainer = NULL; 1507800f99ffSJeremy L Thompson } 15083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1509800f99ffSJeremy L Thompson } 1510800f99ffSJeremy L Thompson 151166976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *)) 1512d71ae5a4SJacob Faibussowitsch { 1513800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 1514800f99ffSJeremy L Thompson 1515800f99ffSJeremy L Thompson PetscFunctionBegin; 1516800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f)); 15173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1518789d8953SBarry Smith } 1519789d8953SBarry Smith 152086a9fd05SPierre Jolivet PetscErrorCode MatShellSetContext_Immutable(Mat mat, void *ctx) 152186a9fd05SPierre Jolivet { 152286a9fd05SPierre Jolivet PetscFunctionBegin; 152386a9fd05SPierre 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); 152486a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 152586a9fd05SPierre Jolivet } 152686a9fd05SPierre Jolivet 152786a9fd05SPierre Jolivet PetscErrorCode MatShellSetContextDestroy_Immutable(Mat mat, PetscErrorCode (*f)(void *)) 152886a9fd05SPierre Jolivet { 152986a9fd05SPierre Jolivet PetscFunctionBegin; 153086a9fd05SPierre 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); 153186a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 153286a9fd05SPierre Jolivet } 153386a9fd05SPierre Jolivet 153486a9fd05SPierre Jolivet PetscErrorCode MatShellSetManageScalingShifts_Immutable(Mat mat) 153586a9fd05SPierre Jolivet { 153686a9fd05SPierre Jolivet PetscFunctionBegin; 153786a9fd05SPierre 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); 153886a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 153986a9fd05SPierre Jolivet } 154086a9fd05SPierre Jolivet 1541d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype) 1542d71ae5a4SJacob Faibussowitsch { 1543db77db73SJeremy L Thompson PetscFunctionBegin; 15449566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 15459566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype)); 15463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1547db77db73SJeremy L Thompson } 1548db77db73SJeremy L Thompson 154966976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1550d71ae5a4SJacob Faibussowitsch { 1551789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 1552789d8953SBarry Smith 1553789d8953SBarry Smith PetscFunctionBegin; 1554789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1555789d8953SBarry Smith A->ops->diagonalset = NULL; 1556789d8953SBarry Smith A->ops->diagonalscale = NULL; 1557789d8953SBarry Smith A->ops->scale = NULL; 1558789d8953SBarry Smith A->ops->shift = NULL; 1559789d8953SBarry Smith A->ops->axpy = NULL; 15603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1561789d8953SBarry Smith } 1562789d8953SBarry Smith 1563*b9c875b8SPierre Jolivet static PetscErrorCode MatShellGetScalingShifts_Shell(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols) 1564*b9c875b8SPierre Jolivet { 1565*b9c875b8SPierre Jolivet Mat_Shell *shell = (Mat_Shell *)A->data; 1566*b9c875b8SPierre Jolivet 1567*b9c875b8SPierre Jolivet PetscFunctionBegin; 1568*b9c875b8SPierre Jolivet PetscCheck(shell->managescalingshifts, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot get scaling and shifts if MatShellSetManageScalingShifts() has been called"); 1569*b9c875b8SPierre 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()"); 1570*b9c875b8SPierre Jolivet else if (vshift) *vshift = shell->vshift; 1571*b9c875b8SPierre 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()"); 1572*b9c875b8SPierre Jolivet else if (vscale) *vscale = shell->vscale; 1573*b9c875b8SPierre 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()"); 1574*b9c875b8SPierre Jolivet else if (dshift) *dshift = shell->dshift; 1575*b9c875b8SPierre 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()"); 1576*b9c875b8SPierre Jolivet else if (left) *left = shell->left; 1577*b9c875b8SPierre 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()"); 1578*b9c875b8SPierre Jolivet else if (right) *right = shell->right; 1579*b9c875b8SPierre 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()"); 1580*b9c875b8SPierre Jolivet else if (axpy) *axpy = shell->axpy; 1581*b9c875b8SPierre 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()"); 1582*b9c875b8SPierre Jolivet else if (zrows) *zrows = shell->zrows; 1583*b9c875b8SPierre 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()"); 1584*b9c875b8SPierre Jolivet else if (zcols) *zcols = shell->zcols; 1585*b9c875b8SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 1586*b9c875b8SPierre Jolivet } 1587*b9c875b8SPierre Jolivet 1588d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void)) 1589d71ae5a4SJacob Faibussowitsch { 1590feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell *)mat->data; 1591789d8953SBarry Smith 1592789d8953SBarry Smith PetscFunctionBegin; 1593789d8953SBarry Smith switch (op) { 1594d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1595d71ae5a4SJacob Faibussowitsch shell->ops->destroy = (PetscErrorCode(*)(Mat))f; 1596d71ae5a4SJacob Faibussowitsch break; 1597789d8953SBarry Smith case MATOP_VIEW: 1598ad540459SPierre Jolivet if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view; 1599789d8953SBarry Smith mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f; 1600789d8953SBarry Smith break; 1601d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1602d71ae5a4SJacob Faibussowitsch shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f; 1603d71ae5a4SJacob Faibussowitsch break; 1604789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1605789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1606789d8953SBarry Smith case MATOP_SHIFT: 1607789d8953SBarry Smith case MATOP_SCALE: 1608789d8953SBarry Smith case MATOP_AXPY: 1609789d8953SBarry Smith case MATOP_ZERO_ROWS: 1610789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 161128b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1612789d8953SBarry Smith (((void (**)(void))mat->ops)[op]) = f; 1613789d8953SBarry Smith break; 1614789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1615789d8953SBarry Smith if (shell->managescalingshifts) { 1616789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1617789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1618789d8953SBarry Smith } else { 1619789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1620789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1621789d8953SBarry Smith } 1622789d8953SBarry Smith break; 1623789d8953SBarry Smith case MATOP_MULT: 1624789d8953SBarry Smith if (shell->managescalingshifts) { 1625789d8953SBarry Smith shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1626789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1627789d8953SBarry Smith } else { 1628789d8953SBarry Smith shell->ops->mult = NULL; 1629789d8953SBarry Smith mat->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1630789d8953SBarry Smith } 1631789d8953SBarry Smith break; 1632789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1633789d8953SBarry Smith if (shell->managescalingshifts) { 1634789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1635789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1636789d8953SBarry Smith } else { 1637789d8953SBarry Smith shell->ops->multtranspose = NULL; 1638789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1639789d8953SBarry Smith } 1640789d8953SBarry Smith break; 1641f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1642f8e07d23SBlanca Mellado Pinto if (shell->managescalingshifts) { 1643f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1644f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = MatMultHermitianTranspose_Shell; 1645f8e07d23SBlanca Mellado Pinto } else { 1646f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = NULL; 1647f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1648f8e07d23SBlanca Mellado Pinto } 1649f8e07d23SBlanca Mellado Pinto break; 1650d71ae5a4SJacob Faibussowitsch default: 1651d71ae5a4SJacob Faibussowitsch (((void (**)(void))mat->ops)[op]) = f; 1652d71ae5a4SJacob Faibussowitsch break; 1653789d8953SBarry Smith } 16543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1655789d8953SBarry Smith } 1656789d8953SBarry Smith 1657d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void)) 1658d71ae5a4SJacob Faibussowitsch { 1659789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1660789d8953SBarry Smith 1661789d8953SBarry Smith PetscFunctionBegin; 1662789d8953SBarry Smith switch (op) { 1663d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1664d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->destroy; 1665d71ae5a4SJacob Faibussowitsch break; 1666d71ae5a4SJacob Faibussowitsch case MATOP_VIEW: 1667d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))mat->ops->view; 1668d71ae5a4SJacob Faibussowitsch break; 1669d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1670d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->copy; 1671d71ae5a4SJacob Faibussowitsch break; 1672789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1673789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1674789d8953SBarry Smith case MATOP_SHIFT: 1675789d8953SBarry Smith case MATOP_SCALE: 1676789d8953SBarry Smith case MATOP_AXPY: 1677789d8953SBarry Smith case MATOP_ZERO_ROWS: 1678d71ae5a4SJacob Faibussowitsch case MATOP_ZERO_ROWS_COLUMNS: 1679d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1680d71ae5a4SJacob Faibussowitsch break; 1681789d8953SBarry Smith case MATOP_GET_DIAGONAL: 16829371c9d4SSatish Balay if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal; 16839371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1684789d8953SBarry Smith break; 1685789d8953SBarry Smith case MATOP_MULT: 16869371c9d4SSatish Balay if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult; 16879371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1688789d8953SBarry Smith break; 1689789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 16909371c9d4SSatish Balay if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose; 16919371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1692789d8953SBarry Smith break; 1693f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1694f8e07d23SBlanca Mellado Pinto if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose; 1695f8e07d23SBlanca Mellado Pinto else *f = (((void (**)(void))mat->ops)[op]); 1696f8e07d23SBlanca Mellado Pinto break; 1697d71ae5a4SJacob Faibussowitsch default: 1698d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1699789d8953SBarry Smith } 17003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1701789d8953SBarry Smith } 1702789d8953SBarry Smith 17030bad9183SKris Buschelman /*MC 170401c1178eSBarry Smith MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free. 17050bad9183SKris Buschelman 17060bad9183SKris Buschelman Level: advanced 17070bad9183SKris Buschelman 17081cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()` 17090bad9183SKris Buschelman M*/ 17100bad9183SKris Buschelman 1711d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1712d71ae5a4SJacob Faibussowitsch { 1713273d9f13SBarry Smith Mat_Shell *b; 1714273d9f13SBarry Smith 1715273d9f13SBarry Smith PetscFunctionBegin; 17164dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&b)); 1717273d9f13SBarry Smith A->data = (void *)b; 1718aea10558SJacob Faibussowitsch A->ops[0] = MatOps_Values; 1719273d9f13SBarry Smith 1720800f99ffSJeremy L Thompson b->ctxcontainer = NULL; 1721ef66eb69SBarry Smith b->vshift = 0.0; 1722ef66eb69SBarry Smith b->vscale = 1.0; 17230c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1724273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1725210f0121SBarry Smith A->preallocated = PETSC_FALSE; 17262205254eSKarl Rupp 17279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell)); 17289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell)); 1729800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell)); 17309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell)); 17319566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell)); 1732*b9c875b8SPierre Jolivet PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetScalingShifts_C", MatShellGetScalingShifts_Shell)); 17339566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell)); 17349566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell)); 17359566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell)); 17369566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL)); 17373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1738273d9f13SBarry Smith } 1739e51e0e81SBarry Smith 17404b828684SBarry Smith /*@C 174111a5261eSBarry Smith MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined 1742ff756334SLois Curfman McInnes private data storage format. 1743e51e0e81SBarry Smith 1744d083f849SBarry Smith Collective 1745c7fcc2eaSBarry Smith 1746e51e0e81SBarry Smith Input Parameters: 1747c7fcc2eaSBarry Smith + comm - MPI communicator 174845f401ebSJose E. Roman . m - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given) 174945f401ebSJose E. Roman . n - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given) 175045f401ebSJose E. Roman . M - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given) 175145f401ebSJose E. Roman . N - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given) 1752c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1753e51e0e81SBarry Smith 1754ff756334SLois Curfman McInnes Output Parameter: 175544cd7ae7SLois Curfman McInnes . A - the matrix 1756e51e0e81SBarry Smith 1757ff2fd236SBarry Smith Level: advanced 1758ff2fd236SBarry Smith 17592920cce0SJacob Faibussowitsch Example Usage: 176027430b45SBarry Smith .vb 176127430b45SBarry Smith extern PetscErrorCode mult(Mat, Vec, Vec); 17622920cce0SJacob Faibussowitsch 176327430b45SBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &mat); 176427430b45SBarry Smith MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult); 17652920cce0SJacob Faibussowitsch // Use matrix for operations that have been set 176627430b45SBarry Smith MatDestroy(mat); 176727430b45SBarry Smith .ve 1768f39d1f56SLois Curfman McInnes 1769ff756334SLois Curfman McInnes Notes: 1770ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 177111a5261eSBarry Smith with `KSP` (such as, for use with matrix-free methods). You should not 1772ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1773e51e0e81SBarry Smith 1774f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1775f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 17762ef1f0ffSBarry Smith creating a shell matrix, `A`, that supports parallel matrix-vector 177711a5261eSBarry Smith products using `MatMult`(A,x,y) the user should set the number 1778645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1779645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1780645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1781645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1782645985a0SLois Curfman McInnes For example, 1783f39d1f56SLois Curfman McInnes 178427430b45SBarry Smith .vb 178527430b45SBarry Smith Vec x, y 178627430b45SBarry Smith extern PetscErrorCode mult(Mat,Vec,Vec); 178727430b45SBarry Smith Mat A 178827430b45SBarry Smith 178927430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,M,&y); 179027430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,N,&x); 179127430b45SBarry Smith VecGetLocalSize(y,&m); 179227430b45SBarry Smith VecGetLocalSize(x,&n); 179327430b45SBarry Smith MatCreateShell(comm,m,n,M,N,ctx,&A); 179427430b45SBarry Smith MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 179527430b45SBarry Smith MatMult(A,x,y); 179627430b45SBarry Smith MatDestroy(&A); 179727430b45SBarry Smith VecDestroy(&y); 179827430b45SBarry Smith VecDestroy(&x); 179927430b45SBarry Smith .ve 1800e51e0e81SBarry Smith 18012ef1f0ffSBarry Smith `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` 18022ef1f0ffSBarry Smith internally, so these operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called. 18030c0fd78eSBarry Smith 180427430b45SBarry Smith Developer Notes: 18052ef1f0ffSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 18062ef1f0ffSBarry Smith 180795452b02SPatrick Sanan Regarding shifting and scaling. The general form is 18080c0fd78eSBarry Smith 18090c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 18100c0fd78eSBarry Smith 18110c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 18120c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 18130c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 18140c0fd78eSBarry Smith 18150c0fd78eSBarry Smith A is the user provided function. 18160c0fd78eSBarry Smith 181727430b45SBarry Smith `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for 1818c5dec841SPierre Jolivet for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger 181911a5261eSBarry Smith an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat); 182011a5261eSBarry Smith each time the `MATSHELL` matrix has changed. 1821ad2f5c3fSBarry Smith 182211a5261eSBarry Smith Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()` 1823b77ba244SStefano Zampini 182411a5261eSBarry Smith Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided 182511a5261eSBarry Smith with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`. 1826ad2f5c3fSBarry Smith 1827fe59aa6dSJacob Faibussowitsch Fortran Notes: 18282ef1f0ffSBarry Smith To use this from Fortran with a `ctx` you must write an interface definition for this 182911a5261eSBarry Smith function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing 18302ef1f0ffSBarry Smith in as the `ctx` argument. 183111a5261eSBarry Smith 1832fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 1833e51e0e81SBarry Smith @*/ 1834d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A) 1835d71ae5a4SJacob Faibussowitsch { 18363a40ed3dSBarry Smith PetscFunctionBegin; 18379566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, A)); 18389566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A, m, n, M, N)); 18399566063dSJacob Faibussowitsch PetscCall(MatSetType(*A, MATSHELL)); 18409566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A, ctx)); 18419566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 18423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1843c7fcc2eaSBarry Smith } 1844c7fcc2eaSBarry Smith 1845c6866cfdSSatish Balay /*@ 184611a5261eSBarry Smith MatShellSetContext - sets the context for a `MATSHELL` shell matrix 1847c7fcc2eaSBarry Smith 1848c3339decSBarry Smith Logically Collective 1849c7fcc2eaSBarry Smith 1850273d9f13SBarry Smith Input Parameters: 185111a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1852273d9f13SBarry Smith - ctx - the context 1853273d9f13SBarry Smith 1854273d9f13SBarry Smith Level: advanced 1855273d9f13SBarry Smith 1856fe59aa6dSJacob Faibussowitsch Fortran Notes: 185727430b45SBarry Smith You must write a Fortran interface definition for this 18582ef1f0ffSBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument. 1859273d9f13SBarry Smith 18601cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()` 18610bc0a719SBarry Smith @*/ 1862d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx) 1863d71ae5a4SJacob Faibussowitsch { 1864273d9f13SBarry Smith PetscFunctionBegin; 18650700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1866cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx)); 18673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1868e51e0e81SBarry Smith } 1869e51e0e81SBarry Smith 1870fe59aa6dSJacob Faibussowitsch /*@C 187111a5261eSBarry Smith MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context 1872800f99ffSJeremy L Thompson 1873c3339decSBarry Smith Logically Collective 1874800f99ffSJeremy L Thompson 1875800f99ffSJeremy L Thompson Input Parameters: 1876800f99ffSJeremy L Thompson + mat - the shell matrix 1877800f99ffSJeremy L Thompson - f - the context destroy function 1878800f99ffSJeremy L Thompson 187927430b45SBarry Smith Level: advanced 188027430b45SBarry Smith 1881800f99ffSJeremy L Thompson Note: 1882800f99ffSJeremy L Thompson If the `MatShell` is never duplicated, the behavior of this function is equivalent 188311a5261eSBarry Smith to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()` 1884800f99ffSJeremy L Thompson ensures proper reference counting for the user provided context data in the case that 188511a5261eSBarry Smith the `MATSHELL` is duplicated. 1886800f99ffSJeremy L Thompson 18871cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()` 1888800f99ffSJeremy L Thompson @*/ 1889d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *)) 1890d71ae5a4SJacob Faibussowitsch { 1891800f99ffSJeremy L Thompson PetscFunctionBegin; 1892800f99ffSJeremy L Thompson PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1893800f99ffSJeremy L Thompson PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f)); 18943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1895800f99ffSJeremy L Thompson } 1896800f99ffSJeremy L Thompson 1897db77db73SJeremy L Thompson /*@C 18982ef1f0ffSBarry Smith MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()` 1899db77db73SJeremy L Thompson 19002ef1f0ffSBarry Smith Logically Collective 1901db77db73SJeremy L Thompson 1902db77db73SJeremy L Thompson Input Parameters: 190311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1904db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1905db77db73SJeremy L Thompson 1906db77db73SJeremy L Thompson Level: advanced 1907db77db73SJeremy L Thompson 19081cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()` 1909db77db73SJeremy L Thompson @*/ 1910d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype) 1911d71ae5a4SJacob Faibussowitsch { 1912db77db73SJeremy L Thompson PetscFunctionBegin; 1913cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype)); 19143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1915db77db73SJeremy L Thompson } 1916db77db73SJeremy L Thompson 19170c0fd78eSBarry Smith /*@ 191811a5261eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately 191911a5261eSBarry Smith after `MatCreateShell()` 19200c0fd78eSBarry Smith 192127430b45SBarry Smith Logically Collective 19220c0fd78eSBarry Smith 19230c0fd78eSBarry Smith Input Parameter: 1924fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix 19250c0fd78eSBarry Smith 19260c0fd78eSBarry Smith Level: advanced 19270c0fd78eSBarry Smith 19281cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()` 19290c0fd78eSBarry Smith @*/ 1930d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1931d71ae5a4SJacob Faibussowitsch { 19320c0fd78eSBarry Smith PetscFunctionBegin; 19330c0fd78eSBarry Smith PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1934cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A)); 19353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19360c0fd78eSBarry Smith } 19370c0fd78eSBarry Smith 1938*b9c875b8SPierre Jolivet // PetscClangLinter pragma disable: -fdoc-internal-linkage 1939*b9c875b8SPierre Jolivet /*@C 1940*b9c875b8SPierre Jolivet MatShellGetScalingShifts - Gets members of a `MATSHELL` used internally for scaling and 1941*b9c875b8SPierre Jolivet shifting the `Mat` or calling `MatAXPY()`, `MatZeroRows()`, or `MatZeroRowsColumns()` with it 1942*b9c875b8SPierre Jolivet 1943*b9c875b8SPierre Jolivet Logically Collective 1944*b9c875b8SPierre Jolivet 1945*b9c875b8SPierre Jolivet Input Parameter: 1946*b9c875b8SPierre Jolivet . A - the `MATSHELL` shell matrix 1947*b9c875b8SPierre Jolivet 1948*b9c875b8SPierre Jolivet Output Parameters: 1949*b9c875b8SPierre Jolivet + vshift - `PetscScalar` pointer (can be `NULL`), see `MatShift()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be 0 1950*b9c875b8SPierre Jolivet . vscale - `PetscScalar` pointer (can be `NULL`), see `MatScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be 1 1951*b9c875b8SPierre Jolivet . dshift - `Vec` pointer (can be `NULL`), see `MatDiagonalSet()`, or `MAT_SHELL_NOT_ALLOWED` if the internal shift should be `NULL` 1952*b9c875b8SPierre Jolivet . left - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL` 1953*b9c875b8SPierre Jolivet . right - `Vec` pointer (can be `NULL`), see `MatDiagonalScale()`, or `MAT_SHELL_NOT_ALLOWED` if the internal scaling should be `NULL` 1954*b9c875b8SPierre Jolivet . axpy - `Mat` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatAXPY()` should have not been called on `A` 1955*b9c875b8SPierre Jolivet . zrows - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRows()` should have not been called on `A` 1956*b9c875b8SPierre Jolivet - zcols - `Vec` pointer (can be `NULL`), or `MAT_SHELL_NOT_ALLOWED` if `MatZeroRowsColumns()` should have not been called on `A` 1957*b9c875b8SPierre Jolivet 1958*b9c875b8SPierre Jolivet Level: advanced 1959*b9c875b8SPierre Jolivet 1960*b9c875b8SPierre Jolivet Developer Notes: 1961*b9c875b8SPierre Jolivet This is mostly useful to check for corner-cases in `MatType` deriving from 1962*b9c875b8SPierre Jolivet `MATSHELL`, e.g, `MATCOMPOSITE` or `MATVIRTUALTRANSPOSE`, since scaling and 1963*b9c875b8SPierre Jolivet shifts often require extra work which is not always implemented. 1964*b9c875b8SPierre Jolivet 1965*b9c875b8SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShift()`, `MatScale()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatShellSetManageScalingShifts()` 1966*b9c875b8SPierre Jolivet @*/ 1967*b9c875b8SPierre Jolivet PetscErrorCode MatShellGetScalingShifts(Mat A, PetscScalar *vshift, PetscScalar *vscale, Vec *dshift, Vec *left, Vec *right, Mat *axpy, IS *zrows, IS *zcols) 1968*b9c875b8SPierre Jolivet { 1969*b9c875b8SPierre Jolivet PetscFunctionBegin; 1970*b9c875b8SPierre Jolivet PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1971*b9c875b8SPierre Jolivet PetscTryMethod(A, "MatShellGetScalingShifts_C", (Mat, PetscScalar *, PetscScalar *, Vec *, Vec *, Vec *, Mat *, IS *, IS *), (A, vshift, vscale, dshift, left, right, axpy, zrows, zcols)); 1972*b9c875b8SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 1973*b9c875b8SPierre Jolivet } 1974*b9c875b8SPierre Jolivet 1975c16cb8f2SBarry Smith /*@C 197611a5261eSBarry Smith MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function. 1977f3b1f45cSBarry Smith 1978cf53795eSBarry Smith Logically Collective; No Fortran Support 1979f3b1f45cSBarry Smith 1980f3b1f45cSBarry Smith Input Parameters: 198111a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1982f3b1f45cSBarry Smith . f - the function 198311a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1984f3b1f45cSBarry Smith - ctx - an optional context for the function 1985f3b1f45cSBarry Smith 1986f3b1f45cSBarry Smith Output Parameter: 198711a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1988f3b1f45cSBarry Smith 19893c7db156SBarry Smith Options Database Key: 1990f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1991f3b1f45cSBarry Smith 1992f3b1f45cSBarry Smith Level: advanced 1993f3b1f45cSBarry Smith 19941cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()` 1995f3b1f45cSBarry Smith @*/ 1996d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1997d71ae5a4SJacob Faibussowitsch { 1998f3b1f45cSBarry Smith PetscInt m, n; 1999f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 2000f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 200174e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 2002f3b1f45cSBarry Smith 2003f3b1f45cSBarry Smith PetscFunctionBegin; 2004f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 20059566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v)); 20069566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 20079566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf)); 20089566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 20099566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 2010f3b1f45cSBarry Smith 20119566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 20129566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat)); 2013f3b1f45cSBarry Smith 20149566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 20159566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 20169566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 20179566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 2018f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 2019f3b1f45cSBarry Smith flag = PETSC_FALSE; 2020f3b1f45cSBarry Smith if (v) { 202101c1178eSBarry 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))); 20229566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view")); 20239566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view")); 20249566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view")); 2025f3b1f45cSBarry Smith } 2026f3b1f45cSBarry Smith } else if (v) { 202701c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n")); 2028f3b1f45cSBarry Smith } 2029f3b1f45cSBarry Smith if (flg) *flg = flag; 20309566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20319566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20329566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 20339566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2035f3b1f45cSBarry Smith } 2036f3b1f45cSBarry Smith 2037f3b1f45cSBarry Smith /*@C 203811a5261eSBarry Smith MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function. 2039f3b1f45cSBarry Smith 2040cf53795eSBarry Smith Logically Collective; No Fortran Support 2041f3b1f45cSBarry Smith 2042f3b1f45cSBarry Smith Input Parameters: 204311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2044f3b1f45cSBarry Smith . f - the function 204511a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 2046f3b1f45cSBarry Smith - ctx - an optional context for the function 2047f3b1f45cSBarry Smith 2048f3b1f45cSBarry Smith Output Parameter: 204911a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 2050f3b1f45cSBarry Smith 20513c7db156SBarry Smith Options Database Key: 2052f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 2053f3b1f45cSBarry Smith 2054f3b1f45cSBarry Smith Level: advanced 2055f3b1f45cSBarry Smith 20561cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()` 2057f3b1f45cSBarry Smith @*/ 2058d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 2059d71ae5a4SJacob Faibussowitsch { 2060f3b1f45cSBarry Smith Vec x, y, z; 2061f3b1f45cSBarry Smith PetscInt m, n, M, N; 2062f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 2063f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 206474e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 2065f3b1f45cSBarry Smith 2066f3b1f45cSBarry Smith PetscFunctionBegin; 2067f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 20689566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v)); 20699566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &y)); 20709566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &z)); 20719566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 20729566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 20739566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf)); 20749566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 20759566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 20769566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 20779566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf)); 20789566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat)); 2079f3b1f45cSBarry Smith 20809566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 20819566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 20829566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 20839566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 2084f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 2085f3b1f45cSBarry Smith flag = PETSC_FALSE; 2086f3b1f45cSBarry Smith if (v) { 208701c1178eSBarry 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))); 20889566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20899566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20909566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 2091f3b1f45cSBarry Smith } 2092f3b1f45cSBarry Smith } else if (v) { 209301c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n")); 2094f3b1f45cSBarry Smith } 2095f3b1f45cSBarry Smith if (flg) *flg = flag; 20969566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20979566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20989566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20999566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 21009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 21019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 21029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 21033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2104f3b1f45cSBarry Smith } 2105f3b1f45cSBarry Smith 2106f3b1f45cSBarry Smith /*@C 210711a5261eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix. 2108e51e0e81SBarry Smith 2109c3339decSBarry Smith Logically Collective 2110fee21e36SBarry Smith 2111c7fcc2eaSBarry Smith Input Parameters: 211211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2113c7fcc2eaSBarry Smith . op - the name of the operation 2114789d8953SBarry Smith - g - the function that provides the operation. 2115c7fcc2eaSBarry Smith 211615091d37SBarry Smith Level: advanced 211715091d37SBarry Smith 21182920cce0SJacob Faibussowitsch Example Usage: 2119c3339decSBarry Smith .vb 2120c3339decSBarry Smith extern PetscErrorCode usermult(Mat, Vec, Vec); 21212920cce0SJacob Faibussowitsch 2122c3339decSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 2123c3339decSBarry Smith MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult); 2124c3339decSBarry Smith .ve 21250b627109SLois Curfman McInnes 2126a62d957aSLois Curfman McInnes Notes: 2127e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 21281c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2129a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 213011a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2131a62d957aSLois Curfman McInnes 213211a5261eSBarry Smith All user-provided functions (except for `MATOP_DESTROY`) should have the same calling 2133deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2134deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2135deebb3c3SLois Curfman McInnes routines, e.g., 2136a62d957aSLois Curfman McInnes $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2137a62d957aSLois Curfman McInnes 21384aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 21394aa34b0aSBarry Smith nonzero on failure. 21404aa34b0aSBarry Smith 2141a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 214211a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 214311a5261eSBarry Smith set by `MatCreateShell()`. 2144a62d957aSLois Curfman McInnes 21452ef1f0ffSBarry Smith Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) 21462ef1f0ffSBarry Smith use `MatShellSetMatProductOperation()` 2147b77ba244SStefano Zampini 2148fe59aa6dSJacob Faibussowitsch Fortran Notes: 214911a5261eSBarry Smith For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not 2150c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2151501d9185SBarry Smith 21521cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 2153e51e0e81SBarry Smith @*/ 2154d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void)) 2155d71ae5a4SJacob Faibussowitsch { 21563a40ed3dSBarry Smith PetscFunctionBegin; 21570700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2158cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g)); 21593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2160e51e0e81SBarry Smith } 2161f0479e8cSBarry Smith 2162d4bb536fSBarry Smith /*@C 216311a5261eSBarry Smith MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix. 2164d4bb536fSBarry Smith 2165c7fcc2eaSBarry Smith Not Collective 2166c7fcc2eaSBarry Smith 2167d4bb536fSBarry Smith Input Parameters: 216811a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2169c7fcc2eaSBarry Smith - op - the name of the operation 2170d4bb536fSBarry Smith 2171d4bb536fSBarry Smith Output Parameter: 2172789d8953SBarry Smith . g - the function that provides the operation. 2173d4bb536fSBarry Smith 217415091d37SBarry Smith Level: advanced 217515091d37SBarry Smith 217627430b45SBarry Smith Notes: 2177e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2178d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2179d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 218011a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2181d4bb536fSBarry Smith 2182d4bb536fSBarry Smith All user-provided functions have the same calling 2183d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2184d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2185d4bb536fSBarry Smith routines, e.g., 2186d4bb536fSBarry Smith $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2187d4bb536fSBarry Smith 2188d4bb536fSBarry Smith Within each user-defined routine, the user should call 218911a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 219011a5261eSBarry Smith set by `MatCreateShell()`. 2191d4bb536fSBarry Smith 21921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()` 2193d4bb536fSBarry Smith @*/ 2194d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void)) 2195d71ae5a4SJacob Faibussowitsch { 21963a40ed3dSBarry Smith PetscFunctionBegin; 21970700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2198cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g)); 21993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2200d4bb536fSBarry Smith } 2201b77ba244SStefano Zampini 2202b77ba244SStefano Zampini /*@ 220311a5261eSBarry Smith MatIsShell - Inquires if a matrix is derived from `MATSHELL` 2204b77ba244SStefano Zampini 2205b77ba244SStefano Zampini Input Parameter: 2206b77ba244SStefano Zampini . mat - the matrix 2207b77ba244SStefano Zampini 2208b77ba244SStefano Zampini Output Parameter: 2209b77ba244SStefano Zampini . flg - the boolean value 2210b77ba244SStefano Zampini 2211b77ba244SStefano Zampini Level: developer 2212b77ba244SStefano Zampini 2213fe59aa6dSJacob Faibussowitsch Developer Notes: 22142ef1f0ffSBarry Smith In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices 22152ef1f0ffSBarry Smith (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc) 2216b77ba244SStefano Zampini 22171cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` 2218b77ba244SStefano Zampini @*/ 2219d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2220d71ae5a4SJacob Faibussowitsch { 2221b77ba244SStefano Zampini PetscFunctionBegin; 2222b77ba244SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 22234f572ea9SToby Isaac PetscAssertPointer(flg, 2); 2224b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 22253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2226b77ba244SStefano Zampini } 2227