1e51e0e81SBarry Smith /* 220563c6bSBarry Smith This provides a simple shell for Fortran (and C programmers) to 320563c6bSBarry Smith create a very simple matrix class for use with KSP without coding 4ed3cc1f0SBarry Smith much of anything. 5e51e0e81SBarry Smith */ 6e51e0e81SBarry Smith 786a9fd05SPierre Jolivet #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/ 80c0fd78eSBarry Smith 945960306SStefano Zampini /* 1045960306SStefano Zampini Store and scale values on zeroed rows 1145960306SStefano Zampini xx = [x_1, 0], 0 on zeroed columns 1245960306SStefano Zampini */ 13d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx) 14d71ae5a4SJacob Faibussowitsch { 1545960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1645960306SStefano Zampini 1745960306SStefano Zampini PetscFunctionBegin; 1845960306SStefano Zampini *xx = x; 1945960306SStefano Zampini if (shell->zrows) { 209566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 219566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 229566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 239566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 2445960306SStefano Zampini } 2545960306SStefano Zampini if (shell->zcols) { 2648a46eb9SPierre Jolivet if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 279566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->right_work)); 289566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0)); 2945960306SStefano Zampini *xx = shell->right_work; 3045960306SStefano Zampini } 313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3245960306SStefano Zampini } 3345960306SStefano Zampini 3445960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 35d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x) 36d71ae5a4SJacob Faibussowitsch { 3745960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 3845960306SStefano Zampini 3945960306SStefano Zampini PetscFunctionBegin; 4045960306SStefano Zampini if (shell->zrows) { 419566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 429566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 4345960306SStefano Zampini } 443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4545960306SStefano Zampini } 4645960306SStefano Zampini 4745960306SStefano Zampini /* 4845960306SStefano Zampini Store and scale values on zeroed rows 4945960306SStefano Zampini xx = [x_1, 0], 0 on zeroed rows 5045960306SStefano Zampini */ 51d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx) 52d71ae5a4SJacob Faibussowitsch { 5345960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 5445960306SStefano Zampini 5545960306SStefano Zampini PetscFunctionBegin; 5645960306SStefano Zampini *xx = NULL; 5745960306SStefano Zampini if (!shell->zrows) { 5845960306SStefano Zampini *xx = x; 5945960306SStefano Zampini } else { 6048a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 619566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->left_work)); 629566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 639566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 649566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 659566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 669566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 679566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 6845960306SStefano Zampini *xx = shell->left_work; 6945960306SStefano Zampini } 703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7145960306SStefano Zampini } 7245960306SStefano Zampini 7345960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 74d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x) 75d71ae5a4SJacob Faibussowitsch { 7645960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 7745960306SStefano Zampini 7845960306SStefano Zampini PetscFunctionBegin; 791baa6e33SBarry Smith if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0)); 8045960306SStefano Zampini if (shell->zrows) { 819566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 829566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 8345960306SStefano Zampini } 843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8545960306SStefano Zampini } 8645960306SStefano Zampini 878fe8eb27SJed Brown /* 880c0fd78eSBarry Smith xx = diag(left)*x 898fe8eb27SJed Brown */ 90f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx, PetscBool conjugate) 91d71ae5a4SJacob Faibussowitsch { 928fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 938fe8eb27SJed Brown 948fe8eb27SJed Brown PetscFunctionBegin; 950298fd71SBarry Smith *xx = NULL; 968fe8eb27SJed Brown if (!shell->left) { 978fe8eb27SJed Brown *xx = x; 988fe8eb27SJed Brown } else { 999566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work)); 100f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 101f8e07d23SBlanca Mellado Pinto PetscInt i, m; 102f8e07d23SBlanca Mellado Pinto const PetscScalar *d, *xarray; 103f8e07d23SBlanca Mellado Pinto PetscScalar *w; 104f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 105f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->left, &d)); 106f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(x, &xarray)); 107f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayWrite(shell->left_work, &w)); 108f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) w[i] = PetscConj(d[i]) * xarray[i]; 109f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 110f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(x, &xarray)); 111f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayWrite(shell->left_work, &w)); 112f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(shell->left_work, x, shell->left)); 1138fe8eb27SJed Brown *xx = shell->left_work; 1148fe8eb27SJed Brown } 1153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1168fe8eb27SJed Brown } 1178fe8eb27SJed Brown 1180c0fd78eSBarry Smith /* 1190c0fd78eSBarry Smith xx = diag(right)*x 1200c0fd78eSBarry Smith */ 121d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx) 122d71ae5a4SJacob Faibussowitsch { 1238fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1248fe8eb27SJed Brown 1258fe8eb27SJed Brown PetscFunctionBegin; 1260298fd71SBarry Smith *xx = NULL; 1278fe8eb27SJed Brown if (!shell->right) { 1288fe8eb27SJed Brown *xx = x; 1298fe8eb27SJed Brown } else { 1309566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work)); 1319566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, x, shell->right)); 1328fe8eb27SJed Brown *xx = shell->right_work; 1338fe8eb27SJed Brown } 1343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1358fe8eb27SJed Brown } 1368fe8eb27SJed Brown 1370c0fd78eSBarry Smith /* 1380c0fd78eSBarry Smith x = diag(left)*x 1390c0fd78eSBarry Smith */ 140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x) 141d71ae5a4SJacob Faibussowitsch { 1428fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1438fe8eb27SJed Brown 1448fe8eb27SJed Brown PetscFunctionBegin; 1459566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left)); 1463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1478fe8eb27SJed Brown } 1488fe8eb27SJed Brown 1490c0fd78eSBarry Smith /* 1500c0fd78eSBarry Smith x = diag(right)*x 1510c0fd78eSBarry Smith */ 152f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x, PetscBool conjugate) 153d71ae5a4SJacob Faibussowitsch { 1548fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1558fe8eb27SJed Brown 1568fe8eb27SJed Brown PetscFunctionBegin; 157f8e07d23SBlanca Mellado Pinto if (shell->right) { 158f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 159f8e07d23SBlanca Mellado Pinto PetscInt i, m; 160f8e07d23SBlanca Mellado Pinto const PetscScalar *d; 161f8e07d23SBlanca Mellado Pinto PetscScalar *xarray; 162f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 163f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->right, &d)); 164f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArray(x, &xarray)); 165f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) xarray[i] = PetscConj(d[i]) * xarray[i]; 166f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 167f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArray(x, &xarray)); 168f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(x, x, shell->right)); 169f8e07d23SBlanca Mellado Pinto } 1703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1718fe8eb27SJed Brown } 1728fe8eb27SJed Brown 1730c0fd78eSBarry Smith /* 1740c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 1750c0fd78eSBarry Smith 1760c0fd78eSBarry Smith On input Y already contains A*x 177f8e07d23SBlanca Mellado Pinto 178f8e07d23SBlanca Mellado Pinto If conjugate=PETSC_TRUE then vscale, dshift, and vshift are conjugated 1790c0fd78eSBarry Smith */ 180f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y, PetscBool conjugate) 181d71ae5a4SJacob Faibussowitsch { 1828fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 183f8e07d23SBlanca Mellado Pinto PetscScalar vscale = conjugate ? PetscConj(shell->vscale) : shell->vscale; 184f8e07d23SBlanca Mellado Pinto PetscScalar vshift = conjugate ? PetscConj(shell->vshift) : shell->vshift; 1858fe8eb27SJed Brown 1868fe8eb27SJed Brown PetscFunctionBegin; 1878fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 1888fe8eb27SJed Brown PetscInt i, m; 1898fe8eb27SJed Brown const PetscScalar *x, *d; 1908fe8eb27SJed Brown PetscScalar *y; 1919566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &m)); 1929566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift, &d)); 1939566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 1949566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y, &y)); 195f8e07d23SBlanca Mellado Pinto if (conjugate) 196f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + PetscConj(d[i]) * x[i]; 197f8e07d23SBlanca Mellado Pinto else 198f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + d[i] * x[i]; 1999566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 2009566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 2019566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y, &y)); 2020c0fd78eSBarry Smith } else { 203f8e07d23SBlanca Mellado Pinto PetscCall(VecScale(Y, vscale)); 2048fe8eb27SJed Brown } 205f8e07d23SBlanca Mellado Pinto if (vshift != 0.0) PetscCall(VecAXPY(Y, vshift, X)); /* if test is for non-square matrices */ 2063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2078fe8eb27SJed Brown } 208e51e0e81SBarry Smith 209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx) 210d71ae5a4SJacob Faibussowitsch { 211800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 212800f99ffSJeremy L Thompson 213789d8953SBarry Smith PetscFunctionBegin; 214800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx)); 215800f99ffSJeremy L Thompson else *(void **)ctx = NULL; 2163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 217789d8953SBarry Smith } 218789d8953SBarry Smith 2199d225801SJed Brown /*@ 22011a5261eSBarry Smith MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix. 221b4fd4287SBarry Smith 222c7fcc2eaSBarry Smith Not Collective 223c7fcc2eaSBarry Smith 224b4fd4287SBarry Smith Input Parameter: 22511a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()` 226b4fd4287SBarry Smith 227b4fd4287SBarry Smith Output Parameter: 228b4fd4287SBarry Smith . ctx - the user provided context 229b4fd4287SBarry Smith 23015091d37SBarry Smith Level: advanced 23115091d37SBarry Smith 232fe59aa6dSJacob Faibussowitsch Fortran Notes: 23327430b45SBarry Smith You must write a Fortran interface definition for this 234daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 235a62d957aSLois Curfman McInnes 2361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()` 2370bc0a719SBarry Smith @*/ 238d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx) 239d71ae5a4SJacob Faibussowitsch { 2403a40ed3dSBarry Smith PetscFunctionBegin; 2410700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2424f572ea9SToby Isaac PetscAssertPointer(ctx, 2); 243cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx)); 2443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 245b4fd4287SBarry Smith } 246b4fd4287SBarry Smith 247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc) 248d71ae5a4SJacob Faibussowitsch { 24945960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 25045960306SStefano Zampini Vec x = NULL, b = NULL; 25145960306SStefano Zampini IS is1, is2; 25245960306SStefano Zampini const PetscInt *ridxs; 25345960306SStefano Zampini PetscInt *idxs, *gidxs; 25445960306SStefano Zampini PetscInt cum, rst, cst, i; 25545960306SStefano Zampini 25645960306SStefano Zampini PetscFunctionBegin; 25748a46eb9SPierre Jolivet if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals)); 25848a46eb9SPierre Jolivet if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w)); 2599566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &rst, NULL)); 2609566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL)); 26145960306SStefano Zampini 26245960306SStefano Zampini /* Expand/create index set of zeroed rows */ 2639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &idxs)); 26445960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 265bd72c1ddSStefano Zampini PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nr, idxs, PETSC_OWN_POINTER, &is1)); 2669566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 2679566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals, is1, diag)); 26845960306SStefano Zampini if (shell->zrows) { 2699566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows, is1, &is2)); 2709566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 2719566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 27245960306SStefano Zampini shell->zrows = is2; 27345960306SStefano Zampini } else shell->zrows = is1; 27445960306SStefano Zampini 27545960306SStefano Zampini /* Create scatters for diagonal values communications */ 2769566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 2779566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 27845960306SStefano Zampini 27945960306SStefano Zampini /* row scatter: from/to left vector */ 2809566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &b)); 2819566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r)); 28245960306SStefano Zampini 28345960306SStefano Zampini /* col scatter: from right vector to left vector */ 2849566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows, &ridxs)); 2859566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows, &nr)); 2869566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &gidxs)); 28745960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 28845960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 28945960306SStefano Zampini gidxs[cum] = ridxs[i]; 29045960306SStefano Zampini cum++; 29145960306SStefano Zampini } 2929566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1)); 2939566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c)); 2949566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 2959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 2969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 29745960306SStefano Zampini 29845960306SStefano Zampini /* Expand/create index set of zeroed columns */ 29945960306SStefano Zampini if (rc) { 3009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &idxs)); 30145960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 302bd72c1ddSStefano Zampini PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nc, idxs, PETSC_OWN_POINTER, &is1)); 3039566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 30445960306SStefano Zampini if (shell->zcols) { 3059566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols, is1, &is2)); 3069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 30845960306SStefano Zampini shell->zcols = is2; 30945960306SStefano Zampini } else shell->zcols = is1; 31045960306SStefano Zampini } 3113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 31245960306SStefano Zampini } 31345960306SStefano Zampini 314d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 315d71ae5a4SJacob Faibussowitsch { 316ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 31745960306SStefano Zampini PetscInt nr, *lrows; 31845960306SStefano Zampini 31945960306SStefano Zampini PetscFunctionBegin; 32045960306SStefano Zampini if (x && b) { 32145960306SStefano Zampini Vec xt; 32245960306SStefano Zampini PetscScalar *vals; 32345960306SStefano Zampini PetscInt *gcols, i, st, nl, nc; 32445960306SStefano Zampini 3259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &gcols)); 3269371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3279371c9d4SSatish Balay if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 32845960306SStefano Zampini 3299566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, NULL)); 3309566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc, &vals)); 3329566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3339566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3349566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3359566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3369566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */ 33745960306SStefano Zampini 3389566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3399566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3409566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 34145960306SStefano Zampini for (i = 0; i < nl; i++) { 34245960306SStefano Zampini PetscInt g = i + st; 34345960306SStefano Zampini if (g > mat->rmap->N) continue; 34445960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 3459566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES)); 34645960306SStefano Zampini } 3479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 3489566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 3499566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 3509566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 3519566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 35245960306SStefano Zampini } 3539566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL)); 3549566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE)); 3551baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL)); 3569566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 3573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35845960306SStefano Zampini } 35945960306SStefano Zampini 360d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b) 361d71ae5a4SJacob Faibussowitsch { 362ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 36345960306SStefano Zampini PetscInt *lrows, *lcols; 36445960306SStefano Zampini PetscInt nr, nc; 36545960306SStefano Zampini PetscBool congruent; 36645960306SStefano Zampini 36745960306SStefano Zampini PetscFunctionBegin; 36845960306SStefano Zampini if (x && b) { 36945960306SStefano Zampini Vec xt, bt; 37045960306SStefano Zampini PetscScalar *vals; 37145960306SStefano Zampini PetscInt *grows, *gcols, i, st, nl; 37245960306SStefano Zampini 3739566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &grows, n, &gcols)); 3749371c9d4SSatish Balay for (i = 0, nr = 0; i < n; i++) 3759371c9d4SSatish Balay if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 3769371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3779371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 3789566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n, &vals)); 37945960306SStefano Zampini 3809566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, &bt)); 3819566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3829566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3839566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3849566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3859566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt, -1.0, x)); /* xt = [0, -x2] */ 3869566063dSJacob Faibussowitsch PetscCall(MatMult(mat, xt, bt)); /* bt = [-A12*x2,-A22*x2] */ 3879566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */ 3889566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 3899566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 3909566063dSJacob Faibussowitsch PetscCall(VecAXPY(b, 1.0, bt)); /* b = [b1 - A12*x2, b2] */ 3919566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 3929566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 3939566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 3949566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 39545960306SStefano Zampini 3969566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3979566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3989566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 39945960306SStefano Zampini for (i = 0; i < nl; i++) { 40045960306SStefano Zampini PetscInt g = i + st; 40145960306SStefano Zampini if (g > mat->rmap->N) continue; 40245960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4039566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES)); 40445960306SStefano Zampini } 4059566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4069566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4079566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4109566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows, gcols)); 41145960306SStefano Zampini } 4129566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL)); 4139566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat, &congruent)); 41445960306SStefano Zampini if (congruent) { 41545960306SStefano Zampini nc = nr; 41645960306SStefano Zampini lcols = lrows; 41745960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 41845960306SStefano Zampini PetscInt i, nt, *t; 41945960306SStefano Zampini 4209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &t)); 4219371c9d4SSatish Balay for (i = 0, nt = 0; i < n; i++) 4229371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4239566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL)); 4249566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 42545960306SStefano Zampini } 4269566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE)); 42748a46eb9SPierre Jolivet if (!congruent) PetscCall(PetscFree(lcols)); 4289566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4291baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL)); 4303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43145960306SStefano Zampini } 43245960306SStefano Zampini 433d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat) 434d71ae5a4SJacob Faibussowitsch { 435bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell *)mat->data; 436b77ba244SStefano Zampini MatShellMatFunctionList matmat; 437ed3cc1f0SBarry Smith 4383a40ed3dSBarry Smith PetscFunctionBegin; 4391baa6e33SBarry Smith if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat)); 4409566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps))); 4419566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4429566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4439566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 4449566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 4459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 4469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 4479566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 4489566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 4499566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 4509566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 4519566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 4529566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 4539566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 4549566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 4559566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 4569566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 457b77ba244SStefano Zampini 458b77ba244SStefano Zampini matmat = shell->matmat; 459b77ba244SStefano Zampini while (matmat) { 460b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 461b77ba244SStefano Zampini 4629566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL)); 4639566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 4649566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 4659566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 466b77ba244SStefano Zampini matmat = next; 467b77ba244SStefano Zampini } 468800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(mat, NULL)); 4699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL)); 4709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 471800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL)); 4729566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL)); 4739566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL)); 4749566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL)); 4759566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL)); 4769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL)); 4779566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 4783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 479b77ba244SStefano Zampini } 480b77ba244SStefano Zampini 481b77ba244SStefano Zampini typedef struct { 482b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 483b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 484b77ba244SStefano Zampini void *userdata; 485b77ba244SStefano Zampini Mat B; 486b77ba244SStefano Zampini Mat Bt; 487b77ba244SStefano Zampini Mat axpy; 488b77ba244SStefano Zampini } MatMatDataShell; 489b77ba244SStefano Zampini 490d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data) 491d71ae5a4SJacob Faibussowitsch { 492b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 493b77ba244SStefano Zampini 494b77ba244SStefano Zampini PetscFunctionBegin; 4951baa6e33SBarry Smith if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata)); 4969566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 4979566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 4989566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 4999566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 5003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 501b77ba244SStefano Zampini } 502b77ba244SStefano Zampini 503d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 504d71ae5a4SJacob Faibussowitsch { 505b77ba244SStefano Zampini Mat_Product *product; 506b77ba244SStefano Zampini Mat A, B; 507b77ba244SStefano Zampini MatMatDataShell *mdata; 508b77ba244SStefano Zampini PetscScalar zero = 0.0; 509b77ba244SStefano Zampini 510b77ba244SStefano Zampini PetscFunctionBegin; 511b77ba244SStefano Zampini MatCheckProduct(D, 1); 512b77ba244SStefano Zampini product = D->product; 51328b400f6SJacob Faibussowitsch PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty"); 514b77ba244SStefano Zampini A = product->A; 515b77ba244SStefano Zampini B = product->B; 516b77ba244SStefano Zampini mdata = (MatMatDataShell *)product->data; 517b77ba244SStefano Zampini if (mdata->numeric) { 518b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 519b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 520b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 521b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 522b77ba244SStefano Zampini 523b77ba244SStefano Zampini if (shell->managescalingshifts) { 52408401ef6SPierre Jolivet PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns"); 525b77ba244SStefano Zampini if (shell->right || shell->left) { 526b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 527b77ba244SStefano Zampini if (!mdata->B) { 5289566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B)); 529b77ba244SStefano Zampini } else { 530b77ba244SStefano Zampini newB = PETSC_FALSE; 531b77ba244SStefano Zampini } 5329566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN)); 533b77ba244SStefano Zampini } 534b77ba244SStefano Zampini switch (product->type) { 535b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 5361baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 537b77ba244SStefano Zampini break; 538b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 5391baa6e33SBarry Smith if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL)); 540b77ba244SStefano Zampini break; 541b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 5421baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 543b77ba244SStefano Zampini break; 544b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 545b77ba244SStefano Zampini if (shell->right && shell->left) { 546b77ba244SStefano Zampini PetscBool flg; 547b77ba244SStefano Zampini 5489566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5499371c9d4SSatish Balay PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name, 5509371c9d4SSatish Balay ((PetscObject)B)->type_name); 551b77ba244SStefano Zampini } 5521baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 553b77ba244SStefano Zampini break; 554b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 555b77ba244SStefano Zampini if (shell->right && shell->left) { 556b77ba244SStefano Zampini PetscBool flg; 557b77ba244SStefano Zampini 5589566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5599371c9d4SSatish Balay PetscCheck(flg, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices because left scaling != from right scaling", MatProductTypes[product->type], ((PetscObject)A)->type_name, 5609371c9d4SSatish Balay ((PetscObject)B)->type_name); 561b77ba244SStefano Zampini } 5621baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 563b77ba244SStefano Zampini break; 564d71ae5a4SJacob Faibussowitsch default: 565d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 566b77ba244SStefano Zampini } 567b77ba244SStefano Zampini } 568b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 569b77ba244SStefano Zampini D->product = NULL; 570b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 571b77ba244SStefano Zampini D->ops->productnumeric = NULL; 572b77ba244SStefano Zampini 5739566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata)); 574b77ba244SStefano Zampini 575b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 5769566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 577b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 578b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 579b77ba244SStefano Zampini D->product = product; 580b77ba244SStefano Zampini 581b77ba244SStefano Zampini if (shell->managescalingshifts) { 5829566063dSJacob Faibussowitsch PetscCall(MatScale(D, shell->vscale)); 583b77ba244SStefano Zampini switch (product->type) { 584b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 585b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 586b77ba244SStefano Zampini if (shell->left) { 5879566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->left, NULL)); 588b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 5899566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 590b77ba244SStefano Zampini if (shell->dshift) { 5919566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->left_work)); 5929566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work, shell->vshift)); 5939566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left)); 594b77ba244SStefano Zampini } else { 5959566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work, shell->vshift)); 596b77ba244SStefano Zampini } 597b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 598b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 599b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 600b77ba244SStefano Zampini 6019566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt)); 6029566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL)); 6039566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->Bt, str)); 604b77ba244SStefano Zampini } else { 605b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 606b77ba244SStefano Zampini 6079566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL)); 6089566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 609b77ba244SStefano Zampini } 610b77ba244SStefano Zampini } 611b77ba244SStefano Zampini } 612b77ba244SStefano Zampini break; 613b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 614b77ba244SStefano Zampini if (shell->right) { 6159566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->right, NULL)); 616b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 617b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 618b77ba244SStefano Zampini 6199566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 620b77ba244SStefano Zampini if (shell->dshift) { 6219566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->right_work)); 6229566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work, shell->vshift)); 6239566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right)); 624b77ba244SStefano Zampini } else { 6259566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work, shell->vshift)); 626b77ba244SStefano Zampini } 6279566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL)); 6289566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 629b77ba244SStefano Zampini } 630b77ba244SStefano Zampini } 631b77ba244SStefano Zampini break; 632b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 633b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6349371c9d4SSatish Balay PetscCheck(!shell->dshift && shell->vshift == zero, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices with diagonal shift", MatProductTypes[product->type], ((PetscObject)A)->type_name, 6359371c9d4SSatish Balay ((PetscObject)B)->type_name); 636b77ba244SStefano Zampini break; 637d71ae5a4SJacob Faibussowitsch default: 638d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 639b77ba244SStefano Zampini } 640b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 641b77ba244SStefano Zampini Mat X; 642b77ba244SStefano Zampini PetscObjectState axpy_state; 643b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 644b77ba244SStefano Zampini 6459566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 6469566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 64708401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 648b77ba244SStefano Zampini if (!mdata->axpy) { 649b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6509566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy)); 6519566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy, product->type)); 6529566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6539566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 654b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 655b77ba244SStefano Zampini PetscBool flg; 656b77ba244SStefano Zampini 6579566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy)); 6589566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg)); 659b77ba244SStefano Zampini if (!flg) { 660b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6619566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6629566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 663b77ba244SStefano Zampini } 664b77ba244SStefano Zampini } 6659566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 6669566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str)); 667b77ba244SStefano Zampini } 668b77ba244SStefano Zampini } 669b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation"); 6703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 671b77ba244SStefano Zampini } 672b77ba244SStefano Zampini 673d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 674d71ae5a4SJacob Faibussowitsch { 675b77ba244SStefano Zampini Mat_Product *product; 676b77ba244SStefano Zampini Mat A, B; 677b77ba244SStefano Zampini MatShellMatFunctionList matmat; 678b77ba244SStefano Zampini Mat_Shell *shell; 679eae3dc7dSJacob Faibussowitsch PetscBool flg = PETSC_FALSE; 680b77ba244SStefano Zampini char composedname[256]; 681b77ba244SStefano Zampini MatMatDataShell *mdata; 682b77ba244SStefano Zampini 683b77ba244SStefano Zampini PetscFunctionBegin; 684b77ba244SStefano Zampini MatCheckProduct(D, 1); 685b77ba244SStefano Zampini product = D->product; 68628b400f6SJacob Faibussowitsch PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty"); 687b77ba244SStefano Zampini A = product->A; 688b77ba244SStefano Zampini B = product->B; 689b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 690b77ba244SStefano Zampini matmat = shell->matmat; 6919566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 692b77ba244SStefano Zampini while (matmat) { 6939566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 694b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 695b77ba244SStefano Zampini if (flg) break; 696b77ba244SStefano Zampini matmat = matmat->next; 697b77ba244SStefano Zampini } 69828b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]); 699b77ba244SStefano Zampini switch (product->type) { 700d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AB: 701d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); 702d71ae5a4SJacob Faibussowitsch break; 703d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AtB: 704d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); 705d71ae5a4SJacob Faibussowitsch break; 706d71ae5a4SJacob Faibussowitsch case MATPRODUCT_ABt: 707d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N)); 708d71ae5a4SJacob Faibussowitsch break; 709d71ae5a4SJacob Faibussowitsch case MATPRODUCT_RARt: 710d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N)); 711d71ae5a4SJacob Faibussowitsch break; 712d71ae5a4SJacob Faibussowitsch case MATPRODUCT_PtAP: 713d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N)); 714d71ae5a4SJacob Faibussowitsch break; 715d71ae5a4SJacob Faibussowitsch default: 716d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 717b77ba244SStefano Zampini } 718b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 719b77ba244SStefano Zampini if (matmat->resultname) { 7209566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg)); 72148a46eb9SPierre Jolivet if (!flg) PetscCall(MatSetType(D, matmat->resultname)); 722b77ba244SStefano Zampini } 723b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 724b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 725b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 726b77ba244SStefano Zampini /* attach product data */ 7279566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 728b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 729b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 730b77ba244SStefano Zampini if (matmat->symbolic) { 7319566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata)); 732b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7339566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 734b77ba244SStefano Zampini } 73528b400f6SJacob Faibussowitsch PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase"); 73628b400f6SJacob Faibussowitsch PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase"); 737b77ba244SStefano Zampini D->product->data = mdata; 738b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 739b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 740b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 741b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 7423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 743b77ba244SStefano Zampini } 744b77ba244SStefano Zampini 745d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 746d71ae5a4SJacob Faibussowitsch { 747b77ba244SStefano Zampini Mat_Product *product; 748b77ba244SStefano Zampini Mat A, B; 749b77ba244SStefano Zampini MatShellMatFunctionList matmat; 750b77ba244SStefano Zampini Mat_Shell *shell; 751b77ba244SStefano Zampini PetscBool flg; 752b77ba244SStefano Zampini char composedname[256]; 753b77ba244SStefano Zampini 754b77ba244SStefano Zampini PetscFunctionBegin; 755b77ba244SStefano Zampini MatCheckProduct(D, 1); 756b77ba244SStefano Zampini product = D->product; 757b77ba244SStefano Zampini A = product->A; 758b77ba244SStefano Zampini B = product->B; 7599566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 7603ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 761b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 762b77ba244SStefano Zampini matmat = shell->matmat; 7639566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 764b77ba244SStefano Zampini while (matmat) { 7659566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 766b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 767b77ba244SStefano Zampini if (flg) break; 768b77ba244SStefano Zampini matmat = matmat->next; 769b77ba244SStefano Zampini } 7709371c9d4SSatish Balay if (flg) { 7719371c9d4SSatish Balay D->ops->productsymbolic = MatProductSymbolic_Shell_X; 7729371c9d4SSatish Balay } else PetscCall(PetscInfo(D, " symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type])); 7733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 774b77ba244SStefano Zampini } 775b77ba244SStefano Zampini 776d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Private(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), char *composedname, const char *resultname) 777d71ae5a4SJacob Faibussowitsch { 778b77ba244SStefano Zampini PetscBool flg; 779b77ba244SStefano Zampini Mat_Shell *shell; 780b77ba244SStefano Zampini MatShellMatFunctionList matmat; 781b77ba244SStefano Zampini 782b77ba244SStefano Zampini PetscFunctionBegin; 78328b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine"); 78428b400f6SJacob Faibussowitsch PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name"); 785b77ba244SStefano Zampini 786b77ba244SStefano Zampini /* add product callback */ 787b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 788b77ba244SStefano Zampini matmat = shell->matmat; 789b77ba244SStefano Zampini if (!matmat) { 7909566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 791b77ba244SStefano Zampini matmat = shell->matmat; 792b77ba244SStefano Zampini } else { 793b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 794b77ba244SStefano Zampini while (entry) { 7959566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, entry->composedname, &flg)); 796b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 797b77ba244SStefano Zampini matmat = entry; 7982e956fe4SStefano Zampini if (flg) goto set; 799b77ba244SStefano Zampini entry = entry->next; 800b77ba244SStefano Zampini } 8019566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 802b77ba244SStefano Zampini matmat = matmat->next; 803b77ba244SStefano Zampini } 804b77ba244SStefano Zampini 805843d480fSStefano Zampini set: 806b77ba244SStefano Zampini matmat->symbolic = symbolic; 807b77ba244SStefano Zampini matmat->numeric = numeric; 808b77ba244SStefano Zampini matmat->destroy = destroy; 809b77ba244SStefano Zampini matmat->ptype = ptype; 8109566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8119566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8129566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname, &matmat->composedname)); 8139566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname, &matmat->resultname)); 8149566063dSJacob Faibussowitsch PetscCall(PetscInfo(A, "Composing %s for product type %s with result %s\n", matmat->composedname, MatProductTypes[matmat->ptype], matmat->resultname ? matmat->resultname : "not specified")); 8159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X)); 8163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 817b77ba244SStefano Zampini } 818b77ba244SStefano Zampini 819b77ba244SStefano Zampini /*@C 82011a5261eSBarry Smith MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix. 821b77ba244SStefano Zampini 82227430b45SBarry Smith Logically Collective; No Fortran Support 823b77ba244SStefano Zampini 824b77ba244SStefano Zampini Input Parameters: 82511a5261eSBarry Smith + A - the `MATSHELL` shell matrix 826b77ba244SStefano Zampini . ptype - the product type 8272ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`) 828b77ba244SStefano Zampini . numeric - the function for the numerical phase 8292ef1f0ffSBarry Smith . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`) 830b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 8312ef1f0ffSBarry Smith - Ctype - the matrix type for the result (can be `NULL`) 832b77ba244SStefano Zampini 833b77ba244SStefano Zampini Level: advanced 834b77ba244SStefano Zampini 8352920cce0SJacob Faibussowitsch Example Usage: 836cf53795eSBarry Smith .vb 837cf53795eSBarry Smith extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**); 838cf53795eSBarry Smith extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*); 839cf53795eSBarry Smith extern PetscErrorCode userdestroy(void*); 8402920cce0SJacob Faibussowitsch 841cf53795eSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 8422920cce0SJacob Faibussowitsch MatShellSetMatProductOperation( 8432920cce0SJacob Faibussowitsch A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE 8442920cce0SJacob Faibussowitsch ); 8452920cce0SJacob Faibussowitsch // create B of type SEQAIJ etc.. 8462920cce0SJacob Faibussowitsch MatProductCreate(A, B, PETSC_NULLPTR, &C); 847cf53795eSBarry Smith MatProductSetType(C, MATPRODUCT_AB); 848cf53795eSBarry Smith MatProductSetFromOptions(C); 8492920cce0SJacob Faibussowitsch MatProductSymbolic(C); // actually runs the user defined symbolic operation 8502920cce0SJacob Faibussowitsch MatProductNumeric(C); // actually runs the user defined numeric operation 8512920cce0SJacob Faibussowitsch // use C = A * B 852cf53795eSBarry Smith .ve 853b77ba244SStefano Zampini 854b77ba244SStefano Zampini Notes: 855cf53795eSBarry Smith `MATPRODUCT_ABC` is not supported yet. 85611a5261eSBarry Smith 8572ef1f0ffSBarry Smith If the symbolic phase is not specified, `MatSetUp()` is called on the result matrix that must have its type set if Ctype is `NULL`. 85811a5261eSBarry Smith 859b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 860b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 861b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 86227430b45SBarry Smith The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence. 863b77ba244SStefano Zampini 8641cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()` 865b77ba244SStefano Zampini @*/ 866d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetMatProductOperation(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype) 867d71ae5a4SJacob Faibussowitsch { 868b77ba244SStefano Zampini PetscFunctionBegin; 869b77ba244SStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 870b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A, ptype, 2); 87108401ef6SPierre Jolivet PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]); 87228b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4"); 8734f572ea9SToby Isaac PetscAssertPointer(Btype, 6); 8744f572ea9SToby Isaac if (Ctype) PetscAssertPointer(Ctype, 7); 875cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetMatProductOperation_C", (Mat, MatProductType, PetscErrorCode(*)(Mat, Mat, Mat, void **), PetscErrorCode(*)(Mat, Mat, Mat, void *), PetscErrorCode(*)(void *), MatType, MatType), (A, ptype, symbolic, numeric, destroy, Btype, Ctype)); 8763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 877b77ba244SStefano Zampini } 878b77ba244SStefano Zampini 879d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetMatProductOperation_Shell(Mat A, MatProductType ptype, PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **), PetscErrorCode (*numeric)(Mat, Mat, Mat, void *), PetscErrorCode (*destroy)(void *), MatType Btype, MatType Ctype) 880d71ae5a4SJacob Faibussowitsch { 881b77ba244SStefano Zampini PetscBool flg; 882b77ba244SStefano Zampini char composedname[256]; 883b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 884b77ba244SStefano Zampini PetscMPIInt size; 885b77ba244SStefano Zampini 886b77ba244SStefano Zampini PetscFunctionBegin; 887b77ba244SStefano Zampini PetscValidType(A, 1); 888b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 8899566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg)); 890b77ba244SStefano Zampini if (flg) break; 891b77ba244SStefano Zampini Bnames = Bnames->next; 892b77ba244SStefano Zampini } 893b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 8949566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg)); 895b77ba244SStefano Zampini if (flg) break; 896b77ba244SStefano Zampini Cnames = Cnames->next; 897b77ba244SStefano Zampini } 8989566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 899b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 900b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9019566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype)); 9029566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype)); 9033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 904e51e0e81SBarry Smith } 905e51e0e81SBarry Smith 906d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str) 907d71ae5a4SJacob Faibussowitsch { 90828f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data; 909cb8c8a77SBarry Smith PetscBool matflg; 910b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9117fabda3fSAlex Fikl 9127fabda3fSAlex Fikl PetscFunctionBegin; 9139566063dSJacob Faibussowitsch PetscCall(MatIsShell(B, &matflg)); 91428b400f6SJacob Faibussowitsch PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name); 9157fabda3fSAlex Fikl 916aea10558SJacob Faibussowitsch B->ops[0] = A->ops[0]; 917aea10558SJacob Faibussowitsch shellB->ops[0] = shellA->ops[0]; 9187fabda3fSAlex Fikl 9191baa6e33SBarry Smith if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str)); 9207fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9217fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9220c0fd78eSBarry Smith if (shellA->dshift) { 92348a46eb9SPierre Jolivet if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift)); 9249566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift, shellB->dshift)); 9257fabda3fSAlex Fikl } else { 9269566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9277fabda3fSAlex Fikl } 9280c0fd78eSBarry Smith if (shellA->left) { 92948a46eb9SPierre Jolivet if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left)); 9309566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left, shellB->left)); 9317fabda3fSAlex Fikl } else { 9329566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9337fabda3fSAlex Fikl } 9340c0fd78eSBarry Smith if (shellA->right) { 93548a46eb9SPierre Jolivet if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right)); 9369566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right, shellB->right)); 9377fabda3fSAlex Fikl } else { 9389566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9397fabda3fSAlex Fikl } 9409566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 941ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 942ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 94340e381c3SBarry Smith if (shellA->axpy) { 9449566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 94540e381c3SBarry Smith shellB->axpy = shellA->axpy; 94640e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 947ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 94840e381c3SBarry Smith } 94945960306SStefano Zampini if (shellA->zrows) { 9509566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows)); 95148a46eb9SPierre Jolivet if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols)); 9529566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals)); 9539566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals, shellB->zvals)); 9549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w)); 9559566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 9569566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 95745960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 95845960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 95945960306SStefano Zampini } 960b77ba244SStefano Zampini 961b77ba244SStefano Zampini matmatA = shellA->matmat; 962b77ba244SStefano Zampini if (matmatA) { 963b77ba244SStefano Zampini while (matmatA->next) { 9649566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname)); 965b77ba244SStefano Zampini matmatA = matmatA->next; 966b77ba244SStefano Zampini } 967b77ba244SStefano Zampini } 9683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9697fabda3fSAlex Fikl } 9707fabda3fSAlex Fikl 971d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M) 972d71ae5a4SJacob Faibussowitsch { 973cb8c8a77SBarry Smith PetscFunctionBegin; 974800f99ffSJeremy L Thompson PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M)); 975800f99ffSJeremy L Thompson ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer; 976f4f49eeaSPierre Jolivet PetscCall(PetscObjectCompose((PetscObject)*M, "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer)); 977f4f49eeaSPierre Jolivet PetscCall(PetscObjectChangeTypeName((PetscObject)*M, ((PetscObject)mat)->type_name)); 978623b4cf3SPierre Jolivet if (op == MAT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN)); 97901f93aa2SJose E. Roman PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M)); 9803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 981cb8c8a77SBarry Smith } 982cb8c8a77SBarry Smith 98366976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y) 984d71ae5a4SJacob Faibussowitsch { 985ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 98625578ef6SJed Brown Vec xx; 987e3f487b0SBarry Smith PetscObjectState instate, outstate; 988ef66eb69SBarry Smith 989ef66eb69SBarry Smith PetscFunctionBegin; 9909566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A, x, &xx)); 9919566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A, xx, &xx)); 9929566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 9939566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A, xx, y)); 9949566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 995e3f487b0SBarry Smith if (instate == outstate) { 996e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 9979566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 998e3f487b0SBarry Smith } 999f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 10009566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A, y)); 10019566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A, y)); 10029f137db4SBarry Smith 10039f137db4SBarry Smith if (shell->axpy) { 1004ef5c7bd2SStefano Zampini Mat X; 1005ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1006ef5c7bd2SStefano Zampini 10079566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10089566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 100908401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1010b77ba244SStefano Zampini 10119566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10129566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_right)); 10139566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left)); 10149566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left)); 10159f137db4SBarry Smith } 10163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1017ef66eb69SBarry Smith } 1018ef66eb69SBarry Smith 1019d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1020d71ae5a4SJacob Faibussowitsch { 10215edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10225edf6516SJed Brown 10235edf6516SJed Brown PetscFunctionBegin; 10245edf6516SJed Brown if (y == z) { 10259566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work)); 10269566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, shell->right_add_work)); 10279566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->right_add_work)); 10285edf6516SJed Brown } else { 10299566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, z)); 10309566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 10315edf6516SJed Brown } 10323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10335edf6516SJed Brown } 10345edf6516SJed Brown 1035d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y) 1036d71ae5a4SJacob Faibussowitsch { 103718be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 103825578ef6SJed Brown Vec xx; 1039e3f487b0SBarry Smith PetscObjectState instate, outstate; 104018be62a5SSatish Balay 104118be62a5SSatish Balay PetscFunctionBegin; 10429566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1043f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE)); 10449566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10459566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A, xx, y)); 10469566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1047e3f487b0SBarry Smith if (instate == outstate) { 1048e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10499566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1050e3f487b0SBarry Smith } 1051f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 1052f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE)); 10539566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A, y)); 1054350ec83bSStefano Zampini 1055350ec83bSStefano Zampini if (shell->axpy) { 1056ef5c7bd2SStefano Zampini Mat X; 1057ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1058ef5c7bd2SStefano Zampini 10599566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10609566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 106108401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 10629566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10639566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_left)); 10649566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 10659566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right)); 1066350ec83bSStefano Zampini } 10673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 106818be62a5SSatish Balay } 106918be62a5SSatish Balay 1070f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y) 1071f8e07d23SBlanca Mellado Pinto { 1072f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1073f8e07d23SBlanca Mellado Pinto Vec xx; 1074f8e07d23SBlanca Mellado Pinto PetscObjectState instate, outstate; 1075f8e07d23SBlanca Mellado Pinto 1076f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1077f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1078f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE)); 1079f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 1080f8e07d23SBlanca Mellado Pinto PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y)); 1081f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1082f8e07d23SBlanca Mellado Pinto if (instate == outstate) { 1083f8e07d23SBlanca Mellado Pinto /* increase the state of the output vector since the user did not update its state themself as should have been done */ 1084f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1085f8e07d23SBlanca Mellado Pinto } 1086f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE)); 1087f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE)); 1088f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostZeroRight(A, y)); 1089f8e07d23SBlanca Mellado Pinto 1090f8e07d23SBlanca Mellado Pinto if (shell->axpy) { 1091f8e07d23SBlanca Mellado Pinto Mat X; 1092f8e07d23SBlanca Mellado Pinto PetscObjectState axpy_state; 1093f8e07d23SBlanca Mellado Pinto 1094f8e07d23SBlanca Mellado Pinto PetscCall(MatShellGetContext(shell->axpy, &X)); 1095f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 1096f8e07d23SBlanca Mellado Pinto PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1097f8e07d23SBlanca Mellado Pinto PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 1098f8e07d23SBlanca Mellado Pinto PetscCall(VecCopy(x, shell->axpy_left)); 1099f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 1100f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right)); 1101f8e07d23SBlanca Mellado Pinto } 1102f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1103f8e07d23SBlanca Mellado Pinto } 1104f8e07d23SBlanca Mellado Pinto 1105d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1106d71ae5a4SJacob Faibussowitsch { 11075edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 11085edf6516SJed Brown 11095edf6516SJed Brown PetscFunctionBegin; 11105edf6516SJed Brown if (y == z) { 11119566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 11129566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, shell->left_add_work)); 11139566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 11145edf6516SJed Brown } else { 11159566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, z)); 11169566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 11175edf6516SJed Brown } 11183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11195edf6516SJed Brown } 11205edf6516SJed Brown 1121f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1122f8e07d23SBlanca Mellado Pinto { 1123f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1124f8e07d23SBlanca Mellado Pinto 1125f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1126f8e07d23SBlanca Mellado Pinto if (y == z) { 1127f8e07d23SBlanca Mellado Pinto if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 1128f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work)); 1129f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 1130f8e07d23SBlanca Mellado Pinto } else { 1131f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, z)); 1132f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, y)); 1133f8e07d23SBlanca Mellado Pinto } 1134f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1135f8e07d23SBlanca Mellado Pinto } 1136f8e07d23SBlanca Mellado Pinto 11370c0fd78eSBarry Smith /* 11380c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11390c0fd78eSBarry Smith */ 1140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v) 1141d71ae5a4SJacob Faibussowitsch { 114218be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 114318be62a5SSatish Balay 114418be62a5SSatish Balay PetscFunctionBegin; 11450c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 11469566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A, v)); 1147305211d5SBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL,...)"); 11489566063dSJacob Faibussowitsch PetscCall(VecScale(v, shell->vscale)); 11491baa6e33SBarry Smith if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift)); 11509566063dSJacob Faibussowitsch PetscCall(VecShift(v, shell->vshift)); 11519566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left)); 11529566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right)); 115345960306SStefano Zampini if (shell->zrows) { 11549566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 11559566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 115645960306SStefano Zampini } 115781c02519SBarry Smith if (shell->axpy) { 1158ef5c7bd2SStefano Zampini Mat X; 1159ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1160ef5c7bd2SStefano Zampini 11619566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 11629566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 116308401ef6SPierre Jolivet PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 11649566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left)); 11659566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left)); 11669566063dSJacob Faibussowitsch PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left)); 116781c02519SBarry Smith } 11683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 116918be62a5SSatish Balay } 117018be62a5SSatish Balay 1171*a29b93afSAudic XU static PetscErrorCode MatGetDiagonalBlock_Shell(Mat A, Mat *b) 1172*a29b93afSAudic XU { 1173*a29b93afSAudic XU Mat_Shell *shell = (Mat_Shell *)A->data; 1174*a29b93afSAudic XU Vec left = NULL, right = NULL; 1175*a29b93afSAudic XU 1176*a29b93afSAudic XU PetscFunctionBegin; 1177*a29b93afSAudic XU PetscCheck(!shell->zrows && !shell->zcols, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatZeroRows() or MatZeroRowsColumns() has been called on the input Mat"); // TODO FIXME 1178*a29b93afSAudic XU PetscCheck(!shell->axpy, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatAXPY() has been called on the input Mat"); // TODO FIXME 1179*a29b93afSAudic XU PetscCheck(!shell->dshift, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot call MatGetDiagonalBlock() if MatDiagonalSet() has been called on the input Mat"); // TODO FIXME 1180*a29b93afSAudic XU if (shell->ops->getdiagonalblock) { 1181*a29b93afSAudic XU PetscCall((*shell->ops->getdiagonalblock)(A, b)); 1182*a29b93afSAudic XU } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Must provide shell matrix with routine to return diagonal block using\nMatShellSetOperation(S,MATOP_GET_DIAGONAL_BLOCK,...)"); 1183*a29b93afSAudic XU PetscCall(MatScale(*b, shell->vscale)); 1184*a29b93afSAudic XU PetscCall(MatShift(*b, shell->vshift)); 1185*a29b93afSAudic XU if (shell->left) { 1186*a29b93afSAudic XU PetscCall(VecCreateLocalVector(shell->left, &left)); 1187*a29b93afSAudic XU PetscCall(VecGetLocalVectorRead(shell->left, left)); 1188*a29b93afSAudic XU } 1189*a29b93afSAudic XU if (shell->right) { 1190*a29b93afSAudic XU PetscCall(VecCreateLocalVector(shell->right, &right)); 1191*a29b93afSAudic XU PetscCall(VecGetLocalVectorRead(shell->right, right)); 1192*a29b93afSAudic XU } 1193*a29b93afSAudic XU PetscCall(MatDiagonalScale(*b, left, right)); 1194*a29b93afSAudic XU if (shell->left) { 1195*a29b93afSAudic XU PetscCall(VecRestoreLocalVectorRead(shell->left, left)); 1196*a29b93afSAudic XU PetscCall(VecDestroy(&left)); 1197*a29b93afSAudic XU } 1198*a29b93afSAudic XU if (shell->right) { 1199*a29b93afSAudic XU PetscCall(VecRestoreLocalVectorRead(shell->right, right)); 1200*a29b93afSAudic XU PetscCall(VecDestroy(&right)); 1201*a29b93afSAudic XU } 1202*a29b93afSAudic XU PetscFunctionReturn(PETSC_SUCCESS); 1203*a29b93afSAudic XU } 1204*a29b93afSAudic XU 1205d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a) 1206d71ae5a4SJacob Faibussowitsch { 1207ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1208789d8953SBarry Smith PetscBool flg; 1209b24ad042SBarry Smith 1210ef66eb69SBarry Smith PetscFunctionBegin; 12119566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y, &flg)); 121228b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent"); 12130c0fd78eSBarry Smith if (shell->left || shell->right) { 12148fe8eb27SJed Brown if (!shell->dshift) { 12159566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 12169566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift, a)); 12170c0fd78eSBarry Smith } else { 12189566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left)); 12199566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right)); 12209566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift, a)); 12210c0fd78eSBarry Smith } 12229566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left)); 12239566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right)); 12248fe8eb27SJed Brown } else shell->vshift += a; 12251baa6e33SBarry Smith if (shell->zrows) PetscCall(VecShift(shell->zvals, a)); 12263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1227ef66eb69SBarry Smith } 1228ef66eb69SBarry Smith 1229d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s) 1230d71ae5a4SJacob Faibussowitsch { 12316464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell *)A->data; 12326464bf51SAlex Fikl 12336464bf51SAlex Fikl PetscFunctionBegin; 12349566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift)); 12350c0fd78eSBarry Smith if (shell->left || shell->right) { 12369566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 12379f137db4SBarry Smith if (shell->left && shell->right) { 12389566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12399566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right)); 12409f137db4SBarry Smith } else if (shell->left) { 12419566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12429f137db4SBarry Smith } else { 12439566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right)); 12449f137db4SBarry Smith } 12459566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, shell->right_work)); 12460c0fd78eSBarry Smith } else { 12479566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, D)); 1248b253ae0bS“Marek } 12493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1250b253ae0bS“Marek } 1251b253ae0bS“Marek 125266976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins) 1253d71ae5a4SJacob Faibussowitsch { 125445960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1255b253ae0bS“Marek Vec d; 1256789d8953SBarry Smith PetscBool flg; 1257b253ae0bS“Marek 1258b253ae0bS“Marek PetscFunctionBegin; 12599566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &flg)); 126028b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent"); 1261b253ae0bS“Marek if (ins == INSERT_VALUES) { 12629566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D, &d)); 12639566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A, d)); 12649566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.)); 12659566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12669566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 12671baa6e33SBarry Smith if (shell->zrows) PetscCall(VecCopy(D, shell->zvals)); 1268b253ae0bS“Marek } else { 12699566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12701baa6e33SBarry Smith if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D)); 12716464bf51SAlex Fikl } 12723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12736464bf51SAlex Fikl } 12746464bf51SAlex Fikl 1275d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a) 1276d71ae5a4SJacob Faibussowitsch { 1277ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1278b24ad042SBarry Smith 1279ef66eb69SBarry Smith PetscFunctionBegin; 1280f4df32b1SMatthew Knepley shell->vscale *= a; 12810c0fd78eSBarry Smith shell->vshift *= a; 12821baa6e33SBarry Smith if (shell->dshift) PetscCall(VecScale(shell->dshift, a)); 128381c02519SBarry Smith shell->axpy_vscale *= a; 12841baa6e33SBarry Smith if (shell->zrows) PetscCall(VecScale(shell->zvals, a)); 12853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 128618be62a5SSatish Balay } 12878fe8eb27SJed Brown 1288d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right) 1289d71ae5a4SJacob Faibussowitsch { 12908fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)Y->data; 12918fe8eb27SJed Brown 12928fe8eb27SJed Brown PetscFunctionBegin; 12938fe8eb27SJed Brown if (left) { 12940c0fd78eSBarry Smith if (!shell->left) { 12959566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left, &shell->left)); 12969566063dSJacob Faibussowitsch PetscCall(VecCopy(left, shell->left)); 12970c0fd78eSBarry Smith } else { 12989566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left, shell->left, left)); 129918be62a5SSatish Balay } 13001baa6e33SBarry Smith if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left)); 1301ef66eb69SBarry Smith } 13028fe8eb27SJed Brown if (right) { 13030c0fd78eSBarry Smith if (!shell->right) { 13049566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right, &shell->right)); 13059566063dSJacob Faibussowitsch PetscCall(VecCopy(right, shell->right)); 13060c0fd78eSBarry Smith } else { 13079566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right, shell->right, right)); 13088fe8eb27SJed Brown } 130945960306SStefano Zampini if (shell->zrows) { 131048a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work)); 13119566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 1.0)); 13129566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 13139566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 13149566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w)); 131545960306SStefano Zampini } 13168fe8eb27SJed Brown } 13171baa6e33SBarry Smith if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right)); 13183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1319ef66eb69SBarry Smith } 1320ef66eb69SBarry Smith 132186a9fd05SPierre Jolivet PETSC_INTERN PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t) 1322d71ae5a4SJacob Faibussowitsch { 1323ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1324ef66eb69SBarry Smith 1325ef66eb69SBarry Smith PetscFunctionBegin; 13268fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1327ef66eb69SBarry Smith shell->vshift = 0.0; 1328ef66eb69SBarry Smith shell->vscale = 1.0; 1329ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1330ef5c7bd2SStefano Zampini shell->axpy_state = 0; 13319566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 13329566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 13339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 13349566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 13359566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 13369566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 13379566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 13389566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 13399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 13409566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1341ef66eb69SBarry Smith } 13423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1343ef66eb69SBarry Smith } 1344ef66eb69SBarry Smith 1345d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d) 1346d71ae5a4SJacob Faibussowitsch { 13473b49f96aSBarry Smith PetscFunctionBegin; 13483b49f96aSBarry Smith *missing = PETSC_FALSE; 13493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13503b49f96aSBarry Smith } 13513b49f96aSBarry Smith 135266976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str) 1353d71ae5a4SJacob Faibussowitsch { 13549f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 13559f137db4SBarry Smith 13569f137db4SBarry Smith PetscFunctionBegin; 1357ef5c7bd2SStefano Zampini if (X == Y) { 13589566063dSJacob Faibussowitsch PetscCall(MatScale(Y, 1.0 + a)); 13593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1360ef5c7bd2SStefano Zampini } 1361ef5c7bd2SStefano Zampini if (!shell->axpy) { 13629566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy)); 13639f137db4SBarry Smith shell->axpy_vscale = a; 13649566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state)); 1365ef5c7bd2SStefano Zampini } else { 13669566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str)); 1367ef5c7bd2SStefano Zampini } 13683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13699f137db4SBarry Smith } 13709f137db4SBarry Smith 1371f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1372f4259b30SLisandro Dalcin NULL, 1373f4259b30SLisandro Dalcin NULL, 1374f4259b30SLisandro Dalcin NULL, 13750c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1376f4259b30SLisandro Dalcin NULL, 13770c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1378f4259b30SLisandro Dalcin NULL, 1379f4259b30SLisandro Dalcin NULL, 1380f4259b30SLisandro Dalcin NULL, 1381f4259b30SLisandro Dalcin /*10*/ NULL, 1382f4259b30SLisandro Dalcin NULL, 1383f4259b30SLisandro Dalcin NULL, 1384f4259b30SLisandro Dalcin NULL, 1385f4259b30SLisandro Dalcin NULL, 1386f4259b30SLisandro Dalcin /*15*/ NULL, 1387f4259b30SLisandro Dalcin NULL, 1388f4259b30SLisandro Dalcin NULL, 13898fe8eb27SJed Brown MatDiagonalScale_Shell, 1390f4259b30SLisandro Dalcin NULL, 1391f4259b30SLisandro Dalcin /*20*/ NULL, 1392ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1393f4259b30SLisandro Dalcin NULL, 1394f4259b30SLisandro Dalcin NULL, 139545960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1396f4259b30SLisandro Dalcin NULL, 1397f4259b30SLisandro Dalcin NULL, 1398f4259b30SLisandro Dalcin NULL, 1399f4259b30SLisandro Dalcin NULL, 1400f4259b30SLisandro Dalcin /*29*/ NULL, 1401f4259b30SLisandro Dalcin NULL, 1402f4259b30SLisandro Dalcin NULL, 1403*a29b93afSAudic XU /*32*/ NULL, 1404f4259b30SLisandro Dalcin NULL, 1405cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin NULL, 1408f4259b30SLisandro Dalcin NULL, 1409f4259b30SLisandro Dalcin NULL, 14109f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1411f4259b30SLisandro Dalcin NULL, 1412f4259b30SLisandro Dalcin NULL, 1413f4259b30SLisandro Dalcin NULL, 1414cb8c8a77SBarry Smith MatCopy_Shell, 1415f4259b30SLisandro Dalcin /*44*/ NULL, 1416ef66eb69SBarry Smith MatScale_Shell, 1417ef66eb69SBarry Smith MatShift_Shell, 14186464bf51SAlex Fikl MatDiagonalSet_Shell, 141945960306SStefano Zampini MatZeroRowsColumns_Shell, 1420f4259b30SLisandro Dalcin /*49*/ NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin NULL, 1423f4259b30SLisandro Dalcin NULL, 1424f4259b30SLisandro Dalcin NULL, 1425f4259b30SLisandro Dalcin /*54*/ NULL, 1426f4259b30SLisandro Dalcin NULL, 1427f4259b30SLisandro Dalcin NULL, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin NULL, 1430f4259b30SLisandro Dalcin /*59*/ NULL, 1431b9b97703SBarry Smith MatDestroy_Shell, 1432f4259b30SLisandro Dalcin NULL, 1433251fad3fSStefano Zampini MatConvertFrom_Shell, 1434f4259b30SLisandro Dalcin NULL, 1435f4259b30SLisandro Dalcin /*64*/ NULL, 1436f4259b30SLisandro Dalcin NULL, 1437f4259b30SLisandro Dalcin NULL, 1438f4259b30SLisandro Dalcin NULL, 1439f4259b30SLisandro Dalcin NULL, 1440f4259b30SLisandro Dalcin /*69*/ NULL, 1441f4259b30SLisandro Dalcin NULL, 1442c87e5d42SMatthew Knepley MatConvert_Shell, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin NULL, 1445f4259b30SLisandro Dalcin /*74*/ NULL, 1446f4259b30SLisandro Dalcin NULL, 1447f4259b30SLisandro Dalcin NULL, 1448f4259b30SLisandro Dalcin NULL, 1449f4259b30SLisandro Dalcin NULL, 1450f4259b30SLisandro Dalcin /*79*/ NULL, 1451f4259b30SLisandro Dalcin NULL, 1452f4259b30SLisandro Dalcin NULL, 1453f4259b30SLisandro Dalcin NULL, 1454f4259b30SLisandro Dalcin NULL, 1455f4259b30SLisandro Dalcin /*84*/ NULL, 1456f4259b30SLisandro Dalcin NULL, 1457f4259b30SLisandro Dalcin NULL, 1458f4259b30SLisandro Dalcin NULL, 1459f4259b30SLisandro Dalcin NULL, 1460f4259b30SLisandro Dalcin /*89*/ NULL, 1461f4259b30SLisandro Dalcin NULL, 1462f4259b30SLisandro Dalcin NULL, 1463f4259b30SLisandro Dalcin NULL, 1464f4259b30SLisandro Dalcin NULL, 1465f4259b30SLisandro Dalcin /*94*/ NULL, 1466f4259b30SLisandro Dalcin NULL, 1467f4259b30SLisandro Dalcin NULL, 1468f4259b30SLisandro Dalcin NULL, 1469f4259b30SLisandro Dalcin NULL, 1470f4259b30SLisandro Dalcin /*99*/ NULL, 1471f4259b30SLisandro Dalcin NULL, 1472f4259b30SLisandro Dalcin NULL, 1473f4259b30SLisandro Dalcin NULL, 1474f4259b30SLisandro Dalcin NULL, 1475f4259b30SLisandro Dalcin /*104*/ NULL, 1476f4259b30SLisandro Dalcin NULL, 1477f4259b30SLisandro Dalcin NULL, 1478f4259b30SLisandro Dalcin NULL, 1479f4259b30SLisandro Dalcin NULL, 1480f4259b30SLisandro Dalcin /*109*/ NULL, 1481f4259b30SLisandro Dalcin NULL, 1482f4259b30SLisandro Dalcin NULL, 1483f4259b30SLisandro Dalcin NULL, 14843b49f96aSBarry Smith MatMissingDiagonal_Shell, 1485f4259b30SLisandro Dalcin /*114*/ NULL, 1486f4259b30SLisandro Dalcin NULL, 1487f4259b30SLisandro Dalcin NULL, 1488f4259b30SLisandro Dalcin NULL, 1489f4259b30SLisandro Dalcin NULL, 1490f4259b30SLisandro Dalcin /*119*/ NULL, 1491f4259b30SLisandro Dalcin NULL, 1492f4259b30SLisandro Dalcin NULL, 1493f8e07d23SBlanca Mellado Pinto MatMultHermitianTransposeAdd_Shell, 1494f4259b30SLisandro Dalcin NULL, 1495f4259b30SLisandro Dalcin /*124*/ NULL, 1496f4259b30SLisandro Dalcin NULL, 1497f4259b30SLisandro Dalcin NULL, 1498f4259b30SLisandro Dalcin NULL, 1499f4259b30SLisandro Dalcin NULL, 1500f4259b30SLisandro Dalcin /*129*/ NULL, 1501f4259b30SLisandro Dalcin NULL, 1502f4259b30SLisandro Dalcin NULL, 1503f4259b30SLisandro Dalcin NULL, 1504f4259b30SLisandro Dalcin NULL, 1505f4259b30SLisandro Dalcin /*134*/ NULL, 1506f4259b30SLisandro Dalcin NULL, 1507f4259b30SLisandro Dalcin NULL, 1508f4259b30SLisandro Dalcin NULL, 1509f4259b30SLisandro Dalcin NULL, 1510f4259b30SLisandro Dalcin /*139*/ NULL, 1511f4259b30SLisandro Dalcin NULL, 1512d70f29a3SPierre Jolivet NULL, 1513d70f29a3SPierre Jolivet NULL, 1514d70f29a3SPierre Jolivet NULL, 1515d70f29a3SPierre Jolivet /*144*/ NULL, 1516d70f29a3SPierre Jolivet NULL, 1517d70f29a3SPierre Jolivet NULL, 151899a7f59eSMark Adams NULL, 151999a7f59eSMark Adams NULL, 15207fb60732SBarry Smith NULL, 1521dec0b466SHong Zhang /*150*/ NULL, 1522eede4a3fSMark Adams NULL, 15234cc2b5b5SPierre Jolivet NULL, 1524dec0b466SHong Zhang NULL}; 1525273d9f13SBarry Smith 1526d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx) 1527d71ae5a4SJacob Faibussowitsch { 1528789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1529789d8953SBarry Smith 1530789d8953SBarry Smith PetscFunctionBegin; 1531800f99ffSJeremy L Thompson if (ctx) { 1532800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 1533800f99ffSJeremy L Thompson PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer)); 1534800f99ffSJeremy L Thompson PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 1535800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer)); 1536800f99ffSJeremy L Thompson shell->ctxcontainer = ctxcontainer; 1537800f99ffSJeremy L Thompson PetscCall(PetscContainerDestroy(&ctxcontainer)); 1538800f99ffSJeremy L Thompson } else { 1539800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL)); 1540800f99ffSJeremy L Thompson shell->ctxcontainer = NULL; 1541800f99ffSJeremy L Thompson } 15423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1543800f99ffSJeremy L Thompson } 1544800f99ffSJeremy L Thompson 154566976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *)) 1546d71ae5a4SJacob Faibussowitsch { 1547800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 1548800f99ffSJeremy L Thompson 1549800f99ffSJeremy L Thompson PetscFunctionBegin; 1550800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f)); 15513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1552789d8953SBarry Smith } 1553789d8953SBarry Smith 155486a9fd05SPierre Jolivet PetscErrorCode MatShellSetContext_Immutable(Mat mat, void *ctx) 155586a9fd05SPierre Jolivet { 155686a9fd05SPierre Jolivet PetscFunctionBegin; 155786a9fd05SPierre 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); 155886a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 155986a9fd05SPierre Jolivet } 156086a9fd05SPierre Jolivet 156186a9fd05SPierre Jolivet PetscErrorCode MatShellSetContextDestroy_Immutable(Mat mat, PetscErrorCode (*f)(void *)) 156286a9fd05SPierre Jolivet { 156386a9fd05SPierre Jolivet PetscFunctionBegin; 156486a9fd05SPierre 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); 156586a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 156686a9fd05SPierre Jolivet } 156786a9fd05SPierre Jolivet 156886a9fd05SPierre Jolivet PetscErrorCode MatShellSetManageScalingShifts_Immutable(Mat mat) 156986a9fd05SPierre Jolivet { 157086a9fd05SPierre Jolivet PetscFunctionBegin; 157186a9fd05SPierre 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); 157286a9fd05SPierre Jolivet PetscFunctionReturn(PETSC_SUCCESS); 157386a9fd05SPierre Jolivet } 157486a9fd05SPierre Jolivet 1575d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype) 1576d71ae5a4SJacob Faibussowitsch { 1577db77db73SJeremy L Thompson PetscFunctionBegin; 15789566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 15799566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype)); 15803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1581db77db73SJeremy L Thompson } 1582db77db73SJeremy L Thompson 158366976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1584d71ae5a4SJacob Faibussowitsch { 1585789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 1586789d8953SBarry Smith 1587789d8953SBarry Smith PetscFunctionBegin; 1588789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1589789d8953SBarry Smith A->ops->diagonalset = NULL; 1590789d8953SBarry Smith A->ops->diagonalscale = NULL; 1591789d8953SBarry Smith A->ops->scale = NULL; 1592789d8953SBarry Smith A->ops->shift = NULL; 1593789d8953SBarry Smith A->ops->axpy = NULL; 15943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1595789d8953SBarry Smith } 1596789d8953SBarry Smith 1597d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void)) 1598d71ae5a4SJacob Faibussowitsch { 1599feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell *)mat->data; 1600789d8953SBarry Smith 1601789d8953SBarry Smith PetscFunctionBegin; 1602789d8953SBarry Smith switch (op) { 1603d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1604d71ae5a4SJacob Faibussowitsch shell->ops->destroy = (PetscErrorCode(*)(Mat))f; 1605d71ae5a4SJacob Faibussowitsch break; 1606789d8953SBarry Smith case MATOP_VIEW: 1607ad540459SPierre Jolivet if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view; 1608789d8953SBarry Smith mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f; 1609789d8953SBarry Smith break; 1610d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1611d71ae5a4SJacob Faibussowitsch shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f; 1612d71ae5a4SJacob Faibussowitsch break; 1613789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1614789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1615789d8953SBarry Smith case MATOP_SHIFT: 1616789d8953SBarry Smith case MATOP_SCALE: 1617789d8953SBarry Smith case MATOP_AXPY: 1618789d8953SBarry Smith case MATOP_ZERO_ROWS: 1619789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 162028b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1621789d8953SBarry Smith (((void (**)(void))mat->ops)[op]) = f; 1622789d8953SBarry Smith break; 1623789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1624789d8953SBarry Smith if (shell->managescalingshifts) { 1625789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1626789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1627789d8953SBarry Smith } else { 1628789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1629789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1630789d8953SBarry Smith } 1631789d8953SBarry Smith break; 1632*a29b93afSAudic XU case MATOP_GET_DIAGONAL_BLOCK: 1633*a29b93afSAudic XU if (shell->managescalingshifts) { 1634*a29b93afSAudic XU shell->ops->getdiagonalblock = (PetscErrorCode(*)(Mat, Mat *))f; 1635*a29b93afSAudic XU mat->ops->getdiagonalblock = MatGetDiagonalBlock_Shell; 1636*a29b93afSAudic XU } else { 1637*a29b93afSAudic XU shell->ops->getdiagonalblock = NULL; 1638*a29b93afSAudic XU mat->ops->getdiagonalblock = (PetscErrorCode(*)(Mat, Mat *))f; 1639*a29b93afSAudic XU } 1640*a29b93afSAudic XU break; 1641789d8953SBarry Smith case MATOP_MULT: 1642789d8953SBarry Smith if (shell->managescalingshifts) { 1643789d8953SBarry Smith shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1644789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1645789d8953SBarry Smith } else { 1646789d8953SBarry Smith shell->ops->mult = NULL; 1647789d8953SBarry Smith mat->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1648789d8953SBarry Smith } 1649789d8953SBarry Smith break; 1650789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1651789d8953SBarry Smith if (shell->managescalingshifts) { 1652789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1653789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1654789d8953SBarry Smith } else { 1655789d8953SBarry Smith shell->ops->multtranspose = NULL; 1656789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1657789d8953SBarry Smith } 1658789d8953SBarry Smith break; 1659f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1660f8e07d23SBlanca Mellado Pinto if (shell->managescalingshifts) { 1661f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1662f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = MatMultHermitianTranspose_Shell; 1663f8e07d23SBlanca Mellado Pinto } else { 1664f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = NULL; 1665f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1666f8e07d23SBlanca Mellado Pinto } 1667f8e07d23SBlanca Mellado Pinto break; 1668d71ae5a4SJacob Faibussowitsch default: 1669d71ae5a4SJacob Faibussowitsch (((void (**)(void))mat->ops)[op]) = f; 1670d71ae5a4SJacob Faibussowitsch break; 1671789d8953SBarry Smith } 16723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1673789d8953SBarry Smith } 1674789d8953SBarry Smith 1675d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void)) 1676d71ae5a4SJacob Faibussowitsch { 1677789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1678789d8953SBarry Smith 1679789d8953SBarry Smith PetscFunctionBegin; 1680789d8953SBarry Smith switch (op) { 1681d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1682d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->destroy; 1683d71ae5a4SJacob Faibussowitsch break; 1684d71ae5a4SJacob Faibussowitsch case MATOP_VIEW: 1685d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))mat->ops->view; 1686d71ae5a4SJacob Faibussowitsch break; 1687d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1688d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->copy; 1689d71ae5a4SJacob Faibussowitsch break; 1690789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1691789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1692789d8953SBarry Smith case MATOP_SHIFT: 1693789d8953SBarry Smith case MATOP_SCALE: 1694789d8953SBarry Smith case MATOP_AXPY: 1695789d8953SBarry Smith case MATOP_ZERO_ROWS: 1696d71ae5a4SJacob Faibussowitsch case MATOP_ZERO_ROWS_COLUMNS: 1697d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1698d71ae5a4SJacob Faibussowitsch break; 1699789d8953SBarry Smith case MATOP_GET_DIAGONAL: 17009371c9d4SSatish Balay if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal; 17019371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1702789d8953SBarry Smith break; 1703*a29b93afSAudic XU case MATOP_GET_DIAGONAL_BLOCK: 1704*a29b93afSAudic XU if (shell->ops->getdiagonalblock) *f = (void (*)(void))shell->ops->getdiagonalblock; 1705*a29b93afSAudic XU else *f = (((void (**)(void))mat->ops)[op]); 1706*a29b93afSAudic XU break; 1707789d8953SBarry Smith case MATOP_MULT: 17089371c9d4SSatish Balay if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult; 17099371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1710789d8953SBarry Smith break; 1711789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 17129371c9d4SSatish Balay if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose; 17139371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1714789d8953SBarry Smith break; 1715f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1716f8e07d23SBlanca Mellado Pinto if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose; 1717f8e07d23SBlanca Mellado Pinto else *f = (((void (**)(void))mat->ops)[op]); 1718f8e07d23SBlanca Mellado Pinto break; 1719d71ae5a4SJacob Faibussowitsch default: 1720d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1721789d8953SBarry Smith } 17223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1723789d8953SBarry Smith } 1724789d8953SBarry Smith 17250bad9183SKris Buschelman /*MC 172601c1178eSBarry Smith MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free. 17270bad9183SKris Buschelman 17280bad9183SKris Buschelman Level: advanced 17290bad9183SKris Buschelman 17301cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()` 17310bad9183SKris Buschelman M*/ 17320bad9183SKris Buschelman 1733d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1734d71ae5a4SJacob Faibussowitsch { 1735273d9f13SBarry Smith Mat_Shell *b; 1736273d9f13SBarry Smith 1737273d9f13SBarry Smith PetscFunctionBegin; 17384dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&b)); 1739273d9f13SBarry Smith A->data = (void *)b; 1740aea10558SJacob Faibussowitsch A->ops[0] = MatOps_Values; 1741273d9f13SBarry Smith 1742800f99ffSJeremy L Thompson b->ctxcontainer = NULL; 1743ef66eb69SBarry Smith b->vshift = 0.0; 1744ef66eb69SBarry Smith b->vscale = 1.0; 17450c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1746273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1747210f0121SBarry Smith A->preallocated = PETSC_FALSE; 17482205254eSKarl Rupp 17499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell)); 17509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell)); 1751800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell)); 17529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell)); 17539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell)); 17549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell)); 17559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell)); 17569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell)); 17579566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL)); 17583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1759273d9f13SBarry Smith } 1760e51e0e81SBarry Smith 17614b828684SBarry Smith /*@C 176211a5261eSBarry Smith MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined 1763ff756334SLois Curfman McInnes private data storage format. 1764e51e0e81SBarry Smith 1765d083f849SBarry Smith Collective 1766c7fcc2eaSBarry Smith 1767e51e0e81SBarry Smith Input Parameters: 1768c7fcc2eaSBarry Smith + comm - MPI communicator 176945f401ebSJose E. Roman . m - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given) 177045f401ebSJose E. Roman . n - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given) 177145f401ebSJose E. Roman . M - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given) 177245f401ebSJose E. Roman . N - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given) 1773c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1774e51e0e81SBarry Smith 1775ff756334SLois Curfman McInnes Output Parameter: 177644cd7ae7SLois Curfman McInnes . A - the matrix 1777e51e0e81SBarry Smith 1778ff2fd236SBarry Smith Level: advanced 1779ff2fd236SBarry Smith 17802920cce0SJacob Faibussowitsch Example Usage: 178127430b45SBarry Smith .vb 178227430b45SBarry Smith extern PetscErrorCode mult(Mat, Vec, Vec); 17832920cce0SJacob Faibussowitsch 178427430b45SBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &mat); 178527430b45SBarry Smith MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult); 17862920cce0SJacob Faibussowitsch // Use matrix for operations that have been set 178727430b45SBarry Smith MatDestroy(mat); 178827430b45SBarry Smith .ve 1789f39d1f56SLois Curfman McInnes 1790ff756334SLois Curfman McInnes Notes: 1791ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 179211a5261eSBarry Smith with `KSP` (such as, for use with matrix-free methods). You should not 1793ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1794e51e0e81SBarry Smith 1795f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1796f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 17972ef1f0ffSBarry Smith creating a shell matrix, `A`, that supports parallel matrix-vector 179811a5261eSBarry Smith products using `MatMult`(A,x,y) the user should set the number 1799645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1800645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1801645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1802645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1803645985a0SLois Curfman McInnes For example, 1804f39d1f56SLois Curfman McInnes 180527430b45SBarry Smith .vb 180627430b45SBarry Smith Vec x, y 180727430b45SBarry Smith extern PetscErrorCode mult(Mat,Vec,Vec); 180827430b45SBarry Smith Mat A 180927430b45SBarry Smith 181027430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,M,&y); 181127430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,N,&x); 181227430b45SBarry Smith VecGetLocalSize(y,&m); 181327430b45SBarry Smith VecGetLocalSize(x,&n); 181427430b45SBarry Smith MatCreateShell(comm,m,n,M,N,ctx,&A); 181527430b45SBarry Smith MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 181627430b45SBarry Smith MatMult(A,x,y); 181727430b45SBarry Smith MatDestroy(&A); 181827430b45SBarry Smith VecDestroy(&y); 181927430b45SBarry Smith VecDestroy(&x); 182027430b45SBarry Smith .ve 1821e51e0e81SBarry Smith 18222ef1f0ffSBarry Smith `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` 18232ef1f0ffSBarry Smith internally, so these operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called. 18240c0fd78eSBarry Smith 182527430b45SBarry Smith Developer Notes: 18262ef1f0ffSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 18272ef1f0ffSBarry Smith 182895452b02SPatrick Sanan Regarding shifting and scaling. The general form is 18290c0fd78eSBarry Smith 18300c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 18310c0fd78eSBarry Smith 18320c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 18330c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 18340c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 18350c0fd78eSBarry Smith 18360c0fd78eSBarry Smith A is the user provided function. 18370c0fd78eSBarry Smith 183827430b45SBarry Smith `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for 1839c5dec841SPierre Jolivet for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger 184011a5261eSBarry Smith an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat); 184111a5261eSBarry Smith each time the `MATSHELL` matrix has changed. 1842ad2f5c3fSBarry Smith 184311a5261eSBarry Smith Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()` 1844b77ba244SStefano Zampini 184511a5261eSBarry Smith Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided 184611a5261eSBarry Smith with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`. 1847ad2f5c3fSBarry Smith 1848fe59aa6dSJacob Faibussowitsch Fortran Notes: 18492ef1f0ffSBarry Smith To use this from Fortran with a `ctx` you must write an interface definition for this 185011a5261eSBarry Smith function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing 18512ef1f0ffSBarry Smith in as the `ctx` argument. 185211a5261eSBarry Smith 1853fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 1854e51e0e81SBarry Smith @*/ 1855d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A) 1856d71ae5a4SJacob Faibussowitsch { 18573a40ed3dSBarry Smith PetscFunctionBegin; 18589566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, A)); 18599566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A, m, n, M, N)); 18609566063dSJacob Faibussowitsch PetscCall(MatSetType(*A, MATSHELL)); 18619566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A, ctx)); 18629566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 18633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1864c7fcc2eaSBarry Smith } 1865c7fcc2eaSBarry Smith 1866c6866cfdSSatish Balay /*@ 186711a5261eSBarry Smith MatShellSetContext - sets the context for a `MATSHELL` shell matrix 1868c7fcc2eaSBarry Smith 1869c3339decSBarry Smith Logically Collective 1870c7fcc2eaSBarry Smith 1871273d9f13SBarry Smith Input Parameters: 187211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1873273d9f13SBarry Smith - ctx - the context 1874273d9f13SBarry Smith 1875273d9f13SBarry Smith Level: advanced 1876273d9f13SBarry Smith 1877fe59aa6dSJacob Faibussowitsch Fortran Notes: 187827430b45SBarry Smith You must write a Fortran interface definition for this 18792ef1f0ffSBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument. 1880273d9f13SBarry Smith 18811cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()` 18820bc0a719SBarry Smith @*/ 1883d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx) 1884d71ae5a4SJacob Faibussowitsch { 1885273d9f13SBarry Smith PetscFunctionBegin; 18860700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1887cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx)); 18883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1889e51e0e81SBarry Smith } 1890e51e0e81SBarry Smith 1891fe59aa6dSJacob Faibussowitsch /*@C 189211a5261eSBarry Smith MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context 1893800f99ffSJeremy L Thompson 1894c3339decSBarry Smith Logically Collective 1895800f99ffSJeremy L Thompson 1896800f99ffSJeremy L Thompson Input Parameters: 1897800f99ffSJeremy L Thompson + mat - the shell matrix 1898800f99ffSJeremy L Thompson - f - the context destroy function 1899800f99ffSJeremy L Thompson 190027430b45SBarry Smith Level: advanced 190127430b45SBarry Smith 1902800f99ffSJeremy L Thompson Note: 1903800f99ffSJeremy L Thompson If the `MatShell` is never duplicated, the behavior of this function is equivalent 190411a5261eSBarry Smith to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()` 1905800f99ffSJeremy L Thompson ensures proper reference counting for the user provided context data in the case that 190611a5261eSBarry Smith the `MATSHELL` is duplicated. 1907800f99ffSJeremy L Thompson 19081cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()` 1909800f99ffSJeremy L Thompson @*/ 1910d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *)) 1911d71ae5a4SJacob Faibussowitsch { 1912800f99ffSJeremy L Thompson PetscFunctionBegin; 1913800f99ffSJeremy L Thompson PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1914800f99ffSJeremy L Thompson PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f)); 19153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1916800f99ffSJeremy L Thompson } 1917800f99ffSJeremy L Thompson 1918db77db73SJeremy L Thompson /*@C 19192ef1f0ffSBarry Smith MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()` 1920db77db73SJeremy L Thompson 19212ef1f0ffSBarry Smith Logically Collective 1922db77db73SJeremy L Thompson 1923db77db73SJeremy L Thompson Input Parameters: 192411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1925db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1926db77db73SJeremy L Thompson 1927db77db73SJeremy L Thompson Level: advanced 1928db77db73SJeremy L Thompson 19291cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()` 1930db77db73SJeremy L Thompson @*/ 1931d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype) 1932d71ae5a4SJacob Faibussowitsch { 1933db77db73SJeremy L Thompson PetscFunctionBegin; 1934cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype)); 19353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1936db77db73SJeremy L Thompson } 1937db77db73SJeremy L Thompson 19380c0fd78eSBarry Smith /*@ 193911a5261eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately 194011a5261eSBarry Smith after `MatCreateShell()` 19410c0fd78eSBarry Smith 194227430b45SBarry Smith Logically Collective 19430c0fd78eSBarry Smith 19440c0fd78eSBarry Smith Input Parameter: 1945fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix 19460c0fd78eSBarry Smith 19470c0fd78eSBarry Smith Level: advanced 19480c0fd78eSBarry Smith 19491cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()` 19500c0fd78eSBarry Smith @*/ 1951d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1952d71ae5a4SJacob Faibussowitsch { 19530c0fd78eSBarry Smith PetscFunctionBegin; 19540c0fd78eSBarry Smith PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1955cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A)); 19563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19570c0fd78eSBarry Smith } 19580c0fd78eSBarry Smith 1959c16cb8f2SBarry Smith /*@C 196011a5261eSBarry Smith MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function. 1961f3b1f45cSBarry Smith 1962cf53795eSBarry Smith Logically Collective; No Fortran Support 1963f3b1f45cSBarry Smith 1964f3b1f45cSBarry Smith Input Parameters: 196511a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1966f3b1f45cSBarry Smith . f - the function 196711a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1968f3b1f45cSBarry Smith - ctx - an optional context for the function 1969f3b1f45cSBarry Smith 1970f3b1f45cSBarry Smith Output Parameter: 197111a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1972f3b1f45cSBarry Smith 19733c7db156SBarry Smith Options Database Key: 1974f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1975f3b1f45cSBarry Smith 1976f3b1f45cSBarry Smith Level: advanced 1977f3b1f45cSBarry Smith 19781cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()` 1979f3b1f45cSBarry Smith @*/ 1980d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1981d71ae5a4SJacob Faibussowitsch { 1982f3b1f45cSBarry Smith PetscInt m, n; 1983f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1984f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 198574e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1986f3b1f45cSBarry Smith 1987f3b1f45cSBarry Smith PetscFunctionBegin; 1988f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 19899566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v)); 19909566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 19919566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf)); 19929566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 19939566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 1994f3b1f45cSBarry Smith 19959566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 19969566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat)); 1997f3b1f45cSBarry Smith 19989566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 19999566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 20009566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 20019566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 2002f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 2003f3b1f45cSBarry Smith flag = PETSC_FALSE; 2004f3b1f45cSBarry Smith if (v) { 200501c1178eSBarry 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))); 20069566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view")); 20079566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view")); 20089566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view")); 2009f3b1f45cSBarry Smith } 2010f3b1f45cSBarry Smith } else if (v) { 201101c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n")); 2012f3b1f45cSBarry Smith } 2013f3b1f45cSBarry Smith if (flg) *flg = flag; 20149566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 20179566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2019f3b1f45cSBarry Smith } 2020f3b1f45cSBarry Smith 2021f3b1f45cSBarry Smith /*@C 202211a5261eSBarry Smith MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function. 2023f3b1f45cSBarry Smith 2024cf53795eSBarry Smith Logically Collective; No Fortran Support 2025f3b1f45cSBarry Smith 2026f3b1f45cSBarry Smith Input Parameters: 202711a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2028f3b1f45cSBarry Smith . f - the function 202911a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 2030f3b1f45cSBarry Smith - ctx - an optional context for the function 2031f3b1f45cSBarry Smith 2032f3b1f45cSBarry Smith Output Parameter: 203311a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 2034f3b1f45cSBarry Smith 20353c7db156SBarry Smith Options Database Key: 2036f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 2037f3b1f45cSBarry Smith 2038f3b1f45cSBarry Smith Level: advanced 2039f3b1f45cSBarry Smith 20401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()` 2041f3b1f45cSBarry Smith @*/ 2042d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 2043d71ae5a4SJacob Faibussowitsch { 2044f3b1f45cSBarry Smith Vec x, y, z; 2045f3b1f45cSBarry Smith PetscInt m, n, M, N; 2046f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 2047f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 204874e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 2049f3b1f45cSBarry Smith 2050f3b1f45cSBarry Smith PetscFunctionBegin; 2051f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 20529566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v)); 20539566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &y)); 20549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &z)); 20559566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 20569566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 20579566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf)); 20589566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 20599566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 20609566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 20619566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf)); 20629566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat)); 2063f3b1f45cSBarry Smith 20649566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 20659566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 20669566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 20679566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 2068f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 2069f3b1f45cSBarry Smith flag = PETSC_FALSE; 2070f3b1f45cSBarry Smith if (v) { 207101c1178eSBarry 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))); 20729566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20739566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20749566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 2075f3b1f45cSBarry Smith } 2076f3b1f45cSBarry Smith } else if (v) { 207701c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n")); 2078f3b1f45cSBarry Smith } 2079f3b1f45cSBarry Smith if (flg) *flg = flag; 20809566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20819566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20829566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20839566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 20849566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 20859566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 20869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 20873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2088f3b1f45cSBarry Smith } 2089f3b1f45cSBarry Smith 2090f3b1f45cSBarry Smith /*@C 209111a5261eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix. 2092e51e0e81SBarry Smith 2093c3339decSBarry Smith Logically Collective 2094fee21e36SBarry Smith 2095c7fcc2eaSBarry Smith Input Parameters: 209611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2097c7fcc2eaSBarry Smith . op - the name of the operation 2098789d8953SBarry Smith - g - the function that provides the operation. 2099c7fcc2eaSBarry Smith 210015091d37SBarry Smith Level: advanced 210115091d37SBarry Smith 21022920cce0SJacob Faibussowitsch Example Usage: 2103c3339decSBarry Smith .vb 2104c3339decSBarry Smith extern PetscErrorCode usermult(Mat, Vec, Vec); 21052920cce0SJacob Faibussowitsch 2106c3339decSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 2107c3339decSBarry Smith MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult); 2108c3339decSBarry Smith .ve 21090b627109SLois Curfman McInnes 2110a62d957aSLois Curfman McInnes Notes: 2111e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 21121c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2113a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 211411a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2115a62d957aSLois Curfman McInnes 211611a5261eSBarry Smith All user-provided functions (except for `MATOP_DESTROY`) should have the same calling 2117deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2118deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2119deebb3c3SLois Curfman McInnes routines, e.g., 2120a62d957aSLois Curfman McInnes $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2121a62d957aSLois Curfman McInnes 21224aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 21234aa34b0aSBarry Smith nonzero on failure. 21244aa34b0aSBarry Smith 2125a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 212611a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 212711a5261eSBarry Smith set by `MatCreateShell()`. 2128a62d957aSLois Curfman McInnes 21292ef1f0ffSBarry Smith Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) 21302ef1f0ffSBarry Smith use `MatShellSetMatProductOperation()` 2131b77ba244SStefano Zampini 2132fe59aa6dSJacob Faibussowitsch Fortran Notes: 213311a5261eSBarry Smith For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not 2134c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2135501d9185SBarry Smith 21361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 2137e51e0e81SBarry Smith @*/ 2138d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void)) 2139d71ae5a4SJacob Faibussowitsch { 21403a40ed3dSBarry Smith PetscFunctionBegin; 21410700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2142cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g)); 21433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2144e51e0e81SBarry Smith } 2145f0479e8cSBarry Smith 2146d4bb536fSBarry Smith /*@C 214711a5261eSBarry Smith MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix. 2148d4bb536fSBarry Smith 2149c7fcc2eaSBarry Smith Not Collective 2150c7fcc2eaSBarry Smith 2151d4bb536fSBarry Smith Input Parameters: 215211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2153c7fcc2eaSBarry Smith - op - the name of the operation 2154d4bb536fSBarry Smith 2155d4bb536fSBarry Smith Output Parameter: 2156789d8953SBarry Smith . g - the function that provides the operation. 2157d4bb536fSBarry Smith 215815091d37SBarry Smith Level: advanced 215915091d37SBarry Smith 216027430b45SBarry Smith Notes: 2161e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2162d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2163d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 216411a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2165d4bb536fSBarry Smith 2166d4bb536fSBarry Smith All user-provided functions have the same calling 2167d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2168d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2169d4bb536fSBarry Smith routines, e.g., 2170d4bb536fSBarry Smith $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2171d4bb536fSBarry Smith 2172d4bb536fSBarry Smith Within each user-defined routine, the user should call 217311a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 217411a5261eSBarry Smith set by `MatCreateShell()`. 2175d4bb536fSBarry Smith 21761cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()` 2177d4bb536fSBarry Smith @*/ 2178d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void)) 2179d71ae5a4SJacob Faibussowitsch { 21803a40ed3dSBarry Smith PetscFunctionBegin; 21810700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2182cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g)); 21833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2184d4bb536fSBarry Smith } 2185b77ba244SStefano Zampini 2186b77ba244SStefano Zampini /*@ 218711a5261eSBarry Smith MatIsShell - Inquires if a matrix is derived from `MATSHELL` 2188b77ba244SStefano Zampini 2189b77ba244SStefano Zampini Input Parameter: 2190b77ba244SStefano Zampini . mat - the matrix 2191b77ba244SStefano Zampini 2192b77ba244SStefano Zampini Output Parameter: 2193b77ba244SStefano Zampini . flg - the boolean value 2194b77ba244SStefano Zampini 2195b77ba244SStefano Zampini Level: developer 2196b77ba244SStefano Zampini 2197fe59aa6dSJacob Faibussowitsch Developer Notes: 21982ef1f0ffSBarry Smith In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices 21992ef1f0ffSBarry Smith (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc) 2200b77ba244SStefano Zampini 22011cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` 2202b77ba244SStefano Zampini @*/ 2203d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2204d71ae5a4SJacob Faibussowitsch { 2205b77ba244SStefano Zampini PetscFunctionBegin; 2206b77ba244SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 22074f572ea9SToby Isaac PetscAssertPointer(flg, 2); 2208b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 22093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2210b77ba244SStefano Zampini } 2211