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 7af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 845960306SStefano Zampini #include <petsc/private/vecimpl.h> 9e51e0e81SBarry Smith 1028f357e3SAlex Fikl struct _MatShellOps { 11976e8c5aSLisandro Dalcin /* 3 */ PetscErrorCode (*mult)(Mat, Vec, Vec); 12976e8c5aSLisandro Dalcin /* 5 */ PetscErrorCode (*multtranspose)(Mat, Vec, Vec); 13976e8c5aSLisandro Dalcin /* 17 */ PetscErrorCode (*getdiagonal)(Mat, Vec); 14976e8c5aSLisandro Dalcin /* 43 */ PetscErrorCode (*copy)(Mat, Mat, MatStructure); 15976e8c5aSLisandro Dalcin /* 60 */ PetscErrorCode (*destroy)(Mat); 1628f357e3SAlex Fikl }; 1728f357e3SAlex Fikl 18b77ba244SStefano Zampini struct _n_MatShellMatFunctionList { 19b77ba244SStefano Zampini PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **); 20b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 21b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 22b77ba244SStefano Zampini MatProductType ptype; 23b77ba244SStefano Zampini char *composedname; /* string to identify routine with double dispatch */ 24b77ba244SStefano Zampini char *resultname; /* result matrix type */ 25b77ba244SStefano Zampini 26b77ba244SStefano Zampini struct _n_MatShellMatFunctionList *next; 27b77ba244SStefano Zampini }; 28b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList; 29b77ba244SStefano Zampini 3028f357e3SAlex Fikl typedef struct { 3128f357e3SAlex Fikl struct _MatShellOps ops[1]; 322205254eSKarl Rupp 33b77ba244SStefano Zampini /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 34b77ba244SStefano Zampini PetscBool managescalingshifts; 35b77ba244SStefano Zampini 36b77ba244SStefano Zampini /* support for MatScale, MatShift and MatMultAdd */ 37ef66eb69SBarry Smith PetscScalar vscale, vshift; 388fe8eb27SJed Brown Vec dshift; 398fe8eb27SJed Brown Vec left, right; 408fe8eb27SJed Brown Vec left_work, right_work; 415edf6516SJed Brown Vec left_add_work, right_add_work; 42b77ba244SStefano Zampini 43ef5c7bd2SStefano Zampini /* support for MatAXPY */ 449f137db4SBarry Smith Mat axpy; 459f137db4SBarry Smith PetscScalar axpy_vscale; 46b77ba244SStefano Zampini Vec axpy_left, axpy_right; 47ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 48b77ba244SStefano Zampini 4945960306SStefano Zampini /* support for ZeroRows/Columns operations */ 5045960306SStefano Zampini IS zrows; 5145960306SStefano Zampini IS zcols; 5245960306SStefano Zampini Vec zvals; 5345960306SStefano Zampini Vec zvals_w; 5445960306SStefano Zampini VecScatter zvals_sct_r; 5545960306SStefano Zampini VecScatter zvals_sct_c; 56b77ba244SStefano Zampini 57b77ba244SStefano Zampini /* MatMat operations */ 58b77ba244SStefano Zampini MatShellMatFunctionList matmat; 59b77ba244SStefano Zampini 60b77ba244SStefano Zampini /* user defined context */ 61800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 6288cf3e7dSBarry Smith } Mat_Shell; 630c0fd78eSBarry Smith 6445960306SStefano Zampini /* 6545960306SStefano Zampini Store and scale values on zeroed rows 6645960306SStefano Zampini xx = [x_1, 0], 0 on zeroed columns 6745960306SStefano Zampini */ 68d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx) 69d71ae5a4SJacob Faibussowitsch { 7045960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 7145960306SStefano Zampini 7245960306SStefano Zampini PetscFunctionBegin; 7345960306SStefano Zampini *xx = x; 7445960306SStefano Zampini if (shell->zrows) { 759566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 769566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 779566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 789566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 7945960306SStefano Zampini } 8045960306SStefano Zampini if (shell->zcols) { 8148a46eb9SPierre Jolivet if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 829566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->right_work)); 839566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0)); 8445960306SStefano Zampini *xx = shell->right_work; 8545960306SStefano Zampini } 863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8745960306SStefano Zampini } 8845960306SStefano Zampini 8945960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 90d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x) 91d71ae5a4SJacob Faibussowitsch { 9245960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 9345960306SStefano Zampini 9445960306SStefano Zampini PetscFunctionBegin; 9545960306SStefano Zampini if (shell->zrows) { 969566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 979566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 9845960306SStefano Zampini } 993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10045960306SStefano Zampini } 10145960306SStefano Zampini 10245960306SStefano Zampini /* 10345960306SStefano Zampini Store and scale values on zeroed rows 10445960306SStefano Zampini xx = [x_1, 0], 0 on zeroed rows 10545960306SStefano Zampini */ 106d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx) 107d71ae5a4SJacob Faibussowitsch { 10845960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 10945960306SStefano Zampini 11045960306SStefano Zampini PetscFunctionBegin; 11145960306SStefano Zampini *xx = NULL; 11245960306SStefano Zampini if (!shell->zrows) { 11345960306SStefano Zampini *xx = x; 11445960306SStefano Zampini } else { 11548a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 1169566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->left_work)); 1179566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 1189566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 1199566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 1209566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 1219566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 1229566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 12345960306SStefano Zampini *xx = shell->left_work; 12445960306SStefano Zampini } 1253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12645960306SStefano Zampini } 12745960306SStefano Zampini 12845960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 129d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x) 130d71ae5a4SJacob Faibussowitsch { 13145960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 13245960306SStefano Zampini 13345960306SStefano Zampini PetscFunctionBegin; 1341baa6e33SBarry Smith if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0)); 13545960306SStefano Zampini if (shell->zrows) { 1369566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 1379566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 13845960306SStefano Zampini } 1393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14045960306SStefano Zampini } 14145960306SStefano Zampini 1428fe8eb27SJed Brown /* 1430c0fd78eSBarry Smith xx = diag(left)*x 1448fe8eb27SJed Brown */ 145d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx) 146d71ae5a4SJacob Faibussowitsch { 1478fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1488fe8eb27SJed Brown 1498fe8eb27SJed Brown PetscFunctionBegin; 1500298fd71SBarry Smith *xx = NULL; 1518fe8eb27SJed Brown if (!shell->left) { 1528fe8eb27SJed Brown *xx = x; 1538fe8eb27SJed Brown } else { 1549566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work)); 1559566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, x, shell->left)); 1568fe8eb27SJed Brown *xx = shell->left_work; 1578fe8eb27SJed Brown } 1583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1598fe8eb27SJed Brown } 1608fe8eb27SJed Brown 1610c0fd78eSBarry Smith /* 1620c0fd78eSBarry Smith xx = diag(right)*x 1630c0fd78eSBarry Smith */ 164d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx) 165d71ae5a4SJacob Faibussowitsch { 1668fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1678fe8eb27SJed Brown 1688fe8eb27SJed Brown PetscFunctionBegin; 1690298fd71SBarry Smith *xx = NULL; 1708fe8eb27SJed Brown if (!shell->right) { 1718fe8eb27SJed Brown *xx = x; 1728fe8eb27SJed Brown } else { 1739566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work)); 1749566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, x, shell->right)); 1758fe8eb27SJed Brown *xx = shell->right_work; 1768fe8eb27SJed Brown } 1773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1788fe8eb27SJed Brown } 1798fe8eb27SJed Brown 1800c0fd78eSBarry Smith /* 1810c0fd78eSBarry Smith x = diag(left)*x 1820c0fd78eSBarry Smith */ 183d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x) 184d71ae5a4SJacob Faibussowitsch { 1858fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1868fe8eb27SJed Brown 1878fe8eb27SJed Brown PetscFunctionBegin; 1889566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left)); 1893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1908fe8eb27SJed Brown } 1918fe8eb27SJed Brown 1920c0fd78eSBarry Smith /* 1930c0fd78eSBarry Smith x = diag(right)*x 1940c0fd78eSBarry Smith */ 195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x) 196d71ae5a4SJacob Faibussowitsch { 1978fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1988fe8eb27SJed Brown 1998fe8eb27SJed Brown PetscFunctionBegin; 2009566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(x, x, shell->right)); 2013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2028fe8eb27SJed Brown } 2038fe8eb27SJed Brown 2040c0fd78eSBarry Smith /* 2050c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 2060c0fd78eSBarry Smith 2070c0fd78eSBarry Smith On input Y already contains A*x 2080c0fd78eSBarry Smith */ 209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y) 210d71ae5a4SJacob Faibussowitsch { 2118fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 2128fe8eb27SJed Brown 2138fe8eb27SJed Brown PetscFunctionBegin; 2148fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 2158fe8eb27SJed Brown PetscInt i, m; 2168fe8eb27SJed Brown const PetscScalar *x, *d; 2178fe8eb27SJed Brown PetscScalar *y; 2189566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &m)); 2199566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift, &d)); 2209566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 2219566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y, &y)); 2228fe8eb27SJed Brown for (i = 0; i < m; i++) y[i] = shell->vscale * y[i] + d[i] * x[i]; 2239566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 2249566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 2259566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y, &y)); 2260c0fd78eSBarry Smith } else { 2279566063dSJacob Faibussowitsch PetscCall(VecScale(Y, shell->vscale)); 2288fe8eb27SJed Brown } 2299566063dSJacob Faibussowitsch if (shell->vshift != 0.0) PetscCall(VecAXPY(Y, shell->vshift, X)); /* if test is for non-square matrices */ 2303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2318fe8eb27SJed Brown } 232e51e0e81SBarry Smith 233d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx) 234d71ae5a4SJacob Faibussowitsch { 235800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 236800f99ffSJeremy L Thompson 237789d8953SBarry Smith PetscFunctionBegin; 238800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx)); 239800f99ffSJeremy L Thompson else *(void **)ctx = NULL; 2403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 241789d8953SBarry Smith } 242789d8953SBarry Smith 2439d225801SJed Brown /*@ 24411a5261eSBarry Smith MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix. 245b4fd4287SBarry Smith 246c7fcc2eaSBarry Smith Not Collective 247c7fcc2eaSBarry Smith 248b4fd4287SBarry Smith Input Parameter: 24911a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()` 250b4fd4287SBarry Smith 251b4fd4287SBarry Smith Output Parameter: 252b4fd4287SBarry Smith . ctx - the user provided context 253b4fd4287SBarry Smith 25415091d37SBarry Smith Level: advanced 25515091d37SBarry Smith 256fe59aa6dSJacob Faibussowitsch Fortran Notes: 25727430b45SBarry Smith You must write a Fortran interface definition for this 258daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 259a62d957aSLois Curfman McInnes 2601cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()` 2610bc0a719SBarry Smith @*/ 262d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx) 263d71ae5a4SJacob Faibussowitsch { 2643a40ed3dSBarry Smith PetscFunctionBegin; 2650700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2664f572ea9SToby Isaac PetscAssertPointer(ctx, 2); 267cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx)); 2683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 269b4fd4287SBarry Smith } 270b4fd4287SBarry Smith 271d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc) 272d71ae5a4SJacob Faibussowitsch { 27345960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 27445960306SStefano Zampini Vec x = NULL, b = NULL; 27545960306SStefano Zampini IS is1, is2; 27645960306SStefano Zampini const PetscInt *ridxs; 27745960306SStefano Zampini PetscInt *idxs, *gidxs; 27845960306SStefano Zampini PetscInt cum, rst, cst, i; 27945960306SStefano Zampini 28045960306SStefano Zampini PetscFunctionBegin; 28148a46eb9SPierre Jolivet if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals)); 28248a46eb9SPierre Jolivet if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w)); 2839566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &rst, NULL)); 2849566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL)); 28545960306SStefano Zampini 28645960306SStefano Zampini /* Expand/create index set of zeroed rows */ 2879566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &idxs)); 28845960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 2899566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1)); 2909566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 2919566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals, is1, diag)); 29245960306SStefano Zampini if (shell->zrows) { 2939566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows, is1, &is2)); 2949566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 2959566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 29645960306SStefano Zampini shell->zrows = is2; 29745960306SStefano Zampini } else shell->zrows = is1; 29845960306SStefano Zampini 29945960306SStefano Zampini /* Create scatters for diagonal values communications */ 3009566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 3019566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 30245960306SStefano Zampini 30345960306SStefano Zampini /* row scatter: from/to left vector */ 3049566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &b)); 3059566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r)); 30645960306SStefano Zampini 30745960306SStefano Zampini /* col scatter: from right vector to left vector */ 3089566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows, &ridxs)); 3099566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows, &nr)); 3109566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &gidxs)); 31145960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 31245960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 31345960306SStefano Zampini gidxs[cum] = ridxs[i]; 31445960306SStefano Zampini cum++; 31545960306SStefano Zampini } 3169566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1)); 3179566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c)); 3189566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 3199566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 3209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 32145960306SStefano Zampini 32245960306SStefano Zampini /* Expand/create index set of zeroed columns */ 32345960306SStefano Zampini if (rc) { 3249566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &idxs)); 32545960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 3269566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1)); 3279566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 32845960306SStefano Zampini if (shell->zcols) { 3299566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols, is1, &is2)); 3309566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3319566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 33245960306SStefano Zampini shell->zcols = is2; 33345960306SStefano Zampini } else shell->zcols = is1; 33445960306SStefano Zampini } 3353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 33645960306SStefano Zampini } 33745960306SStefano Zampini 338d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 339d71ae5a4SJacob Faibussowitsch { 340ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 34145960306SStefano Zampini PetscInt nr, *lrows; 34245960306SStefano Zampini 34345960306SStefano Zampini PetscFunctionBegin; 34445960306SStefano Zampini if (x && b) { 34545960306SStefano Zampini Vec xt; 34645960306SStefano Zampini PetscScalar *vals; 34745960306SStefano Zampini PetscInt *gcols, i, st, nl, nc; 34845960306SStefano Zampini 3499566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &gcols)); 3509371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3519371c9d4SSatish Balay if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 35245960306SStefano Zampini 3539566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, NULL)); 3549566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3559566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc, &vals)); 3569566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3579566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3589566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3599566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3609566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */ 36145960306SStefano Zampini 3629566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3639566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3649566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 36545960306SStefano Zampini for (i = 0; i < nl; i++) { 36645960306SStefano Zampini PetscInt g = i + st; 36745960306SStefano Zampini if (g > mat->rmap->N) continue; 36845960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 3699566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES)); 37045960306SStefano Zampini } 3719566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 3729566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 3739566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 3749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 3759566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 37645960306SStefano Zampini } 3779566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL)); 3789566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE)); 3791baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL)); 3809566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 3813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 38245960306SStefano Zampini } 38345960306SStefano Zampini 384d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b) 385d71ae5a4SJacob Faibussowitsch { 386ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 38745960306SStefano Zampini PetscInt *lrows, *lcols; 38845960306SStefano Zampini PetscInt nr, nc; 38945960306SStefano Zampini PetscBool congruent; 39045960306SStefano Zampini 39145960306SStefano Zampini PetscFunctionBegin; 39245960306SStefano Zampini if (x && b) { 39345960306SStefano Zampini Vec xt, bt; 39445960306SStefano Zampini PetscScalar *vals; 39545960306SStefano Zampini PetscInt *grows, *gcols, i, st, nl; 39645960306SStefano Zampini 3979566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &grows, n, &gcols)); 3989371c9d4SSatish Balay for (i = 0, nr = 0; i < n; i++) 3999371c9d4SSatish Balay if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 4009371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 4019371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 4029566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n, &vals)); 40345960306SStefano Zampini 4049566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, &bt)); 4059566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 4069566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 4079566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 4089566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 4099566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt, -1.0, x)); /* xt = [0, -x2] */ 4109566063dSJacob Faibussowitsch PetscCall(MatMult(mat, xt, bt)); /* bt = [-A12*x2,-A22*x2] */ 4119566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */ 4129566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4139566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4149566063dSJacob Faibussowitsch PetscCall(VecAXPY(b, 1.0, bt)); /* b = [b1 - A12*x2, b2] */ 4159566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 4169566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4179566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4189566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 41945960306SStefano Zampini 4209566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 4219566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 4229566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 42345960306SStefano Zampini for (i = 0; i < nl; i++) { 42445960306SStefano Zampini PetscInt g = i + st; 42545960306SStefano Zampini if (g > mat->rmap->N) continue; 42645960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4279566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES)); 42845960306SStefano Zampini } 4299566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4309566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4319566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4329566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4349566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows, gcols)); 43545960306SStefano Zampini } 4369566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL)); 4379566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat, &congruent)); 43845960306SStefano Zampini if (congruent) { 43945960306SStefano Zampini nc = nr; 44045960306SStefano Zampini lcols = lrows; 44145960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 44245960306SStefano Zampini PetscInt i, nt, *t; 44345960306SStefano Zampini 4449566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &t)); 4459371c9d4SSatish Balay for (i = 0, nt = 0; i < n; i++) 4469371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4479566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL)); 4489566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 44945960306SStefano Zampini } 4509566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE)); 45148a46eb9SPierre Jolivet if (!congruent) PetscCall(PetscFree(lcols)); 4529566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4531baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL)); 4543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 45545960306SStefano Zampini } 45645960306SStefano Zampini 457d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat) 458d71ae5a4SJacob Faibussowitsch { 459bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell *)mat->data; 460b77ba244SStefano Zampini MatShellMatFunctionList matmat; 461ed3cc1f0SBarry Smith 4623a40ed3dSBarry Smith PetscFunctionBegin; 4631baa6e33SBarry Smith if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat)); 4649566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps))); 4659566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4669566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4679566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 4689566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 4699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 4709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 4719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 4729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 4739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 4749566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 4759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 4769566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 4779566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 4789566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 4799566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 4809566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 481b77ba244SStefano Zampini 482b77ba244SStefano Zampini matmat = shell->matmat; 483b77ba244SStefano Zampini while (matmat) { 484b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 485b77ba244SStefano Zampini 4869566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL)); 4879566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 4889566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 4899566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 490b77ba244SStefano Zampini matmat = next; 491b77ba244SStefano Zampini } 492800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(mat, NULL)); 4939566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL)); 4949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 495800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL)); 4969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL)); 4979566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL)); 4989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL)); 4999566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL)); 5009566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL)); 5019566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 5023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 503b77ba244SStefano Zampini } 504b77ba244SStefano Zampini 505b77ba244SStefano Zampini typedef struct { 506b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 507b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 508b77ba244SStefano Zampini void *userdata; 509b77ba244SStefano Zampini Mat B; 510b77ba244SStefano Zampini Mat Bt; 511b77ba244SStefano Zampini Mat axpy; 512b77ba244SStefano Zampini } MatMatDataShell; 513b77ba244SStefano Zampini 514d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data) 515d71ae5a4SJacob Faibussowitsch { 516b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 517b77ba244SStefano Zampini 518b77ba244SStefano Zampini PetscFunctionBegin; 5191baa6e33SBarry Smith if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata)); 5209566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 5219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 5229566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 5239566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 5243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 525b77ba244SStefano Zampini } 526b77ba244SStefano Zampini 527d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 528d71ae5a4SJacob Faibussowitsch { 529b77ba244SStefano Zampini Mat_Product *product; 530b77ba244SStefano Zampini Mat A, B; 531b77ba244SStefano Zampini MatMatDataShell *mdata; 532b77ba244SStefano Zampini PetscScalar zero = 0.0; 533b77ba244SStefano Zampini 534b77ba244SStefano Zampini PetscFunctionBegin; 535b77ba244SStefano Zampini MatCheckProduct(D, 1); 536b77ba244SStefano Zampini product = D->product; 53728b400f6SJacob Faibussowitsch PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty"); 538b77ba244SStefano Zampini A = product->A; 539b77ba244SStefano Zampini B = product->B; 540b77ba244SStefano Zampini mdata = (MatMatDataShell *)product->data; 541b77ba244SStefano Zampini if (mdata->numeric) { 542b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 543b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 544b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 545b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 546b77ba244SStefano Zampini 547b77ba244SStefano Zampini if (shell->managescalingshifts) { 54808401ef6SPierre Jolivet PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns"); 549b77ba244SStefano Zampini if (shell->right || shell->left) { 550b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 551b77ba244SStefano Zampini if (!mdata->B) { 5529566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B)); 553b77ba244SStefano Zampini } else { 554b77ba244SStefano Zampini newB = PETSC_FALSE; 555b77ba244SStefano Zampini } 5569566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN)); 557b77ba244SStefano Zampini } 558b77ba244SStefano Zampini switch (product->type) { 559b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 5601baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 561b77ba244SStefano Zampini break; 562b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 5631baa6e33SBarry Smith if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL)); 564b77ba244SStefano Zampini break; 565b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 5661baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 567b77ba244SStefano Zampini break; 568b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 569b77ba244SStefano Zampini if (shell->right && shell->left) { 570b77ba244SStefano Zampini PetscBool flg; 571b77ba244SStefano Zampini 5729566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5739371c9d4SSatish 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, 5749371c9d4SSatish Balay ((PetscObject)B)->type_name); 575b77ba244SStefano Zampini } 5761baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 577b77ba244SStefano Zampini break; 578b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 579b77ba244SStefano Zampini if (shell->right && shell->left) { 580b77ba244SStefano Zampini PetscBool flg; 581b77ba244SStefano Zampini 5829566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5839371c9d4SSatish 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, 5849371c9d4SSatish Balay ((PetscObject)B)->type_name); 585b77ba244SStefano Zampini } 5861baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 587b77ba244SStefano Zampini break; 588d71ae5a4SJacob Faibussowitsch default: 589d71ae5a4SJacob 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); 590b77ba244SStefano Zampini } 591b77ba244SStefano Zampini } 592b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 593b77ba244SStefano Zampini D->product = NULL; 594b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 595b77ba244SStefano Zampini D->ops->productnumeric = NULL; 596b77ba244SStefano Zampini 5979566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata)); 598b77ba244SStefano Zampini 599b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 6009566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 601b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 602b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 603b77ba244SStefano Zampini D->product = product; 604b77ba244SStefano Zampini 605b77ba244SStefano Zampini if (shell->managescalingshifts) { 6069566063dSJacob Faibussowitsch PetscCall(MatScale(D, shell->vscale)); 607b77ba244SStefano Zampini switch (product->type) { 608b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 609b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 610b77ba244SStefano Zampini if (shell->left) { 6119566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->left, NULL)); 612b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 6139566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 614b77ba244SStefano Zampini if (shell->dshift) { 6159566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->left_work)); 6169566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work, shell->vshift)); 6179566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left)); 618b77ba244SStefano Zampini } else { 6199566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work, shell->vshift)); 620b77ba244SStefano Zampini } 621b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 622b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 623b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 624b77ba244SStefano Zampini 6259566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt)); 6269566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL)); 6279566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->Bt, str)); 628b77ba244SStefano Zampini } else { 629b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 630b77ba244SStefano Zampini 6319566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL)); 6329566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 633b77ba244SStefano Zampini } 634b77ba244SStefano Zampini } 635b77ba244SStefano Zampini } 636b77ba244SStefano Zampini break; 637b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 638b77ba244SStefano Zampini if (shell->right) { 6399566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->right, NULL)); 640b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 641b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 642b77ba244SStefano Zampini 6439566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 644b77ba244SStefano Zampini if (shell->dshift) { 6459566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->right_work)); 6469566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work, shell->vshift)); 6479566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right)); 648b77ba244SStefano Zampini } else { 6499566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work, shell->vshift)); 650b77ba244SStefano Zampini } 6519566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL)); 6529566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 653b77ba244SStefano Zampini } 654b77ba244SStefano Zampini } 655b77ba244SStefano Zampini break; 656b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 657b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6589371c9d4SSatish 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, 6599371c9d4SSatish Balay ((PetscObject)B)->type_name); 660b77ba244SStefano Zampini break; 661d71ae5a4SJacob Faibussowitsch default: 662d71ae5a4SJacob 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); 663b77ba244SStefano Zampini } 664b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 665b77ba244SStefano Zampini Mat X; 666b77ba244SStefano Zampini PetscObjectState axpy_state; 667b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 668b77ba244SStefano Zampini 6699566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 6709566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 67108401ef6SPierre 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,...)"); 672b77ba244SStefano Zampini if (!mdata->axpy) { 673b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6749566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy)); 6759566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy, product->type)); 6769566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6779566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 678b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 679b77ba244SStefano Zampini PetscBool flg; 680b77ba244SStefano Zampini 6819566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy)); 6829566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg)); 683b77ba244SStefano Zampini if (!flg) { 684b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6859566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6869566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 687b77ba244SStefano Zampini } 688b77ba244SStefano Zampini } 6899566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 6909566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str)); 691b77ba244SStefano Zampini } 692b77ba244SStefano Zampini } 693b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation"); 6943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 695b77ba244SStefano Zampini } 696b77ba244SStefano Zampini 697d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 698d71ae5a4SJacob Faibussowitsch { 699b77ba244SStefano Zampini Mat_Product *product; 700b77ba244SStefano Zampini Mat A, B; 701b77ba244SStefano Zampini MatShellMatFunctionList matmat; 702b77ba244SStefano Zampini Mat_Shell *shell; 703eae3dc7dSJacob Faibussowitsch PetscBool flg = PETSC_FALSE; 704b77ba244SStefano Zampini char composedname[256]; 705b77ba244SStefano Zampini MatMatDataShell *mdata; 706b77ba244SStefano Zampini 707b77ba244SStefano Zampini PetscFunctionBegin; 708b77ba244SStefano Zampini MatCheckProduct(D, 1); 709b77ba244SStefano Zampini product = D->product; 71028b400f6SJacob Faibussowitsch PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty"); 711b77ba244SStefano Zampini A = product->A; 712b77ba244SStefano Zampini B = product->B; 713b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 714b77ba244SStefano Zampini matmat = shell->matmat; 7159566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 716b77ba244SStefano Zampini while (matmat) { 7179566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 718b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 719b77ba244SStefano Zampini if (flg) break; 720b77ba244SStefano Zampini matmat = matmat->next; 721b77ba244SStefano Zampini } 72228b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]); 723b77ba244SStefano Zampini switch (product->type) { 724d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AB: 725d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); 726d71ae5a4SJacob Faibussowitsch break; 727d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AtB: 728d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); 729d71ae5a4SJacob Faibussowitsch break; 730d71ae5a4SJacob Faibussowitsch case MATPRODUCT_ABt: 731d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N)); 732d71ae5a4SJacob Faibussowitsch break; 733d71ae5a4SJacob Faibussowitsch case MATPRODUCT_RARt: 734d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N)); 735d71ae5a4SJacob Faibussowitsch break; 736d71ae5a4SJacob Faibussowitsch case MATPRODUCT_PtAP: 737d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N)); 738d71ae5a4SJacob Faibussowitsch break; 739d71ae5a4SJacob Faibussowitsch default: 740d71ae5a4SJacob 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); 741b77ba244SStefano Zampini } 742b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 743b77ba244SStefano Zampini if (matmat->resultname) { 7449566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg)); 74548a46eb9SPierre Jolivet if (!flg) PetscCall(MatSetType(D, matmat->resultname)); 746b77ba244SStefano Zampini } 747b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 748b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 749b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 750b77ba244SStefano Zampini /* attach product data */ 7519566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 752b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 753b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 754b77ba244SStefano Zampini if (matmat->symbolic) { 7559566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata)); 756b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7579566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 758b77ba244SStefano Zampini } 75928b400f6SJacob Faibussowitsch PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase"); 76028b400f6SJacob Faibussowitsch PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase"); 761b77ba244SStefano Zampini D->product->data = mdata; 762b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 763b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 764b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 765b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 7663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 767b77ba244SStefano Zampini } 768b77ba244SStefano Zampini 769d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 770d71ae5a4SJacob Faibussowitsch { 771b77ba244SStefano Zampini Mat_Product *product; 772b77ba244SStefano Zampini Mat A, B; 773b77ba244SStefano Zampini MatShellMatFunctionList matmat; 774b77ba244SStefano Zampini Mat_Shell *shell; 775b77ba244SStefano Zampini PetscBool flg; 776b77ba244SStefano Zampini char composedname[256]; 777b77ba244SStefano Zampini 778b77ba244SStefano Zampini PetscFunctionBegin; 779b77ba244SStefano Zampini MatCheckProduct(D, 1); 780b77ba244SStefano Zampini product = D->product; 781b77ba244SStefano Zampini A = product->A; 782b77ba244SStefano Zampini B = product->B; 7839566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 7843ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 785b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 786b77ba244SStefano Zampini matmat = shell->matmat; 7879566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 788b77ba244SStefano Zampini while (matmat) { 7899566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 790b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 791b77ba244SStefano Zampini if (flg) break; 792b77ba244SStefano Zampini matmat = matmat->next; 793b77ba244SStefano Zampini } 7949371c9d4SSatish Balay if (flg) { 7959371c9d4SSatish Balay D->ops->productsymbolic = MatProductSymbolic_Shell_X; 7969371c9d4SSatish Balay } else PetscCall(PetscInfo(D, " symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type])); 7973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 798b77ba244SStefano Zampini } 799b77ba244SStefano Zampini 800d71ae5a4SJacob 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) 801d71ae5a4SJacob Faibussowitsch { 802b77ba244SStefano Zampini PetscBool flg; 803b77ba244SStefano Zampini Mat_Shell *shell; 804b77ba244SStefano Zampini MatShellMatFunctionList matmat; 805b77ba244SStefano Zampini 806b77ba244SStefano Zampini PetscFunctionBegin; 80728b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine"); 80828b400f6SJacob Faibussowitsch PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name"); 809b77ba244SStefano Zampini 810b77ba244SStefano Zampini /* add product callback */ 811b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 812b77ba244SStefano Zampini matmat = shell->matmat; 813b77ba244SStefano Zampini if (!matmat) { 8149566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 815b77ba244SStefano Zampini matmat = shell->matmat; 816b77ba244SStefano Zampini } else { 817b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 818b77ba244SStefano Zampini while (entry) { 8199566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, entry->composedname, &flg)); 820b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 821b77ba244SStefano Zampini matmat = entry; 8222e956fe4SStefano Zampini if (flg) goto set; 823b77ba244SStefano Zampini entry = entry->next; 824b77ba244SStefano Zampini } 8259566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 826b77ba244SStefano Zampini matmat = matmat->next; 827b77ba244SStefano Zampini } 828b77ba244SStefano Zampini 829843d480fSStefano Zampini set: 830b77ba244SStefano Zampini matmat->symbolic = symbolic; 831b77ba244SStefano Zampini matmat->numeric = numeric; 832b77ba244SStefano Zampini matmat->destroy = destroy; 833b77ba244SStefano Zampini matmat->ptype = ptype; 8349566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8359566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8369566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname, &matmat->composedname)); 8379566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname, &matmat->resultname)); 8389566063dSJacob 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")); 8399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X)); 8403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 841b77ba244SStefano Zampini } 842b77ba244SStefano Zampini 843b77ba244SStefano Zampini /*@C 84411a5261eSBarry Smith MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix. 845b77ba244SStefano Zampini 84627430b45SBarry Smith Logically Collective; No Fortran Support 847b77ba244SStefano Zampini 848b77ba244SStefano Zampini Input Parameters: 84911a5261eSBarry Smith + A - the `MATSHELL` shell matrix 850b77ba244SStefano Zampini . ptype - the product type 8512ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`) 852b77ba244SStefano Zampini . numeric - the function for the numerical phase 8532ef1f0ffSBarry Smith . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`) 854b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 8552ef1f0ffSBarry Smith - Ctype - the matrix type for the result (can be `NULL`) 856b77ba244SStefano Zampini 857b77ba244SStefano Zampini Level: advanced 858b77ba244SStefano Zampini 8592920cce0SJacob Faibussowitsch Example Usage: 860cf53795eSBarry Smith .vb 861cf53795eSBarry Smith extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**); 862cf53795eSBarry Smith extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*); 863cf53795eSBarry Smith extern PetscErrorCode userdestroy(void*); 8642920cce0SJacob Faibussowitsch 865cf53795eSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 8662920cce0SJacob Faibussowitsch MatShellSetMatProductOperation( 8672920cce0SJacob Faibussowitsch A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE 8682920cce0SJacob Faibussowitsch ); 8692920cce0SJacob Faibussowitsch // create B of type SEQAIJ etc.. 8702920cce0SJacob Faibussowitsch MatProductCreate(A, B, PETSC_NULLPTR, &C); 871cf53795eSBarry Smith MatProductSetType(C, MATPRODUCT_AB); 872cf53795eSBarry Smith MatProductSetFromOptions(C); 8732920cce0SJacob Faibussowitsch MatProductSymbolic(C); // actually runs the user defined symbolic operation 8742920cce0SJacob Faibussowitsch MatProductNumeric(C); // actually runs the user defined numeric operation 8752920cce0SJacob Faibussowitsch // use C = A * B 876cf53795eSBarry Smith .ve 877b77ba244SStefano Zampini 878b77ba244SStefano Zampini Notes: 879cf53795eSBarry Smith `MATPRODUCT_ABC` is not supported yet. 88011a5261eSBarry Smith 8812ef1f0ffSBarry 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`. 88211a5261eSBarry Smith 883b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 884b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 885b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 88627430b45SBarry Smith The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence. 887b77ba244SStefano Zampini 8881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()` 889b77ba244SStefano Zampini @*/ 890d71ae5a4SJacob 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) 891d71ae5a4SJacob Faibussowitsch { 892b77ba244SStefano Zampini PetscFunctionBegin; 893b77ba244SStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 894b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A, ptype, 2); 89508401ef6SPierre Jolivet PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]); 89628b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4"); 8974f572ea9SToby Isaac PetscAssertPointer(Btype, 6); 8984f572ea9SToby Isaac if (Ctype) PetscAssertPointer(Ctype, 7); 899cac4c232SBarry 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)); 9003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 901b77ba244SStefano Zampini } 902b77ba244SStefano Zampini 903d71ae5a4SJacob 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) 904d71ae5a4SJacob Faibussowitsch { 905b77ba244SStefano Zampini PetscBool flg; 906b77ba244SStefano Zampini char composedname[256]; 907b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 908b77ba244SStefano Zampini PetscMPIInt size; 909b77ba244SStefano Zampini 910b77ba244SStefano Zampini PetscFunctionBegin; 911b77ba244SStefano Zampini PetscValidType(A, 1); 912b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 9139566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg)); 914b77ba244SStefano Zampini if (flg) break; 915b77ba244SStefano Zampini Bnames = Bnames->next; 916b77ba244SStefano Zampini } 917b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 9189566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg)); 919b77ba244SStefano Zampini if (flg) break; 920b77ba244SStefano Zampini Cnames = Cnames->next; 921b77ba244SStefano Zampini } 9229566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 923b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 924b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9259566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype)); 9269566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype)); 9273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 928e51e0e81SBarry Smith } 929e51e0e81SBarry Smith 930d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str) 931d71ae5a4SJacob Faibussowitsch { 93228f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data; 933cb8c8a77SBarry Smith PetscBool matflg; 934b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9357fabda3fSAlex Fikl 9367fabda3fSAlex Fikl PetscFunctionBegin; 9379566063dSJacob Faibussowitsch PetscCall(MatIsShell(B, &matflg)); 93828b400f6SJacob Faibussowitsch PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name); 9397fabda3fSAlex Fikl 940aea10558SJacob Faibussowitsch B->ops[0] = A->ops[0]; 941aea10558SJacob Faibussowitsch shellB->ops[0] = shellA->ops[0]; 9427fabda3fSAlex Fikl 9431baa6e33SBarry Smith if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str)); 9447fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9457fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9460c0fd78eSBarry Smith if (shellA->dshift) { 94748a46eb9SPierre Jolivet if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift)); 9489566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift, shellB->dshift)); 9497fabda3fSAlex Fikl } else { 9509566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9517fabda3fSAlex Fikl } 9520c0fd78eSBarry Smith if (shellA->left) { 95348a46eb9SPierre Jolivet if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left)); 9549566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left, shellB->left)); 9557fabda3fSAlex Fikl } else { 9569566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9577fabda3fSAlex Fikl } 9580c0fd78eSBarry Smith if (shellA->right) { 95948a46eb9SPierre Jolivet if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right)); 9609566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right, shellB->right)); 9617fabda3fSAlex Fikl } else { 9629566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9637fabda3fSAlex Fikl } 9649566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 965ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 966ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 96740e381c3SBarry Smith if (shellA->axpy) { 9689566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 96940e381c3SBarry Smith shellB->axpy = shellA->axpy; 97040e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 971ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 97240e381c3SBarry Smith } 97345960306SStefano Zampini if (shellA->zrows) { 9749566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows)); 97548a46eb9SPierre Jolivet if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols)); 9769566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals)); 9779566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals, shellB->zvals)); 9789566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w)); 9799566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 9809566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 98145960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 98245960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 98345960306SStefano Zampini } 984b77ba244SStefano Zampini 985b77ba244SStefano Zampini matmatA = shellA->matmat; 986b77ba244SStefano Zampini if (matmatA) { 987b77ba244SStefano Zampini while (matmatA->next) { 9889566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname)); 989b77ba244SStefano Zampini matmatA = matmatA->next; 990b77ba244SStefano Zampini } 991b77ba244SStefano Zampini } 9923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 9937fabda3fSAlex Fikl } 9947fabda3fSAlex Fikl 995d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M) 996d71ae5a4SJacob Faibussowitsch { 997cb8c8a77SBarry Smith PetscFunctionBegin; 998800f99ffSJeremy L Thompson PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M)); 999800f99ffSJeremy L Thompson ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer; 1000800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer)); 10019566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name)); 100248a46eb9SPierre Jolivet if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN)); 1003*01f93aa2SJose E. Roman PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M)); 10043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1005cb8c8a77SBarry Smith } 1006cb8c8a77SBarry Smith 100766976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y) 1008d71ae5a4SJacob Faibussowitsch { 1009ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 101025578ef6SJed Brown Vec xx; 1011e3f487b0SBarry Smith PetscObjectState instate, outstate; 1012ef66eb69SBarry Smith 1013ef66eb69SBarry Smith PetscFunctionBegin; 10149566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A, x, &xx)); 10159566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A, xx, &xx)); 10169566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10179566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A, xx, y)); 10189566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1019e3f487b0SBarry Smith if (instate == outstate) { 1020e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10219566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1022e3f487b0SBarry Smith } 10239566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A, xx, y)); 10249566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A, y)); 10259566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A, y)); 10269f137db4SBarry Smith 10279f137db4SBarry Smith if (shell->axpy) { 1028ef5c7bd2SStefano Zampini Mat X; 1029ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1030ef5c7bd2SStefano Zampini 10319566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10329566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 103308401ef6SPierre 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,...)"); 1034b77ba244SStefano Zampini 10359566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10369566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_right)); 10379566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left)); 10389566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left)); 10399f137db4SBarry Smith } 10403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1041ef66eb69SBarry Smith } 1042ef66eb69SBarry Smith 1043d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1044d71ae5a4SJacob Faibussowitsch { 10455edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10465edf6516SJed Brown 10475edf6516SJed Brown PetscFunctionBegin; 10485edf6516SJed Brown if (y == z) { 10499566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work)); 10509566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, shell->right_add_work)); 10519566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->right_add_work)); 10525edf6516SJed Brown } else { 10539566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, z)); 10549566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 10555edf6516SJed Brown } 10563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10575edf6516SJed Brown } 10585edf6516SJed Brown 1059d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y) 1060d71ae5a4SJacob Faibussowitsch { 106118be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 106225578ef6SJed Brown Vec xx; 1063e3f487b0SBarry Smith PetscObjectState instate, outstate; 106418be62a5SSatish Balay 106518be62a5SSatish Balay PetscFunctionBegin; 10669566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A, x, &xx)); 10679566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleLeft(A, xx, &xx)); 10689566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10699566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A, xx, y)); 10709566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1071e3f487b0SBarry Smith if (instate == outstate) { 1072e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10739566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1074e3f487b0SBarry Smith } 10759566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A, xx, y)); 10769566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleRight(A, y)); 10779566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A, y)); 1078350ec83bSStefano Zampini 1079350ec83bSStefano Zampini if (shell->axpy) { 1080ef5c7bd2SStefano Zampini Mat X; 1081ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1082ef5c7bd2SStefano Zampini 10839566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10849566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 108508401ef6SPierre 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,...)"); 10869566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10879566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_left)); 10889566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 10899566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right)); 1090350ec83bSStefano Zampini } 10913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 109218be62a5SSatish Balay } 109318be62a5SSatish Balay 1094d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1095d71ae5a4SJacob Faibussowitsch { 10965edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10975edf6516SJed Brown 10985edf6516SJed Brown PetscFunctionBegin; 10995edf6516SJed Brown if (y == z) { 11009566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 11019566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, shell->left_add_work)); 11029566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 11035edf6516SJed Brown } else { 11049566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, z)); 11059566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 11065edf6516SJed Brown } 11073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11085edf6516SJed Brown } 11095edf6516SJed Brown 11100c0fd78eSBarry Smith /* 11110c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11120c0fd78eSBarry Smith */ 1113d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v) 1114d71ae5a4SJacob Faibussowitsch { 111518be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 111618be62a5SSatish Balay 111718be62a5SSatish Balay PetscFunctionBegin; 11180c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 11199566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A, v)); 1120305211d5SBarry 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,...)"); 11219566063dSJacob Faibussowitsch PetscCall(VecScale(v, shell->vscale)); 11221baa6e33SBarry Smith if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift)); 11239566063dSJacob Faibussowitsch PetscCall(VecShift(v, shell->vshift)); 11249566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left)); 11259566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right)); 112645960306SStefano Zampini if (shell->zrows) { 11279566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 11289566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 112945960306SStefano Zampini } 113081c02519SBarry Smith if (shell->axpy) { 1131ef5c7bd2SStefano Zampini Mat X; 1132ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1133ef5c7bd2SStefano Zampini 11349566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 11359566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 113608401ef6SPierre 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,...)"); 11379566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left)); 11389566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left)); 11399566063dSJacob Faibussowitsch PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left)); 114081c02519SBarry Smith } 11413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 114218be62a5SSatish Balay } 114318be62a5SSatish Balay 1144d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a) 1145d71ae5a4SJacob Faibussowitsch { 1146ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1147789d8953SBarry Smith PetscBool flg; 1148b24ad042SBarry Smith 1149ef66eb69SBarry Smith PetscFunctionBegin; 11509566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y, &flg)); 115128b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent"); 11520c0fd78eSBarry Smith if (shell->left || shell->right) { 11538fe8eb27SJed Brown if (!shell->dshift) { 11549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 11559566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift, a)); 11560c0fd78eSBarry Smith } else { 11579566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left)); 11589566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right)); 11599566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift, a)); 11600c0fd78eSBarry Smith } 11619566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left)); 11629566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right)); 11638fe8eb27SJed Brown } else shell->vshift += a; 11641baa6e33SBarry Smith if (shell->zrows) PetscCall(VecShift(shell->zvals, a)); 11653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1166ef66eb69SBarry Smith } 1167ef66eb69SBarry Smith 1168d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s) 1169d71ae5a4SJacob Faibussowitsch { 11706464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell *)A->data; 11716464bf51SAlex Fikl 11726464bf51SAlex Fikl PetscFunctionBegin; 11739566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift)); 11740c0fd78eSBarry Smith if (shell->left || shell->right) { 11759566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 11769f137db4SBarry Smith if (shell->left && shell->right) { 11779566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 11789566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right)); 11799f137db4SBarry Smith } else if (shell->left) { 11809566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 11819f137db4SBarry Smith } else { 11829566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right)); 11839f137db4SBarry Smith } 11849566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, shell->right_work)); 11850c0fd78eSBarry Smith } else { 11869566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, D)); 1187b253ae0bS“Marek } 11883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1189b253ae0bS“Marek } 1190b253ae0bS“Marek 119166976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins) 1192d71ae5a4SJacob Faibussowitsch { 119345960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1194b253ae0bS“Marek Vec d; 1195789d8953SBarry Smith PetscBool flg; 1196b253ae0bS“Marek 1197b253ae0bS“Marek PetscFunctionBegin; 11989566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &flg)); 119928b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent"); 1200b253ae0bS“Marek if (ins == INSERT_VALUES) { 12019566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D, &d)); 12029566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A, d)); 12039566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.)); 12049566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 12061baa6e33SBarry Smith if (shell->zrows) PetscCall(VecCopy(D, shell->zvals)); 1207b253ae0bS“Marek } else { 12089566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12091baa6e33SBarry Smith if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D)); 12106464bf51SAlex Fikl } 12113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12126464bf51SAlex Fikl } 12136464bf51SAlex Fikl 1214d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a) 1215d71ae5a4SJacob Faibussowitsch { 1216ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1217b24ad042SBarry Smith 1218ef66eb69SBarry Smith PetscFunctionBegin; 1219f4df32b1SMatthew Knepley shell->vscale *= a; 12200c0fd78eSBarry Smith shell->vshift *= a; 12211baa6e33SBarry Smith if (shell->dshift) PetscCall(VecScale(shell->dshift, a)); 122281c02519SBarry Smith shell->axpy_vscale *= a; 12231baa6e33SBarry Smith if (shell->zrows) PetscCall(VecScale(shell->zvals, a)); 12243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 122518be62a5SSatish Balay } 12268fe8eb27SJed Brown 1227d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right) 1228d71ae5a4SJacob Faibussowitsch { 12298fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)Y->data; 12308fe8eb27SJed Brown 12318fe8eb27SJed Brown PetscFunctionBegin; 12328fe8eb27SJed Brown if (left) { 12330c0fd78eSBarry Smith if (!shell->left) { 12349566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left, &shell->left)); 12359566063dSJacob Faibussowitsch PetscCall(VecCopy(left, shell->left)); 12360c0fd78eSBarry Smith } else { 12379566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left, shell->left, left)); 123818be62a5SSatish Balay } 12391baa6e33SBarry Smith if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left)); 1240ef66eb69SBarry Smith } 12418fe8eb27SJed Brown if (right) { 12420c0fd78eSBarry Smith if (!shell->right) { 12439566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right, &shell->right)); 12449566063dSJacob Faibussowitsch PetscCall(VecCopy(right, shell->right)); 12450c0fd78eSBarry Smith } else { 12469566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right, shell->right, right)); 12478fe8eb27SJed Brown } 124845960306SStefano Zampini if (shell->zrows) { 124948a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work)); 12509566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 1.0)); 12519566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12529566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12539566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w)); 125445960306SStefano Zampini } 12558fe8eb27SJed Brown } 12561baa6e33SBarry Smith if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right)); 12573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1258ef66eb69SBarry Smith } 1259ef66eb69SBarry Smith 126066976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t) 1261d71ae5a4SJacob Faibussowitsch { 1262ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1263ef66eb69SBarry Smith 1264ef66eb69SBarry Smith PetscFunctionBegin; 12658fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1266ef66eb69SBarry Smith shell->vshift = 0.0; 1267ef66eb69SBarry Smith shell->vscale = 1.0; 1268ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1269ef5c7bd2SStefano Zampini shell->axpy_state = 0; 12709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 12719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 12729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 12739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 12749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 12759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 12769566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 12779566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 12789566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 12799566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1280ef66eb69SBarry Smith } 12813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1282ef66eb69SBarry Smith } 1283ef66eb69SBarry Smith 1284d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d) 1285d71ae5a4SJacob Faibussowitsch { 12863b49f96aSBarry Smith PetscFunctionBegin; 12873b49f96aSBarry Smith *missing = PETSC_FALSE; 12883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12893b49f96aSBarry Smith } 12903b49f96aSBarry Smith 129166976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str) 1292d71ae5a4SJacob Faibussowitsch { 12939f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 12949f137db4SBarry Smith 12959f137db4SBarry Smith PetscFunctionBegin; 1296ef5c7bd2SStefano Zampini if (X == Y) { 12979566063dSJacob Faibussowitsch PetscCall(MatScale(Y, 1.0 + a)); 12983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1299ef5c7bd2SStefano Zampini } 1300ef5c7bd2SStefano Zampini if (!shell->axpy) { 13019566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy)); 13029f137db4SBarry Smith shell->axpy_vscale = a; 13039566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state)); 1304ef5c7bd2SStefano Zampini } else { 13059566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str)); 1306ef5c7bd2SStefano Zampini } 13073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13089f137db4SBarry Smith } 13099f137db4SBarry Smith 1310f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1311f4259b30SLisandro Dalcin NULL, 1312f4259b30SLisandro Dalcin NULL, 1313f4259b30SLisandro Dalcin NULL, 13140c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1315f4259b30SLisandro Dalcin NULL, 13160c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1317f4259b30SLisandro Dalcin NULL, 1318f4259b30SLisandro Dalcin NULL, 1319f4259b30SLisandro Dalcin NULL, 1320f4259b30SLisandro Dalcin /*10*/ NULL, 1321f4259b30SLisandro Dalcin NULL, 1322f4259b30SLisandro Dalcin NULL, 1323f4259b30SLisandro Dalcin NULL, 1324f4259b30SLisandro Dalcin NULL, 1325f4259b30SLisandro Dalcin /*15*/ NULL, 1326f4259b30SLisandro Dalcin NULL, 1327f4259b30SLisandro Dalcin NULL, 13288fe8eb27SJed Brown MatDiagonalScale_Shell, 1329f4259b30SLisandro Dalcin NULL, 1330f4259b30SLisandro Dalcin /*20*/ NULL, 1331ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1332f4259b30SLisandro Dalcin NULL, 1333f4259b30SLisandro Dalcin NULL, 133445960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1335f4259b30SLisandro Dalcin NULL, 1336f4259b30SLisandro Dalcin NULL, 1337f4259b30SLisandro Dalcin NULL, 1338f4259b30SLisandro Dalcin NULL, 1339f4259b30SLisandro Dalcin /*29*/ NULL, 1340f4259b30SLisandro Dalcin NULL, 1341f4259b30SLisandro Dalcin NULL, 1342f4259b30SLisandro Dalcin NULL, 1343f4259b30SLisandro Dalcin NULL, 1344cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1345f4259b30SLisandro Dalcin NULL, 1346f4259b30SLisandro Dalcin NULL, 1347f4259b30SLisandro Dalcin NULL, 1348f4259b30SLisandro Dalcin NULL, 13499f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1350f4259b30SLisandro Dalcin NULL, 1351f4259b30SLisandro Dalcin NULL, 1352f4259b30SLisandro Dalcin NULL, 1353cb8c8a77SBarry Smith MatCopy_Shell, 1354f4259b30SLisandro Dalcin /*44*/ NULL, 1355ef66eb69SBarry Smith MatScale_Shell, 1356ef66eb69SBarry Smith MatShift_Shell, 13576464bf51SAlex Fikl MatDiagonalSet_Shell, 135845960306SStefano Zampini MatZeroRowsColumns_Shell, 1359f4259b30SLisandro Dalcin /*49*/ NULL, 1360f4259b30SLisandro Dalcin NULL, 1361f4259b30SLisandro Dalcin NULL, 1362f4259b30SLisandro Dalcin NULL, 1363f4259b30SLisandro Dalcin NULL, 1364f4259b30SLisandro Dalcin /*54*/ NULL, 1365f4259b30SLisandro Dalcin NULL, 1366f4259b30SLisandro Dalcin NULL, 1367f4259b30SLisandro Dalcin NULL, 1368f4259b30SLisandro Dalcin NULL, 1369f4259b30SLisandro Dalcin /*59*/ NULL, 1370b9b97703SBarry Smith MatDestroy_Shell, 1371f4259b30SLisandro Dalcin NULL, 1372251fad3fSStefano Zampini MatConvertFrom_Shell, 1373f4259b30SLisandro Dalcin NULL, 1374f4259b30SLisandro Dalcin /*64*/ NULL, 1375f4259b30SLisandro Dalcin NULL, 1376f4259b30SLisandro Dalcin NULL, 1377f4259b30SLisandro Dalcin NULL, 1378f4259b30SLisandro Dalcin NULL, 1379f4259b30SLisandro Dalcin /*69*/ NULL, 1380f4259b30SLisandro Dalcin NULL, 1381c87e5d42SMatthew Knepley MatConvert_Shell, 1382f4259b30SLisandro Dalcin NULL, 1383f4259b30SLisandro Dalcin NULL, 1384f4259b30SLisandro Dalcin /*74*/ NULL, 1385f4259b30SLisandro Dalcin NULL, 1386f4259b30SLisandro Dalcin NULL, 1387f4259b30SLisandro Dalcin NULL, 1388f4259b30SLisandro Dalcin NULL, 1389f4259b30SLisandro Dalcin /*79*/ NULL, 1390f4259b30SLisandro Dalcin NULL, 1391f4259b30SLisandro Dalcin NULL, 1392f4259b30SLisandro Dalcin NULL, 1393f4259b30SLisandro Dalcin NULL, 1394f4259b30SLisandro Dalcin /*84*/ NULL, 1395f4259b30SLisandro Dalcin NULL, 1396f4259b30SLisandro Dalcin NULL, 1397f4259b30SLisandro Dalcin NULL, 1398f4259b30SLisandro Dalcin NULL, 1399f4259b30SLisandro Dalcin /*89*/ NULL, 1400f4259b30SLisandro Dalcin NULL, 1401f4259b30SLisandro Dalcin NULL, 1402f4259b30SLisandro Dalcin NULL, 1403f4259b30SLisandro Dalcin NULL, 1404f4259b30SLisandro Dalcin /*94*/ NULL, 1405f4259b30SLisandro Dalcin NULL, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin NULL, 1408f4259b30SLisandro Dalcin NULL, 1409f4259b30SLisandro Dalcin /*99*/ NULL, 1410f4259b30SLisandro Dalcin NULL, 1411f4259b30SLisandro Dalcin NULL, 1412f4259b30SLisandro Dalcin NULL, 1413f4259b30SLisandro Dalcin NULL, 1414f4259b30SLisandro Dalcin /*104*/ NULL, 1415f4259b30SLisandro Dalcin NULL, 1416f4259b30SLisandro Dalcin NULL, 1417f4259b30SLisandro Dalcin NULL, 1418f4259b30SLisandro Dalcin NULL, 1419f4259b30SLisandro Dalcin /*109*/ NULL, 1420f4259b30SLisandro Dalcin NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin NULL, 14233b49f96aSBarry Smith MatMissingDiagonal_Shell, 1424f4259b30SLisandro Dalcin /*114*/ NULL, 1425f4259b30SLisandro Dalcin NULL, 1426f4259b30SLisandro Dalcin NULL, 1427f4259b30SLisandro Dalcin NULL, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin /*119*/ NULL, 1430f4259b30SLisandro Dalcin NULL, 1431f4259b30SLisandro Dalcin NULL, 1432f4259b30SLisandro Dalcin NULL, 1433f4259b30SLisandro Dalcin NULL, 1434f4259b30SLisandro Dalcin /*124*/ NULL, 1435f4259b30SLisandro Dalcin NULL, 1436f4259b30SLisandro Dalcin NULL, 1437f4259b30SLisandro Dalcin NULL, 1438f4259b30SLisandro Dalcin NULL, 1439f4259b30SLisandro Dalcin /*129*/ NULL, 1440f4259b30SLisandro Dalcin NULL, 1441f4259b30SLisandro Dalcin NULL, 1442f4259b30SLisandro Dalcin NULL, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin /*134*/ NULL, 1445f4259b30SLisandro Dalcin NULL, 1446f4259b30SLisandro Dalcin NULL, 1447f4259b30SLisandro Dalcin NULL, 1448f4259b30SLisandro Dalcin NULL, 1449f4259b30SLisandro Dalcin /*139*/ NULL, 1450f4259b30SLisandro Dalcin NULL, 1451d70f29a3SPierre Jolivet NULL, 1452d70f29a3SPierre Jolivet NULL, 1453d70f29a3SPierre Jolivet NULL, 1454d70f29a3SPierre Jolivet /*144*/ NULL, 1455d70f29a3SPierre Jolivet NULL, 1456d70f29a3SPierre Jolivet NULL, 145799a7f59eSMark Adams NULL, 145899a7f59eSMark Adams NULL, 14597fb60732SBarry Smith NULL, 1460dec0b466SHong Zhang /*150*/ NULL, 1461dec0b466SHong Zhang NULL}; 1462273d9f13SBarry Smith 1463d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx) 1464d71ae5a4SJacob Faibussowitsch { 1465789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1466789d8953SBarry Smith 1467789d8953SBarry Smith PetscFunctionBegin; 1468800f99ffSJeremy L Thompson if (ctx) { 1469800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 1470800f99ffSJeremy L Thompson PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer)); 1471800f99ffSJeremy L Thompson PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 1472800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer)); 1473800f99ffSJeremy L Thompson shell->ctxcontainer = ctxcontainer; 1474800f99ffSJeremy L Thompson PetscCall(PetscContainerDestroy(&ctxcontainer)); 1475800f99ffSJeremy L Thompson } else { 1476800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL)); 1477800f99ffSJeremy L Thompson shell->ctxcontainer = NULL; 1478800f99ffSJeremy L Thompson } 1479800f99ffSJeremy L Thompson 14803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1481800f99ffSJeremy L Thompson } 1482800f99ffSJeremy L Thompson 148366976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *)) 1484d71ae5a4SJacob Faibussowitsch { 1485800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 1486800f99ffSJeremy L Thompson 1487800f99ffSJeremy L Thompson PetscFunctionBegin; 1488800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f)); 14893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1490789d8953SBarry Smith } 1491789d8953SBarry Smith 1492d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype) 1493d71ae5a4SJacob Faibussowitsch { 1494db77db73SJeremy L Thompson PetscFunctionBegin; 14959566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 14969566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype)); 14973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1498db77db73SJeremy L Thompson } 1499db77db73SJeremy L Thompson 150066976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1501d71ae5a4SJacob Faibussowitsch { 1502789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 1503789d8953SBarry Smith 1504789d8953SBarry Smith PetscFunctionBegin; 1505789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1506789d8953SBarry Smith A->ops->diagonalset = NULL; 1507789d8953SBarry Smith A->ops->diagonalscale = NULL; 1508789d8953SBarry Smith A->ops->scale = NULL; 1509789d8953SBarry Smith A->ops->shift = NULL; 1510789d8953SBarry Smith A->ops->axpy = NULL; 15113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1512789d8953SBarry Smith } 1513789d8953SBarry Smith 1514d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void)) 1515d71ae5a4SJacob Faibussowitsch { 1516feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell *)mat->data; 1517789d8953SBarry Smith 1518789d8953SBarry Smith PetscFunctionBegin; 1519789d8953SBarry Smith switch (op) { 1520d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1521d71ae5a4SJacob Faibussowitsch shell->ops->destroy = (PetscErrorCode(*)(Mat))f; 1522d71ae5a4SJacob Faibussowitsch break; 1523789d8953SBarry Smith case MATOP_VIEW: 1524ad540459SPierre Jolivet if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view; 1525789d8953SBarry Smith mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f; 1526789d8953SBarry Smith break; 1527d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1528d71ae5a4SJacob Faibussowitsch shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f; 1529d71ae5a4SJacob Faibussowitsch break; 1530789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1531789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1532789d8953SBarry Smith case MATOP_SHIFT: 1533789d8953SBarry Smith case MATOP_SCALE: 1534789d8953SBarry Smith case MATOP_AXPY: 1535789d8953SBarry Smith case MATOP_ZERO_ROWS: 1536789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 153728b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1538789d8953SBarry Smith (((void (**)(void))mat->ops)[op]) = f; 1539789d8953SBarry Smith break; 1540789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1541789d8953SBarry Smith if (shell->managescalingshifts) { 1542789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1543789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1544789d8953SBarry Smith } else { 1545789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1546789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1547789d8953SBarry Smith } 1548789d8953SBarry Smith break; 1549789d8953SBarry Smith case MATOP_MULT: 1550789d8953SBarry Smith if (shell->managescalingshifts) { 1551789d8953SBarry Smith shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1552789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1553789d8953SBarry Smith } else { 1554789d8953SBarry Smith shell->ops->mult = NULL; 1555789d8953SBarry Smith mat->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1556789d8953SBarry Smith } 1557789d8953SBarry Smith break; 1558789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1559789d8953SBarry Smith if (shell->managescalingshifts) { 1560789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1561789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1562789d8953SBarry Smith } else { 1563789d8953SBarry Smith shell->ops->multtranspose = NULL; 1564789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1565789d8953SBarry Smith } 1566789d8953SBarry Smith break; 1567d71ae5a4SJacob Faibussowitsch default: 1568d71ae5a4SJacob Faibussowitsch (((void (**)(void))mat->ops)[op]) = f; 1569d71ae5a4SJacob Faibussowitsch break; 1570789d8953SBarry Smith } 15713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1572789d8953SBarry Smith } 1573789d8953SBarry Smith 1574d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void)) 1575d71ae5a4SJacob Faibussowitsch { 1576789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1577789d8953SBarry Smith 1578789d8953SBarry Smith PetscFunctionBegin; 1579789d8953SBarry Smith switch (op) { 1580d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1581d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->destroy; 1582d71ae5a4SJacob Faibussowitsch break; 1583d71ae5a4SJacob Faibussowitsch case MATOP_VIEW: 1584d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))mat->ops->view; 1585d71ae5a4SJacob Faibussowitsch break; 1586d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1587d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->copy; 1588d71ae5a4SJacob Faibussowitsch break; 1589789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1590789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1591789d8953SBarry Smith case MATOP_SHIFT: 1592789d8953SBarry Smith case MATOP_SCALE: 1593789d8953SBarry Smith case MATOP_AXPY: 1594789d8953SBarry Smith case MATOP_ZERO_ROWS: 1595d71ae5a4SJacob Faibussowitsch case MATOP_ZERO_ROWS_COLUMNS: 1596d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1597d71ae5a4SJacob Faibussowitsch break; 1598789d8953SBarry Smith case MATOP_GET_DIAGONAL: 15999371c9d4SSatish Balay if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal; 16009371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1601789d8953SBarry Smith break; 1602789d8953SBarry Smith case MATOP_MULT: 16039371c9d4SSatish Balay if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult; 16049371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1605789d8953SBarry Smith break; 1606789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 16079371c9d4SSatish Balay if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose; 16089371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1609789d8953SBarry Smith break; 1610d71ae5a4SJacob Faibussowitsch default: 1611d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1612789d8953SBarry Smith } 16133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1614789d8953SBarry Smith } 1615789d8953SBarry Smith 16160bad9183SKris Buschelman /*MC 161701c1178eSBarry Smith MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free. 16180bad9183SKris Buschelman 16190bad9183SKris Buschelman Level: advanced 16200bad9183SKris Buschelman 16211cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()` 16220bad9183SKris Buschelman M*/ 16230bad9183SKris Buschelman 1624d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1625d71ae5a4SJacob Faibussowitsch { 1626273d9f13SBarry Smith Mat_Shell *b; 1627273d9f13SBarry Smith 1628273d9f13SBarry Smith PetscFunctionBegin; 16294dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&b)); 1630273d9f13SBarry Smith A->data = (void *)b; 1631aea10558SJacob Faibussowitsch A->ops[0] = MatOps_Values; 1632273d9f13SBarry Smith 1633800f99ffSJeremy L Thompson b->ctxcontainer = NULL; 1634ef66eb69SBarry Smith b->vshift = 0.0; 1635ef66eb69SBarry Smith b->vscale = 1.0; 16360c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1637273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1638210f0121SBarry Smith A->preallocated = PETSC_FALSE; 16392205254eSKarl Rupp 16409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell)); 16419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell)); 1642800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell)); 16439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell)); 16449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell)); 16459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell)); 16469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell)); 16479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell)); 16489566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL)); 16493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1650273d9f13SBarry Smith } 1651e51e0e81SBarry Smith 16524b828684SBarry Smith /*@C 165311a5261eSBarry Smith MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined 1654ff756334SLois Curfman McInnes private data storage format. 1655e51e0e81SBarry Smith 1656d083f849SBarry Smith Collective 1657c7fcc2eaSBarry Smith 1658e51e0e81SBarry Smith Input Parameters: 1659c7fcc2eaSBarry Smith + comm - MPI communicator 166045f401ebSJose E. Roman . m - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given) 166145f401ebSJose E. Roman . n - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given) 166245f401ebSJose E. Roman . M - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given) 166345f401ebSJose E. Roman . N - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given) 1664c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1665e51e0e81SBarry Smith 1666ff756334SLois Curfman McInnes Output Parameter: 166744cd7ae7SLois Curfman McInnes . A - the matrix 1668e51e0e81SBarry Smith 1669ff2fd236SBarry Smith Level: advanced 1670ff2fd236SBarry Smith 16712920cce0SJacob Faibussowitsch Example Usage: 167227430b45SBarry Smith .vb 167327430b45SBarry Smith extern PetscErrorCode mult(Mat, Vec, Vec); 16742920cce0SJacob Faibussowitsch 167527430b45SBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &mat); 167627430b45SBarry Smith MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult); 16772920cce0SJacob Faibussowitsch // Use matrix for operations that have been set 167827430b45SBarry Smith MatDestroy(mat); 167927430b45SBarry Smith .ve 1680f39d1f56SLois Curfman McInnes 1681ff756334SLois Curfman McInnes Notes: 1682ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 168311a5261eSBarry Smith with `KSP` (such as, for use with matrix-free methods). You should not 1684ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1685e51e0e81SBarry Smith 1686f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1687f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 16882ef1f0ffSBarry Smith creating a shell matrix, `A`, that supports parallel matrix-vector 168911a5261eSBarry Smith products using `MatMult`(A,x,y) the user should set the number 1690645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1691645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1692645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1693645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1694645985a0SLois Curfman McInnes For example, 1695f39d1f56SLois Curfman McInnes 169627430b45SBarry Smith .vb 169727430b45SBarry Smith Vec x, y 169827430b45SBarry Smith extern PetscErrorCode mult(Mat,Vec,Vec); 169927430b45SBarry Smith Mat A 170027430b45SBarry Smith 170127430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,M,&y); 170227430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,N,&x); 170327430b45SBarry Smith VecGetLocalSize(y,&m); 170427430b45SBarry Smith VecGetLocalSize(x,&n); 170527430b45SBarry Smith MatCreateShell(comm,m,n,M,N,ctx,&A); 170627430b45SBarry Smith MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 170727430b45SBarry Smith MatMult(A,x,y); 170827430b45SBarry Smith MatDestroy(&A); 170927430b45SBarry Smith VecDestroy(&y); 171027430b45SBarry Smith VecDestroy(&x); 171127430b45SBarry Smith .ve 1712e51e0e81SBarry Smith 17132ef1f0ffSBarry Smith `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` 17142ef1f0ffSBarry Smith internally, so these operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called. 17150c0fd78eSBarry Smith 171627430b45SBarry Smith Developer Notes: 17172ef1f0ffSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 17182ef1f0ffSBarry Smith 171995452b02SPatrick Sanan Regarding shifting and scaling. The general form is 17200c0fd78eSBarry Smith 17210c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 17220c0fd78eSBarry Smith 17230c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 17240c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 17250c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 17260c0fd78eSBarry Smith 17270c0fd78eSBarry Smith A is the user provided function. 17280c0fd78eSBarry Smith 172927430b45SBarry Smith `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for 1730c5dec841SPierre Jolivet for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger 173111a5261eSBarry Smith an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat); 173211a5261eSBarry Smith each time the `MATSHELL` matrix has changed. 1733ad2f5c3fSBarry Smith 173411a5261eSBarry Smith Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()` 1735b77ba244SStefano Zampini 173611a5261eSBarry Smith Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided 173711a5261eSBarry Smith with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`. 1738ad2f5c3fSBarry Smith 1739fe59aa6dSJacob Faibussowitsch Fortran Notes: 17402ef1f0ffSBarry Smith To use this from Fortran with a `ctx` you must write an interface definition for this 174111a5261eSBarry Smith function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing 17422ef1f0ffSBarry Smith in as the `ctx` argument. 174311a5261eSBarry Smith 1744fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 1745e51e0e81SBarry Smith @*/ 1746d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A) 1747d71ae5a4SJacob Faibussowitsch { 17483a40ed3dSBarry Smith PetscFunctionBegin; 17499566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, A)); 17509566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A, m, n, M, N)); 17519566063dSJacob Faibussowitsch PetscCall(MatSetType(*A, MATSHELL)); 17529566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A, ctx)); 17539566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 17543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1755c7fcc2eaSBarry Smith } 1756c7fcc2eaSBarry Smith 1757c6866cfdSSatish Balay /*@ 175811a5261eSBarry Smith MatShellSetContext - sets the context for a `MATSHELL` shell matrix 1759c7fcc2eaSBarry Smith 1760c3339decSBarry Smith Logically Collective 1761c7fcc2eaSBarry Smith 1762273d9f13SBarry Smith Input Parameters: 176311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1764273d9f13SBarry Smith - ctx - the context 1765273d9f13SBarry Smith 1766273d9f13SBarry Smith Level: advanced 1767273d9f13SBarry Smith 1768fe59aa6dSJacob Faibussowitsch Fortran Notes: 176927430b45SBarry Smith You must write a Fortran interface definition for this 17702ef1f0ffSBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument. 1771273d9f13SBarry Smith 17721cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()` 17730bc0a719SBarry Smith @*/ 1774d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx) 1775d71ae5a4SJacob Faibussowitsch { 1776273d9f13SBarry Smith PetscFunctionBegin; 17770700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1778cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx)); 17793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1780e51e0e81SBarry Smith } 1781e51e0e81SBarry Smith 1782fe59aa6dSJacob Faibussowitsch /*@C 178311a5261eSBarry Smith MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context 1784800f99ffSJeremy L Thompson 1785c3339decSBarry Smith Logically Collective 1786800f99ffSJeremy L Thompson 1787800f99ffSJeremy L Thompson Input Parameters: 1788800f99ffSJeremy L Thompson + mat - the shell matrix 1789800f99ffSJeremy L Thompson - f - the context destroy function 1790800f99ffSJeremy L Thompson 179127430b45SBarry Smith Level: advanced 179227430b45SBarry Smith 1793800f99ffSJeremy L Thompson Note: 1794800f99ffSJeremy L Thompson If the `MatShell` is never duplicated, the behavior of this function is equivalent 179511a5261eSBarry Smith to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()` 1796800f99ffSJeremy L Thompson ensures proper reference counting for the user provided context data in the case that 179711a5261eSBarry Smith the `MATSHELL` is duplicated. 1798800f99ffSJeremy L Thompson 17991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()` 1800800f99ffSJeremy L Thompson @*/ 1801d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *)) 1802d71ae5a4SJacob Faibussowitsch { 1803800f99ffSJeremy L Thompson PetscFunctionBegin; 1804800f99ffSJeremy L Thompson PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1805800f99ffSJeremy L Thompson PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f)); 18063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1807800f99ffSJeremy L Thompson } 1808800f99ffSJeremy L Thompson 1809db77db73SJeremy L Thompson /*@C 18102ef1f0ffSBarry Smith MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()` 1811db77db73SJeremy L Thompson 18122ef1f0ffSBarry Smith Logically Collective 1813db77db73SJeremy L Thompson 1814db77db73SJeremy L Thompson Input Parameters: 181511a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1816db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1817db77db73SJeremy L Thompson 1818db77db73SJeremy L Thompson Level: advanced 1819db77db73SJeremy L Thompson 18201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()` 1821db77db73SJeremy L Thompson @*/ 1822d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype) 1823d71ae5a4SJacob Faibussowitsch { 1824db77db73SJeremy L Thompson PetscFunctionBegin; 1825cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype)); 18263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1827db77db73SJeremy L Thompson } 1828db77db73SJeremy L Thompson 18290c0fd78eSBarry Smith /*@ 183011a5261eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately 183111a5261eSBarry Smith after `MatCreateShell()` 18320c0fd78eSBarry Smith 183327430b45SBarry Smith Logically Collective 18340c0fd78eSBarry Smith 18350c0fd78eSBarry Smith Input Parameter: 1836fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix 18370c0fd78eSBarry Smith 18380c0fd78eSBarry Smith Level: advanced 18390c0fd78eSBarry Smith 18401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()` 18410c0fd78eSBarry Smith @*/ 1842d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1843d71ae5a4SJacob Faibussowitsch { 18440c0fd78eSBarry Smith PetscFunctionBegin; 18450c0fd78eSBarry Smith PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1846cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A)); 18473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 18480c0fd78eSBarry Smith } 18490c0fd78eSBarry Smith 1850c16cb8f2SBarry Smith /*@C 185111a5261eSBarry Smith MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function. 1852f3b1f45cSBarry Smith 1853cf53795eSBarry Smith Logically Collective; No Fortran Support 1854f3b1f45cSBarry Smith 1855f3b1f45cSBarry Smith Input Parameters: 185611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1857f3b1f45cSBarry Smith . f - the function 185811a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1859f3b1f45cSBarry Smith - ctx - an optional context for the function 1860f3b1f45cSBarry Smith 1861f3b1f45cSBarry Smith Output Parameter: 186211a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1863f3b1f45cSBarry Smith 18643c7db156SBarry Smith Options Database Key: 1865f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1866f3b1f45cSBarry Smith 1867f3b1f45cSBarry Smith Level: advanced 1868f3b1f45cSBarry Smith 18691cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()` 1870f3b1f45cSBarry Smith @*/ 1871d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1872d71ae5a4SJacob Faibussowitsch { 1873f3b1f45cSBarry Smith PetscInt m, n; 1874f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1875f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 187674e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1877f3b1f45cSBarry Smith 1878f3b1f45cSBarry Smith PetscFunctionBegin; 1879f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 18809566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v)); 18819566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 18829566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf)); 18839566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 18849566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 1885f3b1f45cSBarry Smith 18869566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 18879566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat)); 1888f3b1f45cSBarry Smith 18899566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 18909566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 18919566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 18929566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 1893f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 1894f3b1f45cSBarry Smith flag = PETSC_FALSE; 1895f3b1f45cSBarry Smith if (v) { 189601c1178eSBarry 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))); 18979566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view")); 18989566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view")); 18999566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view")); 1900f3b1f45cSBarry Smith } 1901f3b1f45cSBarry Smith } else if (v) { 190201c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n")); 1903f3b1f45cSBarry Smith } 1904f3b1f45cSBarry Smith if (flg) *flg = flag; 19059566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19069566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19079566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 19093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1910f3b1f45cSBarry Smith } 1911f3b1f45cSBarry Smith 1912f3b1f45cSBarry Smith /*@C 191311a5261eSBarry Smith MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function. 1914f3b1f45cSBarry Smith 1915cf53795eSBarry Smith Logically Collective; No Fortran Support 1916f3b1f45cSBarry Smith 1917f3b1f45cSBarry Smith Input Parameters: 191811a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1919f3b1f45cSBarry Smith . f - the function 192011a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1921f3b1f45cSBarry Smith - ctx - an optional context for the function 1922f3b1f45cSBarry Smith 1923f3b1f45cSBarry Smith Output Parameter: 192411a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1925f3b1f45cSBarry Smith 19263c7db156SBarry Smith Options Database Key: 1927f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1928f3b1f45cSBarry Smith 1929f3b1f45cSBarry Smith Level: advanced 1930f3b1f45cSBarry Smith 19311cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()` 1932f3b1f45cSBarry Smith @*/ 1933d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1934d71ae5a4SJacob Faibussowitsch { 1935f3b1f45cSBarry Smith Vec x, y, z; 1936f3b1f45cSBarry Smith PetscInt m, n, M, N; 1937f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1938f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 193974e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1940f3b1f45cSBarry Smith 1941f3b1f45cSBarry Smith PetscFunctionBegin; 1942f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 19439566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v)); 19449566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &y)); 19459566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &z)); 19469566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 19479566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 19489566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf)); 19499566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 19509566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 19519566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 19529566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf)); 19539566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat)); 1954f3b1f45cSBarry Smith 19559566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 19569566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 19579566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 19589566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 1959f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 1960f3b1f45cSBarry Smith flag = PETSC_FALSE; 1961f3b1f45cSBarry Smith if (v) { 196201c1178eSBarry 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))); 19639566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 19649566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 19659566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 1966f3b1f45cSBarry Smith } 1967f3b1f45cSBarry Smith } else if (v) { 196801c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n")); 1969f3b1f45cSBarry Smith } 1970f3b1f45cSBarry Smith if (flg) *flg = flag; 19719566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19729566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 19739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19749566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 19769566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 19779566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 19783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1979f3b1f45cSBarry Smith } 1980f3b1f45cSBarry Smith 1981f3b1f45cSBarry Smith /*@C 198211a5261eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix. 1983e51e0e81SBarry Smith 1984c3339decSBarry Smith Logically Collective 1985fee21e36SBarry Smith 1986c7fcc2eaSBarry Smith Input Parameters: 198711a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1988c7fcc2eaSBarry Smith . op - the name of the operation 1989789d8953SBarry Smith - g - the function that provides the operation. 1990c7fcc2eaSBarry Smith 199115091d37SBarry Smith Level: advanced 199215091d37SBarry Smith 19932920cce0SJacob Faibussowitsch Example Usage: 1994c3339decSBarry Smith .vb 1995c3339decSBarry Smith extern PetscErrorCode usermult(Mat, Vec, Vec); 19962920cce0SJacob Faibussowitsch 1997c3339decSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 1998c3339decSBarry Smith MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult); 1999c3339decSBarry Smith .ve 20000b627109SLois Curfman McInnes 2001a62d957aSLois Curfman McInnes Notes: 2002e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 20031c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2004a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 200511a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2006a62d957aSLois Curfman McInnes 200711a5261eSBarry Smith All user-provided functions (except for `MATOP_DESTROY`) should have the same calling 2008deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2009deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2010deebb3c3SLois Curfman McInnes routines, e.g., 2011a62d957aSLois Curfman McInnes $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2012a62d957aSLois Curfman McInnes 20134aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 20144aa34b0aSBarry Smith nonzero on failure. 20154aa34b0aSBarry Smith 2016a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 201711a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 201811a5261eSBarry Smith set by `MatCreateShell()`. 2019a62d957aSLois Curfman McInnes 20202ef1f0ffSBarry Smith Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) 20212ef1f0ffSBarry Smith use `MatShellSetMatProductOperation()` 2022b77ba244SStefano Zampini 2023fe59aa6dSJacob Faibussowitsch Fortran Notes: 202411a5261eSBarry Smith For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not 2025c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2026501d9185SBarry Smith 20271cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 2028e51e0e81SBarry Smith @*/ 2029d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void)) 2030d71ae5a4SJacob Faibussowitsch { 20313a40ed3dSBarry Smith PetscFunctionBegin; 20320700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2033cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g)); 20343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2035e51e0e81SBarry Smith } 2036f0479e8cSBarry Smith 2037d4bb536fSBarry Smith /*@C 203811a5261eSBarry Smith MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix. 2039d4bb536fSBarry Smith 2040c7fcc2eaSBarry Smith Not Collective 2041c7fcc2eaSBarry Smith 2042d4bb536fSBarry Smith Input Parameters: 204311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2044c7fcc2eaSBarry Smith - op - the name of the operation 2045d4bb536fSBarry Smith 2046d4bb536fSBarry Smith Output Parameter: 2047789d8953SBarry Smith . g - the function that provides the operation. 2048d4bb536fSBarry Smith 204915091d37SBarry Smith Level: advanced 205015091d37SBarry Smith 205127430b45SBarry Smith Notes: 2052e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2053d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2054d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 205511a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2056d4bb536fSBarry Smith 2057d4bb536fSBarry Smith All user-provided functions have the same calling 2058d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2059d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2060d4bb536fSBarry Smith routines, e.g., 2061d4bb536fSBarry Smith $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2062d4bb536fSBarry Smith 2063d4bb536fSBarry Smith Within each user-defined routine, the user should call 206411a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 206511a5261eSBarry Smith set by `MatCreateShell()`. 2066d4bb536fSBarry Smith 20671cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()` 2068d4bb536fSBarry Smith @*/ 2069d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void)) 2070d71ae5a4SJacob Faibussowitsch { 20713a40ed3dSBarry Smith PetscFunctionBegin; 20720700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2073cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g)); 20743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2075d4bb536fSBarry Smith } 2076b77ba244SStefano Zampini 2077b77ba244SStefano Zampini /*@ 207811a5261eSBarry Smith MatIsShell - Inquires if a matrix is derived from `MATSHELL` 2079b77ba244SStefano Zampini 2080b77ba244SStefano Zampini Input Parameter: 2081b77ba244SStefano Zampini . mat - the matrix 2082b77ba244SStefano Zampini 2083b77ba244SStefano Zampini Output Parameter: 2084b77ba244SStefano Zampini . flg - the boolean value 2085b77ba244SStefano Zampini 2086b77ba244SStefano Zampini Level: developer 2087b77ba244SStefano Zampini 2088fe59aa6dSJacob Faibussowitsch Developer Notes: 20892ef1f0ffSBarry Smith In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices 20902ef1f0ffSBarry Smith (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc) 2091b77ba244SStefano Zampini 20921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` 2093b77ba244SStefano Zampini @*/ 2094d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2095d71ae5a4SJacob Faibussowitsch { 2096b77ba244SStefano Zampini PetscFunctionBegin; 2097b77ba244SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 20984f572ea9SToby Isaac PetscAssertPointer(flg, 2); 2099b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 21003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2101b77ba244SStefano Zampini } 2102