1be1d678aSKris Buschelman 2e51e0e81SBarry Smith /* 320563c6bSBarry Smith This provides a simple shell for Fortran (and C programmers) to 420563c6bSBarry Smith create a very simple matrix class for use with KSP without coding 5ed3cc1f0SBarry Smith much of anything. 6e51e0e81SBarry Smith */ 7e51e0e81SBarry Smith 8af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 945960306SStefano Zampini #include <petsc/private/vecimpl.h> 10e51e0e81SBarry Smith 1128f357e3SAlex Fikl struct _MatShellOps { 12976e8c5aSLisandro Dalcin /* 3 */ PetscErrorCode (*mult)(Mat, Vec, Vec); 13976e8c5aSLisandro Dalcin /* 5 */ PetscErrorCode (*multtranspose)(Mat, Vec, Vec); 14976e8c5aSLisandro Dalcin /* 17 */ PetscErrorCode (*getdiagonal)(Mat, Vec); 15976e8c5aSLisandro Dalcin /* 43 */ PetscErrorCode (*copy)(Mat, Mat, MatStructure); 16976e8c5aSLisandro Dalcin /* 60 */ PetscErrorCode (*destroy)(Mat); 1728f357e3SAlex Fikl }; 1828f357e3SAlex Fikl 19b77ba244SStefano Zampini struct _n_MatShellMatFunctionList { 20b77ba244SStefano Zampini PetscErrorCode (*symbolic)(Mat, Mat, Mat, void **); 21b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 22b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 23b77ba244SStefano Zampini MatProductType ptype; 24b77ba244SStefano Zampini char *composedname; /* string to identify routine with double dispatch */ 25b77ba244SStefano Zampini char *resultname; /* result matrix type */ 26b77ba244SStefano Zampini 27b77ba244SStefano Zampini struct _n_MatShellMatFunctionList *next; 28b77ba244SStefano Zampini }; 29b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList; 30b77ba244SStefano Zampini 3128f357e3SAlex Fikl typedef struct { 3228f357e3SAlex Fikl struct _MatShellOps ops[1]; 332205254eSKarl Rupp 34b77ba244SStefano Zampini /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 35b77ba244SStefano Zampini PetscBool managescalingshifts; 36b77ba244SStefano Zampini 37b77ba244SStefano Zampini /* support for MatScale, MatShift and MatMultAdd */ 38ef66eb69SBarry Smith PetscScalar vscale, vshift; 398fe8eb27SJed Brown Vec dshift; 408fe8eb27SJed Brown Vec left, right; 418fe8eb27SJed Brown Vec left_work, right_work; 425edf6516SJed Brown Vec left_add_work, right_add_work; 43b77ba244SStefano Zampini 44ef5c7bd2SStefano Zampini /* support for MatAXPY */ 459f137db4SBarry Smith Mat axpy; 469f137db4SBarry Smith PetscScalar axpy_vscale; 47b77ba244SStefano Zampini Vec axpy_left, axpy_right; 48ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 49b77ba244SStefano Zampini 5045960306SStefano Zampini /* support for ZeroRows/Columns operations */ 5145960306SStefano Zampini IS zrows; 5245960306SStefano Zampini IS zcols; 5345960306SStefano Zampini Vec zvals; 5445960306SStefano Zampini Vec zvals_w; 5545960306SStefano Zampini VecScatter zvals_sct_r; 5645960306SStefano Zampini VecScatter zvals_sct_c; 57b77ba244SStefano Zampini 58b77ba244SStefano Zampini /* MatMat operations */ 59b77ba244SStefano Zampini MatShellMatFunctionList matmat; 60b77ba244SStefano Zampini 61b77ba244SStefano Zampini /* user defined context */ 62800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 6388cf3e7dSBarry Smith } Mat_Shell; 640c0fd78eSBarry Smith 6545960306SStefano Zampini /* 6645960306SStefano Zampini Store and scale values on zeroed rows 6745960306SStefano Zampini xx = [x_1, 0], 0 on zeroed columns 6845960306SStefano Zampini */ 69d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroRight(Mat A, Vec x, Vec *xx) 70d71ae5a4SJacob Faibussowitsch { 7145960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 7245960306SStefano Zampini 7345960306SStefano Zampini PetscFunctionBegin; 7445960306SStefano Zampini *xx = x; 7545960306SStefano Zampini if (shell->zrows) { 769566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 779566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 789566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 799566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 8045960306SStefano Zampini } 8145960306SStefano Zampini if (shell->zcols) { 8248a46eb9SPierre Jolivet if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 839566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->right_work)); 849566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->right_work, shell->zcols, 0.0)); 8545960306SStefano Zampini *xx = shell->right_work; 8645960306SStefano Zampini } 8745960306SStefano Zampini PetscFunctionReturn(0); 8845960306SStefano Zampini } 8945960306SStefano Zampini 9045960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 91d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroLeft(Mat A, Vec x) 92d71ae5a4SJacob Faibussowitsch { 9345960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 9445960306SStefano Zampini 9545960306SStefano Zampini PetscFunctionBegin; 9645960306SStefano Zampini if (shell->zrows) { 979566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 989566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, x, INSERT_VALUES, SCATTER_REVERSE)); 9945960306SStefano Zampini } 10045960306SStefano Zampini PetscFunctionReturn(0); 10145960306SStefano Zampini } 10245960306SStefano Zampini 10345960306SStefano Zampini /* 10445960306SStefano Zampini Store and scale values on zeroed rows 10545960306SStefano Zampini xx = [x_1, 0], 0 on zeroed rows 10645960306SStefano Zampini */ 107d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreZeroLeft(Mat A, Vec x, Vec *xx) 108d71ae5a4SJacob Faibussowitsch { 10945960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 11045960306SStefano Zampini 11145960306SStefano Zampini PetscFunctionBegin; 11245960306SStefano Zampini *xx = NULL; 11345960306SStefano Zampini if (!shell->zrows) { 11445960306SStefano Zampini *xx = x; 11545960306SStefano Zampini } else { 11648a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 1179566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->left_work)); 1189566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 0.0)); 1199566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 1209566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals_w, shell->left_work, INSERT_VALUES, SCATTER_REVERSE)); 1219566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 1229566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, x, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 1239566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w, shell->zvals_w, shell->zvals)); 12445960306SStefano Zampini *xx = shell->left_work; 12545960306SStefano Zampini } 12645960306SStefano Zampini PetscFunctionReturn(0); 12745960306SStefano Zampini } 12845960306SStefano Zampini 12945960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 130d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostZeroRight(Mat A, Vec x) 131d71ae5a4SJacob Faibussowitsch { 13245960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 13345960306SStefano Zampini 13445960306SStefano Zampini PetscFunctionBegin; 1351baa6e33SBarry Smith if (shell->zcols) PetscCall(VecISSet(x, shell->zcols, 0.0)); 13645960306SStefano Zampini if (shell->zrows) { 1379566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 1389566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, shell->zvals_w, x, ADD_VALUES, SCATTER_REVERSE)); 13945960306SStefano Zampini } 14045960306SStefano Zampini PetscFunctionReturn(0); 14145960306SStefano Zampini } 14245960306SStefano Zampini 1438fe8eb27SJed Brown /* 1440c0fd78eSBarry Smith xx = diag(left)*x 1458fe8eb27SJed Brown */ 146d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx) 147d71ae5a4SJacob Faibussowitsch { 1488fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1498fe8eb27SJed Brown 1508fe8eb27SJed Brown PetscFunctionBegin; 1510298fd71SBarry Smith *xx = NULL; 1528fe8eb27SJed Brown if (!shell->left) { 1538fe8eb27SJed Brown *xx = x; 1548fe8eb27SJed Brown } else { 1559566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(VecDuplicate(shell->left, &shell->left_work)); 1569566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, x, shell->left)); 1578fe8eb27SJed Brown *xx = shell->left_work; 1588fe8eb27SJed Brown } 1598fe8eb27SJed Brown PetscFunctionReturn(0); 1608fe8eb27SJed Brown } 1618fe8eb27SJed Brown 1620c0fd78eSBarry Smith /* 1630c0fd78eSBarry Smith xx = diag(right)*x 1640c0fd78eSBarry Smith */ 165d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx) 166d71ae5a4SJacob Faibussowitsch { 1678fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1688fe8eb27SJed Brown 1698fe8eb27SJed Brown PetscFunctionBegin; 1700298fd71SBarry Smith *xx = NULL; 1718fe8eb27SJed Brown if (!shell->right) { 1728fe8eb27SJed Brown *xx = x; 1738fe8eb27SJed Brown } else { 1749566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work)); 1759566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, x, shell->right)); 1768fe8eb27SJed Brown *xx = shell->right_work; 1778fe8eb27SJed Brown } 1788fe8eb27SJed Brown PetscFunctionReturn(0); 1798fe8eb27SJed Brown } 1808fe8eb27SJed Brown 1810c0fd78eSBarry Smith /* 1820c0fd78eSBarry Smith x = diag(left)*x 1830c0fd78eSBarry Smith */ 184d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x) 185d71ae5a4SJacob Faibussowitsch { 1868fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1878fe8eb27SJed Brown 1888fe8eb27SJed Brown PetscFunctionBegin; 1899566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left)); 1908fe8eb27SJed Brown PetscFunctionReturn(0); 1918fe8eb27SJed Brown } 1928fe8eb27SJed Brown 1930c0fd78eSBarry Smith /* 1940c0fd78eSBarry Smith x = diag(right)*x 1950c0fd78eSBarry Smith */ 196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x) 197d71ae5a4SJacob Faibussowitsch { 1988fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1998fe8eb27SJed Brown 2008fe8eb27SJed Brown PetscFunctionBegin; 2019566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(x, x, shell->right)); 2028fe8eb27SJed Brown PetscFunctionReturn(0); 2038fe8eb27SJed Brown } 2048fe8eb27SJed Brown 2050c0fd78eSBarry Smith /* 2060c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 2070c0fd78eSBarry Smith 2080c0fd78eSBarry Smith On input Y already contains A*x 2090c0fd78eSBarry Smith */ 210d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y) 211d71ae5a4SJacob Faibussowitsch { 2128fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 2138fe8eb27SJed Brown 2148fe8eb27SJed Brown PetscFunctionBegin; 2158fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 2168fe8eb27SJed Brown PetscInt i, m; 2178fe8eb27SJed Brown const PetscScalar *x, *d; 2188fe8eb27SJed Brown PetscScalar *y; 2199566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &m)); 2209566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift, &d)); 2219566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 2229566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y, &y)); 2238fe8eb27SJed Brown for (i = 0; i < m; i++) y[i] = shell->vscale * y[i] + d[i] * x[i]; 2249566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 2259566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 2269566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y, &y)); 2270c0fd78eSBarry Smith } else { 2289566063dSJacob Faibussowitsch PetscCall(VecScale(Y, shell->vscale)); 2298fe8eb27SJed Brown } 2309566063dSJacob Faibussowitsch if (shell->vshift != 0.0) PetscCall(VecAXPY(Y, shell->vshift, X)); /* if test is for non-square matrices */ 2318fe8eb27SJed Brown PetscFunctionReturn(0); 2328fe8eb27SJed Brown } 233e51e0e81SBarry Smith 234d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx) 235d71ae5a4SJacob Faibussowitsch { 236800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 237800f99ffSJeremy L Thompson 238789d8953SBarry Smith PetscFunctionBegin; 239800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx)); 240800f99ffSJeremy L Thompson else *(void **)ctx = NULL; 241789d8953SBarry Smith PetscFunctionReturn(0); 242789d8953SBarry Smith } 243789d8953SBarry Smith 2449d225801SJed Brown /*@ 24511a5261eSBarry Smith MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix. 246b4fd4287SBarry Smith 247c7fcc2eaSBarry Smith Not Collective 248c7fcc2eaSBarry Smith 249b4fd4287SBarry Smith Input Parameter: 25011a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()` 251b4fd4287SBarry Smith 252b4fd4287SBarry Smith Output Parameter: 253b4fd4287SBarry Smith . ctx - the user provided context 254b4fd4287SBarry Smith 25515091d37SBarry Smith Level: advanced 25615091d37SBarry Smith 25711a5261eSBarry Smith Fortran Note: 25895452b02SPatrick Sanan To use this from Fortran you must write a Fortran interface definition for this 259daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 260a62d957aSLois Curfman McInnes 26111a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()` 2620bc0a719SBarry Smith @*/ 263d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx) 264d71ae5a4SJacob Faibussowitsch { 2653a40ed3dSBarry Smith PetscFunctionBegin; 2660700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2674482741eSBarry Smith PetscValidPointer(ctx, 2); 268cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx)); 2693a40ed3dSBarry Smith PetscFunctionReturn(0); 270b4fd4287SBarry Smith } 271b4fd4287SBarry Smith 272d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc) 273d71ae5a4SJacob Faibussowitsch { 27445960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 27545960306SStefano Zampini Vec x = NULL, b = NULL; 27645960306SStefano Zampini IS is1, is2; 27745960306SStefano Zampini const PetscInt *ridxs; 27845960306SStefano Zampini PetscInt *idxs, *gidxs; 27945960306SStefano Zampini PetscInt cum, rst, cst, i; 28045960306SStefano Zampini 28145960306SStefano Zampini PetscFunctionBegin; 28248a46eb9SPierre Jolivet if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals)); 28348a46eb9SPierre Jolivet if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w)); 2849566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &rst, NULL)); 2859566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL)); 28645960306SStefano Zampini 28745960306SStefano Zampini /* Expand/create index set of zeroed rows */ 2889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &idxs)); 28945960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 2909566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1)); 2919566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 2929566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals, is1, diag)); 29345960306SStefano Zampini if (shell->zrows) { 2949566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows, is1, &is2)); 2959566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 2969566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 29745960306SStefano Zampini shell->zrows = is2; 29845960306SStefano Zampini } else shell->zrows = is1; 29945960306SStefano Zampini 30045960306SStefano Zampini /* Create scatters for diagonal values communications */ 3019566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 3029566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 30345960306SStefano Zampini 30445960306SStefano Zampini /* row scatter: from/to left vector */ 3059566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &b)); 3069566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r)); 30745960306SStefano Zampini 30845960306SStefano Zampini /* col scatter: from right vector to left vector */ 3099566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows, &ridxs)); 3109566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows, &nr)); 3119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &gidxs)); 31245960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 31345960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 31445960306SStefano Zampini gidxs[cum] = ridxs[i]; 31545960306SStefano Zampini cum++; 31645960306SStefano Zampini } 3179566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1)); 3189566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c)); 3199566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 3209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 3219566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 32245960306SStefano Zampini 32345960306SStefano Zampini /* Expand/create index set of zeroed columns */ 32445960306SStefano Zampini if (rc) { 3259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &idxs)); 32645960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 3279566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1)); 3289566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 32945960306SStefano Zampini if (shell->zcols) { 3309566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols, is1, &is2)); 3319566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3329566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 33345960306SStefano Zampini shell->zcols = is2; 33445960306SStefano Zampini } else shell->zcols = is1; 33545960306SStefano Zampini } 33645960306SStefano Zampini PetscFunctionReturn(0); 33745960306SStefano Zampini } 33845960306SStefano Zampini 339d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 340d71ae5a4SJacob Faibussowitsch { 341ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 34245960306SStefano Zampini PetscInt nr, *lrows; 34345960306SStefano Zampini 34445960306SStefano Zampini PetscFunctionBegin; 34545960306SStefano Zampini if (x && b) { 34645960306SStefano Zampini Vec xt; 34745960306SStefano Zampini PetscScalar *vals; 34845960306SStefano Zampini PetscInt *gcols, i, st, nl, nc; 34945960306SStefano Zampini 3509566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &gcols)); 3519371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3529371c9d4SSatish Balay if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 35345960306SStefano Zampini 3549566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, NULL)); 3559566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3569566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc, &vals)); 3579566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3589566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3599566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3609566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3619566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */ 36245960306SStefano Zampini 3639566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3649566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3659566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 36645960306SStefano Zampini for (i = 0; i < nl; i++) { 36745960306SStefano Zampini PetscInt g = i + st; 36845960306SStefano Zampini if (g > mat->rmap->N) continue; 36945960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 3709566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES)); 37145960306SStefano Zampini } 3729566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 3739566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 3749566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 3759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 3769566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 37745960306SStefano Zampini } 3789566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL)); 3799566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE)); 3801baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL)); 3819566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 38245960306SStefano Zampini PetscFunctionReturn(0); 38345960306SStefano Zampini } 38445960306SStefano Zampini 385d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b) 386d71ae5a4SJacob Faibussowitsch { 387ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 38845960306SStefano Zampini PetscInt *lrows, *lcols; 38945960306SStefano Zampini PetscInt nr, nc; 39045960306SStefano Zampini PetscBool congruent; 39145960306SStefano Zampini 39245960306SStefano Zampini PetscFunctionBegin; 39345960306SStefano Zampini if (x && b) { 39445960306SStefano Zampini Vec xt, bt; 39545960306SStefano Zampini PetscScalar *vals; 39645960306SStefano Zampini PetscInt *grows, *gcols, i, st, nl; 39745960306SStefano Zampini 3989566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &grows, n, &gcols)); 3999371c9d4SSatish Balay for (i = 0, nr = 0; i < n; i++) 4009371c9d4SSatish Balay if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 4019371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 4029371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 4039566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n, &vals)); 40445960306SStefano Zampini 4059566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, &bt)); 4069566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 4079566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 4089566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 4099566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 4109566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt, -1.0, x)); /* xt = [0, -x2] */ 4119566063dSJacob Faibussowitsch PetscCall(MatMult(mat, xt, bt)); /* bt = [-A12*x2,-A22*x2] */ 4129566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */ 4139566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4149566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4159566063dSJacob Faibussowitsch PetscCall(VecAXPY(b, 1.0, bt)); /* b = [b1 - A12*x2, b2] */ 4169566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 4179566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4189566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4199566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 42045960306SStefano Zampini 4219566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 4229566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 4239566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 42445960306SStefano Zampini for (i = 0; i < nl; i++) { 42545960306SStefano Zampini PetscInt g = i + st; 42645960306SStefano Zampini if (g > mat->rmap->N) continue; 42745960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4289566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES)); 42945960306SStefano Zampini } 4309566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4319566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4329566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4349566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4359566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows, gcols)); 43645960306SStefano Zampini } 4379566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL)); 4389566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat, &congruent)); 43945960306SStefano Zampini if (congruent) { 44045960306SStefano Zampini nc = nr; 44145960306SStefano Zampini lcols = lrows; 44245960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 44345960306SStefano Zampini PetscInt i, nt, *t; 44445960306SStefano Zampini 4459566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &t)); 4469371c9d4SSatish Balay for (i = 0, nt = 0; i < n; i++) 4479371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4489566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL)); 4499566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 45045960306SStefano Zampini } 4519566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE)); 45248a46eb9SPierre Jolivet if (!congruent) PetscCall(PetscFree(lcols)); 4539566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4541baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL)); 45545960306SStefano Zampini PetscFunctionReturn(0); 45645960306SStefano Zampini } 45745960306SStefano Zampini 458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat) 459d71ae5a4SJacob Faibussowitsch { 460bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell *)mat->data; 461b77ba244SStefano Zampini MatShellMatFunctionList matmat; 462ed3cc1f0SBarry Smith 4633a40ed3dSBarry Smith PetscFunctionBegin; 4641baa6e33SBarry Smith if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat)); 4659566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps))); 4669566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4679566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4689566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 4699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 4709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 4719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 4729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 4739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 4749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 4759566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 4769566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 4779566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 4789566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 4799566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 4809566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 4819566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 482b77ba244SStefano Zampini 483b77ba244SStefano Zampini matmat = shell->matmat; 484b77ba244SStefano Zampini while (matmat) { 485b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 486b77ba244SStefano Zampini 4879566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL)); 4889566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 4899566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 4909566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 491b77ba244SStefano Zampini matmat = next; 492b77ba244SStefano Zampini } 493800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(mat, NULL)); 4949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL)); 4959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 496800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL)); 4979566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL)); 4989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL)); 4999566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL)); 5009566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL)); 5019566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL)); 5029566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 503b77ba244SStefano Zampini PetscFunctionReturn(0); 504b77ba244SStefano Zampini } 505b77ba244SStefano Zampini 506b77ba244SStefano Zampini typedef struct { 507b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 508b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 509b77ba244SStefano Zampini void *userdata; 510b77ba244SStefano Zampini Mat B; 511b77ba244SStefano Zampini Mat Bt; 512b77ba244SStefano Zampini Mat axpy; 513b77ba244SStefano Zampini } MatMatDataShell; 514b77ba244SStefano Zampini 515d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data) 516d71ae5a4SJacob Faibussowitsch { 517b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 518b77ba244SStefano Zampini 519b77ba244SStefano Zampini PetscFunctionBegin; 5201baa6e33SBarry Smith if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata)); 5219566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 5229566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 5239566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 5249566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 525b77ba244SStefano Zampini PetscFunctionReturn(0); 526b77ba244SStefano Zampini } 527b77ba244SStefano Zampini 528d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 529d71ae5a4SJacob Faibussowitsch { 530b77ba244SStefano Zampini Mat_Product *product; 531b77ba244SStefano Zampini Mat A, B; 532b77ba244SStefano Zampini MatMatDataShell *mdata; 533b77ba244SStefano Zampini PetscScalar zero = 0.0; 534b77ba244SStefano Zampini 535b77ba244SStefano Zampini PetscFunctionBegin; 536b77ba244SStefano Zampini MatCheckProduct(D, 1); 537b77ba244SStefano Zampini product = D->product; 53828b400f6SJacob Faibussowitsch PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty"); 539b77ba244SStefano Zampini A = product->A; 540b77ba244SStefano Zampini B = product->B; 541b77ba244SStefano Zampini mdata = (MatMatDataShell *)product->data; 542b77ba244SStefano Zampini if (mdata->numeric) { 543b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 544b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 545b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 546b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 547b77ba244SStefano Zampini 548b77ba244SStefano Zampini if (shell->managescalingshifts) { 54908401ef6SPierre Jolivet PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns"); 550b77ba244SStefano Zampini if (shell->right || shell->left) { 551b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 552b77ba244SStefano Zampini if (!mdata->B) { 5539566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B)); 554b77ba244SStefano Zampini } else { 555b77ba244SStefano Zampini newB = PETSC_FALSE; 556b77ba244SStefano Zampini } 5579566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN)); 558b77ba244SStefano Zampini } 559b77ba244SStefano Zampini switch (product->type) { 560b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 5611baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 562b77ba244SStefano Zampini break; 563b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 5641baa6e33SBarry Smith if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL)); 565b77ba244SStefano Zampini break; 566b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 5671baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 568b77ba244SStefano Zampini break; 569b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 570b77ba244SStefano Zampini if (shell->right && shell->left) { 571b77ba244SStefano Zampini PetscBool flg; 572b77ba244SStefano Zampini 5739566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5749371c9d4SSatish 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, 5759371c9d4SSatish Balay ((PetscObject)B)->type_name); 576b77ba244SStefano Zampini } 5771baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 578b77ba244SStefano Zampini break; 579b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 580b77ba244SStefano Zampini if (shell->right && shell->left) { 581b77ba244SStefano Zampini PetscBool flg; 582b77ba244SStefano Zampini 5839566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 5849371c9d4SSatish 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, 5859371c9d4SSatish Balay ((PetscObject)B)->type_name); 586b77ba244SStefano Zampini } 5871baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 588b77ba244SStefano Zampini break; 589d71ae5a4SJacob Faibussowitsch default: 590d71ae5a4SJacob 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); 591b77ba244SStefano Zampini } 592b77ba244SStefano Zampini } 593b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 594b77ba244SStefano Zampini D->product = NULL; 595b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 596b77ba244SStefano Zampini D->ops->productnumeric = NULL; 597b77ba244SStefano Zampini 5989566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata)); 599b77ba244SStefano Zampini 600b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 6019566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 602b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 603b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 604b77ba244SStefano Zampini D->product = product; 605b77ba244SStefano Zampini 606b77ba244SStefano Zampini if (shell->managescalingshifts) { 6079566063dSJacob Faibussowitsch PetscCall(MatScale(D, shell->vscale)); 608b77ba244SStefano Zampini switch (product->type) { 609b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 610b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 611b77ba244SStefano Zampini if (shell->left) { 6129566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->left, NULL)); 613b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 6149566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 615b77ba244SStefano Zampini if (shell->dshift) { 6169566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->left_work)); 6179566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work, shell->vshift)); 6189566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left)); 619b77ba244SStefano Zampini } else { 6209566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work, shell->vshift)); 621b77ba244SStefano Zampini } 622b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 623b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 624b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 625b77ba244SStefano Zampini 6269566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt)); 6279566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL)); 6289566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->Bt, str)); 629b77ba244SStefano Zampini } else { 630b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 631b77ba244SStefano Zampini 6329566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL)); 6339566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 634b77ba244SStefano Zampini } 635b77ba244SStefano Zampini } 636b77ba244SStefano Zampini } 637b77ba244SStefano Zampini break; 638b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 639b77ba244SStefano Zampini if (shell->right) { 6409566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->right, NULL)); 641b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 642b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 643b77ba244SStefano Zampini 6449566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 645b77ba244SStefano Zampini if (shell->dshift) { 6469566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->right_work)); 6479566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work, shell->vshift)); 6489566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right)); 649b77ba244SStefano Zampini } else { 6509566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work, shell->vshift)); 651b77ba244SStefano Zampini } 6529566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL)); 6539566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 654b77ba244SStefano Zampini } 655b77ba244SStefano Zampini } 656b77ba244SStefano Zampini break; 657b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 658b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6599371c9d4SSatish 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, 6609371c9d4SSatish Balay ((PetscObject)B)->type_name); 661b77ba244SStefano Zampini break; 662d71ae5a4SJacob Faibussowitsch default: 663d71ae5a4SJacob 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); 664b77ba244SStefano Zampini } 665b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 666b77ba244SStefano Zampini Mat X; 667b77ba244SStefano Zampini PetscObjectState axpy_state; 668b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 669b77ba244SStefano Zampini 6709566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 6719566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 67208401ef6SPierre 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,...)"); 673b77ba244SStefano Zampini if (!mdata->axpy) { 674b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6759566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy)); 6769566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy, product->type)); 6779566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6789566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 679b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 680b77ba244SStefano Zampini PetscBool flg; 681b77ba244SStefano Zampini 6829566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy)); 6839566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg)); 684b77ba244SStefano Zampini if (!flg) { 685b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6869566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6879566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 688b77ba244SStefano Zampini } 689b77ba244SStefano Zampini } 6909566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 6919566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str)); 692b77ba244SStefano Zampini } 693b77ba244SStefano Zampini } 694b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation"); 695b77ba244SStefano Zampini PetscFunctionReturn(0); 696b77ba244SStefano Zampini } 697b77ba244SStefano Zampini 698d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 699d71ae5a4SJacob Faibussowitsch { 700b77ba244SStefano Zampini Mat_Product *product; 701b77ba244SStefano Zampini Mat A, B; 702b77ba244SStefano Zampini MatShellMatFunctionList matmat; 703b77ba244SStefano Zampini Mat_Shell *shell; 704b77ba244SStefano Zampini PetscBool flg; 705b77ba244SStefano Zampini char composedname[256]; 706b77ba244SStefano Zampini MatMatDataShell *mdata; 707b77ba244SStefano Zampini 708b77ba244SStefano Zampini PetscFunctionBegin; 709b77ba244SStefano Zampini MatCheckProduct(D, 1); 710b77ba244SStefano Zampini product = D->product; 71128b400f6SJacob Faibussowitsch PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty"); 712b77ba244SStefano Zampini A = product->A; 713b77ba244SStefano Zampini B = product->B; 714b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 715b77ba244SStefano Zampini matmat = shell->matmat; 7169566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 717b77ba244SStefano Zampini while (matmat) { 7189566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 719b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 720b77ba244SStefano Zampini if (flg) break; 721b77ba244SStefano Zampini matmat = matmat->next; 722b77ba244SStefano Zampini } 72328b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]); 724b77ba244SStefano Zampini switch (product->type) { 725d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AB: 726d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); 727d71ae5a4SJacob Faibussowitsch break; 728d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AtB: 729d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); 730d71ae5a4SJacob Faibussowitsch break; 731d71ae5a4SJacob Faibussowitsch case MATPRODUCT_ABt: 732d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N)); 733d71ae5a4SJacob Faibussowitsch break; 734d71ae5a4SJacob Faibussowitsch case MATPRODUCT_RARt: 735d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N)); 736d71ae5a4SJacob Faibussowitsch break; 737d71ae5a4SJacob Faibussowitsch case MATPRODUCT_PtAP: 738d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N)); 739d71ae5a4SJacob Faibussowitsch break; 740d71ae5a4SJacob Faibussowitsch default: 741d71ae5a4SJacob 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); 742b77ba244SStefano Zampini } 743b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 744b77ba244SStefano Zampini if (matmat->resultname) { 7459566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg)); 74648a46eb9SPierre Jolivet if (!flg) PetscCall(MatSetType(D, matmat->resultname)); 747b77ba244SStefano Zampini } 748b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 749b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 750b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 751b77ba244SStefano Zampini /* attach product data */ 7529566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 753b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 754b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 755b77ba244SStefano Zampini if (matmat->symbolic) { 7569566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata)); 757b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7589566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 759b77ba244SStefano Zampini } 76028b400f6SJacob Faibussowitsch PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase"); 76128b400f6SJacob Faibussowitsch PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase"); 762b77ba244SStefano Zampini D->product->data = mdata; 763b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 764b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 765b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 766b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 767b77ba244SStefano Zampini PetscFunctionReturn(0); 768b77ba244SStefano Zampini } 769b77ba244SStefano Zampini 770d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 771d71ae5a4SJacob Faibussowitsch { 772b77ba244SStefano Zampini Mat_Product *product; 773b77ba244SStefano Zampini Mat A, B; 774b77ba244SStefano Zampini MatShellMatFunctionList matmat; 775b77ba244SStefano Zampini Mat_Shell *shell; 776b77ba244SStefano Zampini PetscBool flg; 777b77ba244SStefano Zampini char composedname[256]; 778b77ba244SStefano Zampini 779b77ba244SStefano Zampini PetscFunctionBegin; 780b77ba244SStefano Zampini MatCheckProduct(D, 1); 781b77ba244SStefano Zampini product = D->product; 782b77ba244SStefano Zampini A = product->A; 783b77ba244SStefano Zampini B = product->B; 7849566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 785b77ba244SStefano Zampini if (!flg) PetscFunctionReturn(0); 786b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 787b77ba244SStefano Zampini matmat = shell->matmat; 7889566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 789b77ba244SStefano Zampini while (matmat) { 7909566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 791b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 792b77ba244SStefano Zampini if (flg) break; 793b77ba244SStefano Zampini matmat = matmat->next; 794b77ba244SStefano Zampini } 7959371c9d4SSatish Balay if (flg) { 7969371c9d4SSatish Balay D->ops->productsymbolic = MatProductSymbolic_Shell_X; 7979371c9d4SSatish Balay } else PetscCall(PetscInfo(D, " symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type])); 798b77ba244SStefano Zampini PetscFunctionReturn(0); 799b77ba244SStefano Zampini } 800b77ba244SStefano Zampini 801d71ae5a4SJacob 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) 802d71ae5a4SJacob Faibussowitsch { 803b77ba244SStefano Zampini PetscBool flg; 804b77ba244SStefano Zampini Mat_Shell *shell; 805b77ba244SStefano Zampini MatShellMatFunctionList matmat; 806b77ba244SStefano Zampini 807b77ba244SStefano Zampini PetscFunctionBegin; 80828b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine"); 80928b400f6SJacob Faibussowitsch PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name"); 810b77ba244SStefano Zampini 811b77ba244SStefano Zampini /* add product callback */ 812b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 813b77ba244SStefano Zampini matmat = shell->matmat; 814b77ba244SStefano Zampini if (!matmat) { 8159566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 816b77ba244SStefano Zampini matmat = shell->matmat; 817b77ba244SStefano Zampini } else { 818b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 819b77ba244SStefano Zampini while (entry) { 8209566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, entry->composedname, &flg)); 821b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 822b77ba244SStefano Zampini matmat = entry; 8232e956fe4SStefano Zampini if (flg) goto set; 824b77ba244SStefano Zampini entry = entry->next; 825b77ba244SStefano Zampini } 8269566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 827b77ba244SStefano Zampini matmat = matmat->next; 828b77ba244SStefano Zampini } 829b77ba244SStefano Zampini 830843d480fSStefano Zampini set: 831b77ba244SStefano Zampini matmat->symbolic = symbolic; 832b77ba244SStefano Zampini matmat->numeric = numeric; 833b77ba244SStefano Zampini matmat->destroy = destroy; 834b77ba244SStefano Zampini matmat->ptype = ptype; 8359566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8369566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8379566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname, &matmat->composedname)); 8389566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname, &matmat->resultname)); 8399566063dSJacob 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")); 8409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X)); 841b77ba244SStefano Zampini PetscFunctionReturn(0); 842b77ba244SStefano Zampini } 843b77ba244SStefano Zampini 844b77ba244SStefano Zampini /*@C 84511a5261eSBarry Smith MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix. 846b77ba244SStefano Zampini 84711a5261eSBarry Smith Logically Collective on A 848b77ba244SStefano Zampini 849b77ba244SStefano Zampini Input Parameters: 85011a5261eSBarry Smith + A - the `MATSHELL` shell matrix 851b77ba244SStefano Zampini . ptype - the product type 852b77ba244SStefano Zampini . symbolic - the function for the symbolic phase (can be NULL) 853b77ba244SStefano Zampini . numeric - the function for the numerical phase 854b77ba244SStefano Zampini . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL) 855b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 856b77ba244SStefano Zampini - Ctype - the matrix type for the result (can be NULL) 857b77ba244SStefano Zampini 858b77ba244SStefano Zampini Level: advanced 859b77ba244SStefano Zampini 860b77ba244SStefano Zampini Usage: 861b77ba244SStefano Zampini $ extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**); 862b77ba244SStefano Zampini $ extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*); 863b77ba244SStefano Zampini $ extern PetscErrorCode userdestroy(void*); 864b77ba244SStefano Zampini $ MatCreateShell(comm,m,n,M,N,ctx,&A); 865b77ba244SStefano Zampini $ MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE); 866b77ba244SStefano Zampini $ [ create B of type SEQAIJ etc..] 867b77ba244SStefano Zampini $ MatProductCreate(A,B,NULL,&C); 868b77ba244SStefano Zampini $ MatProductSetType(C,MATPRODUCT_AB); 869b77ba244SStefano Zampini $ MatProductSetFromOptions(C); 870b77ba244SStefano Zampini $ MatProductSymbolic(C); -> actually runs the user defined symbolic operation 871b77ba244SStefano Zampini $ MatProductNumeric(C); -> actually runs the user defined numeric operation 872b77ba244SStefano Zampini $ [ use C = A*B ] 873b77ba244SStefano Zampini 874b77ba244SStefano Zampini Notes: 87511a5261eSBarry Smith `MATPRODUCT_ABC` is not supported yet. Not supported in Fortran. 87611a5261eSBarry Smith 87711a5261eSBarry 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. 87811a5261eSBarry Smith 879b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 880b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 881b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 882b77ba244SStefano Zampini The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence. 883b77ba244SStefano Zampini 88411a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()` 885b77ba244SStefano Zampini @*/ 886d71ae5a4SJacob 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) 887d71ae5a4SJacob Faibussowitsch { 888b77ba244SStefano Zampini PetscFunctionBegin; 889b77ba244SStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 890b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A, ptype, 2); 89108401ef6SPierre Jolivet PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]); 89228b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4"); 893dadcf809SJacob Faibussowitsch PetscValidCharPointer(Btype, 6); 894dadcf809SJacob Faibussowitsch if (Ctype) PetscValidCharPointer(Ctype, 7); 895cac4c232SBarry 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)); 896b77ba244SStefano Zampini PetscFunctionReturn(0); 897b77ba244SStefano Zampini } 898b77ba244SStefano Zampini 899d71ae5a4SJacob 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) 900d71ae5a4SJacob Faibussowitsch { 901b77ba244SStefano Zampini PetscBool flg; 902b77ba244SStefano Zampini char composedname[256]; 903b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 904b77ba244SStefano Zampini PetscMPIInt size; 905b77ba244SStefano Zampini 906b77ba244SStefano Zampini PetscFunctionBegin; 907b77ba244SStefano Zampini PetscValidType(A, 1); 908b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 9099566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg)); 910b77ba244SStefano Zampini if (flg) break; 911b77ba244SStefano Zampini Bnames = Bnames->next; 912b77ba244SStefano Zampini } 913b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 9149566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg)); 915b77ba244SStefano Zampini if (flg) break; 916b77ba244SStefano Zampini Cnames = Cnames->next; 917b77ba244SStefano Zampini } 9189566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 919b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 920b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9219566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype)); 9229566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype)); 9233a40ed3dSBarry Smith PetscFunctionReturn(0); 924e51e0e81SBarry Smith } 925e51e0e81SBarry Smith 926d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str) 927d71ae5a4SJacob Faibussowitsch { 92828f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data; 929cb8c8a77SBarry Smith PetscBool matflg; 930b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9317fabda3fSAlex Fikl 9327fabda3fSAlex Fikl PetscFunctionBegin; 9339566063dSJacob Faibussowitsch PetscCall(MatIsShell(B, &matflg)); 93428b400f6SJacob Faibussowitsch PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name); 9357fabda3fSAlex Fikl 9369566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(B->ops, A->ops, sizeof(struct _MatOps))); 9379566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(shellB->ops, shellA->ops, sizeof(struct _MatShellOps))); 9387fabda3fSAlex Fikl 9391baa6e33SBarry Smith if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str)); 9407fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9417fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9420c0fd78eSBarry Smith if (shellA->dshift) { 94348a46eb9SPierre Jolivet if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift)); 9449566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift, shellB->dshift)); 9457fabda3fSAlex Fikl } else { 9469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9477fabda3fSAlex Fikl } 9480c0fd78eSBarry Smith if (shellA->left) { 94948a46eb9SPierre Jolivet if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left)); 9509566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left, shellB->left)); 9517fabda3fSAlex Fikl } else { 9529566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9537fabda3fSAlex Fikl } 9540c0fd78eSBarry Smith if (shellA->right) { 95548a46eb9SPierre Jolivet if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right)); 9569566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right, shellB->right)); 9577fabda3fSAlex Fikl } else { 9589566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9597fabda3fSAlex Fikl } 9609566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 961ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 962ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 96340e381c3SBarry Smith if (shellA->axpy) { 9649566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 96540e381c3SBarry Smith shellB->axpy = shellA->axpy; 96640e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 967ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 96840e381c3SBarry Smith } 96945960306SStefano Zampini if (shellA->zrows) { 9709566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows)); 97148a46eb9SPierre Jolivet if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols)); 9729566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals)); 9739566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals, shellB->zvals)); 9749566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w)); 9759566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 9769566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 97745960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 97845960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 97945960306SStefano Zampini } 980b77ba244SStefano Zampini 981b77ba244SStefano Zampini matmatA = shellA->matmat; 982b77ba244SStefano Zampini if (matmatA) { 983b77ba244SStefano Zampini while (matmatA->next) { 9849566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname)); 985b77ba244SStefano Zampini matmatA = matmatA->next; 986b77ba244SStefano Zampini } 987b77ba244SStefano Zampini } 9887fabda3fSAlex Fikl PetscFunctionReturn(0); 9897fabda3fSAlex Fikl } 9907fabda3fSAlex Fikl 991d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M) 992d71ae5a4SJacob Faibussowitsch { 993cb8c8a77SBarry Smith PetscFunctionBegin; 994800f99ffSJeremy L Thompson PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M)); 995800f99ffSJeremy L Thompson ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer; 996800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer)); 9979566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name)); 99848a46eb9SPierre Jolivet if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN)); 999cb8c8a77SBarry Smith PetscFunctionReturn(0); 1000cb8c8a77SBarry Smith } 1001cb8c8a77SBarry Smith 1002d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y) 1003d71ae5a4SJacob Faibussowitsch { 1004ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 100525578ef6SJed Brown Vec xx; 1006e3f487b0SBarry Smith PetscObjectState instate, outstate; 1007ef66eb69SBarry Smith 1008ef66eb69SBarry Smith PetscFunctionBegin; 10099566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A, x, &xx)); 10109566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A, xx, &xx)); 10119566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10129566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A, xx, y)); 10139566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1014e3f487b0SBarry Smith if (instate == outstate) { 1015e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10169566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1017e3f487b0SBarry Smith } 10189566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A, xx, y)); 10199566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A, y)); 10209566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A, y)); 10219f137db4SBarry Smith 10229f137db4SBarry Smith if (shell->axpy) { 1023ef5c7bd2SStefano Zampini Mat X; 1024ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1025ef5c7bd2SStefano Zampini 10269566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10279566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 102808401ef6SPierre 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,...)"); 1029b77ba244SStefano Zampini 10309566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10319566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_right)); 10329566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left)); 10339566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left)); 10349f137db4SBarry Smith } 1035ef66eb69SBarry Smith PetscFunctionReturn(0); 1036ef66eb69SBarry Smith } 1037ef66eb69SBarry Smith 1038d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1039d71ae5a4SJacob Faibussowitsch { 10405edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10415edf6516SJed Brown 10425edf6516SJed Brown PetscFunctionBegin; 10435edf6516SJed Brown if (y == z) { 10449566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work)); 10459566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, shell->right_add_work)); 10469566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->right_add_work)); 10475edf6516SJed Brown } else { 10489566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, z)); 10499566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 10505edf6516SJed Brown } 10515edf6516SJed Brown PetscFunctionReturn(0); 10525edf6516SJed Brown } 10535edf6516SJed Brown 1054d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y) 1055d71ae5a4SJacob Faibussowitsch { 105618be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 105725578ef6SJed Brown Vec xx; 1058e3f487b0SBarry Smith PetscObjectState instate, outstate; 105918be62a5SSatish Balay 106018be62a5SSatish Balay PetscFunctionBegin; 10619566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A, x, &xx)); 10629566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleLeft(A, xx, &xx)); 10639566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10649566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A, xx, y)); 10659566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1066e3f487b0SBarry Smith if (instate == outstate) { 1067e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10689566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1069e3f487b0SBarry Smith } 10709566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A, xx, y)); 10719566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleRight(A, y)); 10729566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A, y)); 1073350ec83bSStefano Zampini 1074350ec83bSStefano Zampini if (shell->axpy) { 1075ef5c7bd2SStefano Zampini Mat X; 1076ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1077ef5c7bd2SStefano Zampini 10789566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10799566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 108008401ef6SPierre 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,...)"); 10819566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10829566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_left)); 10839566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 10849566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right)); 1085350ec83bSStefano Zampini } 108618be62a5SSatish Balay PetscFunctionReturn(0); 108718be62a5SSatish Balay } 108818be62a5SSatish Balay 1089d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1090d71ae5a4SJacob Faibussowitsch { 10915edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10925edf6516SJed Brown 10935edf6516SJed Brown PetscFunctionBegin; 10945edf6516SJed Brown if (y == z) { 10959566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 10969566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, shell->left_add_work)); 10979566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 10985edf6516SJed Brown } else { 10999566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, z)); 11009566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 11015edf6516SJed Brown } 11025edf6516SJed Brown PetscFunctionReturn(0); 11035edf6516SJed Brown } 11045edf6516SJed Brown 11050c0fd78eSBarry Smith /* 11060c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11070c0fd78eSBarry Smith */ 1108d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v) 1109d71ae5a4SJacob Faibussowitsch { 111018be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 111118be62a5SSatish Balay 111218be62a5SSatish Balay PetscFunctionBegin; 11130c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 11149566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A, v)); 1115305211d5SBarry 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,...)"); 11169566063dSJacob Faibussowitsch PetscCall(VecScale(v, shell->vscale)); 11171baa6e33SBarry Smith if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift)); 11189566063dSJacob Faibussowitsch PetscCall(VecShift(v, shell->vshift)); 11199566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left)); 11209566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right)); 112145960306SStefano Zampini if (shell->zrows) { 11229566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 11239566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 112445960306SStefano Zampini } 112581c02519SBarry Smith if (shell->axpy) { 1126ef5c7bd2SStefano Zampini Mat X; 1127ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1128ef5c7bd2SStefano Zampini 11299566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 11309566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 113108401ef6SPierre 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,...)"); 11329566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left)); 11339566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left)); 11349566063dSJacob Faibussowitsch PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left)); 113581c02519SBarry Smith } 113618be62a5SSatish Balay PetscFunctionReturn(0); 113718be62a5SSatish Balay } 113818be62a5SSatish Balay 1139d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a) 1140d71ae5a4SJacob Faibussowitsch { 1141ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1142789d8953SBarry Smith PetscBool flg; 1143b24ad042SBarry Smith 1144ef66eb69SBarry Smith PetscFunctionBegin; 11459566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y, &flg)); 114628b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent"); 11470c0fd78eSBarry Smith if (shell->left || shell->right) { 11488fe8eb27SJed Brown if (!shell->dshift) { 11499566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 11509566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift, a)); 11510c0fd78eSBarry Smith } else { 11529566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left)); 11539566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right)); 11549566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift, a)); 11550c0fd78eSBarry Smith } 11569566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left)); 11579566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right)); 11588fe8eb27SJed Brown } else shell->vshift += a; 11591baa6e33SBarry Smith if (shell->zrows) PetscCall(VecShift(shell->zvals, a)); 1160ef66eb69SBarry Smith PetscFunctionReturn(0); 1161ef66eb69SBarry Smith } 1162ef66eb69SBarry Smith 1163d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s) 1164d71ae5a4SJacob Faibussowitsch { 11656464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell *)A->data; 11666464bf51SAlex Fikl 11676464bf51SAlex Fikl PetscFunctionBegin; 11689566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift)); 11690c0fd78eSBarry Smith if (shell->left || shell->right) { 11709566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 11719f137db4SBarry Smith if (shell->left && shell->right) { 11729566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 11739566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right)); 11749f137db4SBarry Smith } else if (shell->left) { 11759566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 11769f137db4SBarry Smith } else { 11779566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right)); 11789f137db4SBarry Smith } 11799566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, shell->right_work)); 11800c0fd78eSBarry Smith } else { 11819566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, D)); 1182b253ae0bS“Marek } 1183b253ae0bS“Marek PetscFunctionReturn(0); 1184b253ae0bS“Marek } 1185b253ae0bS“Marek 1186d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins) 1187d71ae5a4SJacob Faibussowitsch { 118845960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1189b253ae0bS“Marek Vec d; 1190789d8953SBarry Smith PetscBool flg; 1191b253ae0bS“Marek 1192b253ae0bS“Marek PetscFunctionBegin; 11939566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &flg)); 119428b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent"); 1195b253ae0bS“Marek if (ins == INSERT_VALUES) { 11969566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D, &d)); 11979566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A, d)); 11989566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.)); 11999566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 12011baa6e33SBarry Smith if (shell->zrows) PetscCall(VecCopy(D, shell->zvals)); 1202b253ae0bS“Marek } else { 12039566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12041baa6e33SBarry Smith if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D)); 12056464bf51SAlex Fikl } 12066464bf51SAlex Fikl PetscFunctionReturn(0); 12076464bf51SAlex Fikl } 12086464bf51SAlex Fikl 1209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a) 1210d71ae5a4SJacob Faibussowitsch { 1211ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1212b24ad042SBarry Smith 1213ef66eb69SBarry Smith PetscFunctionBegin; 1214f4df32b1SMatthew Knepley shell->vscale *= a; 12150c0fd78eSBarry Smith shell->vshift *= a; 12161baa6e33SBarry Smith if (shell->dshift) PetscCall(VecScale(shell->dshift, a)); 121781c02519SBarry Smith shell->axpy_vscale *= a; 12181baa6e33SBarry Smith if (shell->zrows) PetscCall(VecScale(shell->zvals, a)); 12198fe8eb27SJed Brown PetscFunctionReturn(0); 122018be62a5SSatish Balay } 12218fe8eb27SJed Brown 1222d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right) 1223d71ae5a4SJacob Faibussowitsch { 12248fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)Y->data; 12258fe8eb27SJed Brown 12268fe8eb27SJed Brown PetscFunctionBegin; 12278fe8eb27SJed Brown if (left) { 12280c0fd78eSBarry Smith if (!shell->left) { 12299566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left, &shell->left)); 12309566063dSJacob Faibussowitsch PetscCall(VecCopy(left, shell->left)); 12310c0fd78eSBarry Smith } else { 12329566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left, shell->left, left)); 123318be62a5SSatish Balay } 12341baa6e33SBarry Smith if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left)); 1235ef66eb69SBarry Smith } 12368fe8eb27SJed Brown if (right) { 12370c0fd78eSBarry Smith if (!shell->right) { 12389566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right, &shell->right)); 12399566063dSJacob Faibussowitsch PetscCall(VecCopy(right, shell->right)); 12400c0fd78eSBarry Smith } else { 12419566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right, shell->right, right)); 12428fe8eb27SJed Brown } 124345960306SStefano Zampini if (shell->zrows) { 124448a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work)); 12459566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 1.0)); 12469566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12479566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 12489566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w)); 124945960306SStefano Zampini } 12508fe8eb27SJed Brown } 12511baa6e33SBarry Smith if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right)); 1252ef66eb69SBarry Smith PetscFunctionReturn(0); 1253ef66eb69SBarry Smith } 1254ef66eb69SBarry Smith 1255d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t) 1256d71ae5a4SJacob Faibussowitsch { 1257ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1258ef66eb69SBarry Smith 1259ef66eb69SBarry Smith PetscFunctionBegin; 12608fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1261ef66eb69SBarry Smith shell->vshift = 0.0; 1262ef66eb69SBarry Smith shell->vscale = 1.0; 1263ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1264ef5c7bd2SStefano Zampini shell->axpy_state = 0; 12659566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 12669566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 12679566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 12689566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 12699566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 12709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 12719566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 12729566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 12739566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 12749566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1275ef66eb69SBarry Smith } 1276ef66eb69SBarry Smith PetscFunctionReturn(0); 1277ef66eb69SBarry Smith } 1278ef66eb69SBarry Smith 1279d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d) 1280d71ae5a4SJacob Faibussowitsch { 12813b49f96aSBarry Smith PetscFunctionBegin; 12823b49f96aSBarry Smith *missing = PETSC_FALSE; 12833b49f96aSBarry Smith PetscFunctionReturn(0); 12843b49f96aSBarry Smith } 12853b49f96aSBarry Smith 1286d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str) 1287d71ae5a4SJacob Faibussowitsch { 12889f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 12899f137db4SBarry Smith 12909f137db4SBarry Smith PetscFunctionBegin; 1291ef5c7bd2SStefano Zampini if (X == Y) { 12929566063dSJacob Faibussowitsch PetscCall(MatScale(Y, 1.0 + a)); 1293ef5c7bd2SStefano Zampini PetscFunctionReturn(0); 1294ef5c7bd2SStefano Zampini } 1295ef5c7bd2SStefano Zampini if (!shell->axpy) { 12969566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy)); 12979f137db4SBarry Smith shell->axpy_vscale = a; 12989566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state)); 1299ef5c7bd2SStefano Zampini } else { 13009566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str)); 1301ef5c7bd2SStefano Zampini } 13029f137db4SBarry Smith PetscFunctionReturn(0); 13039f137db4SBarry Smith } 13049f137db4SBarry Smith 1305f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1306f4259b30SLisandro Dalcin NULL, 1307f4259b30SLisandro Dalcin NULL, 1308f4259b30SLisandro Dalcin NULL, 13090c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1310f4259b30SLisandro Dalcin NULL, 13110c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1312f4259b30SLisandro Dalcin NULL, 1313f4259b30SLisandro Dalcin NULL, 1314f4259b30SLisandro Dalcin NULL, 1315f4259b30SLisandro Dalcin /*10*/ NULL, 1316f4259b30SLisandro Dalcin NULL, 1317f4259b30SLisandro Dalcin NULL, 1318f4259b30SLisandro Dalcin NULL, 1319f4259b30SLisandro Dalcin NULL, 1320f4259b30SLisandro Dalcin /*15*/ NULL, 1321f4259b30SLisandro Dalcin NULL, 1322f4259b30SLisandro Dalcin NULL, 13238fe8eb27SJed Brown MatDiagonalScale_Shell, 1324f4259b30SLisandro Dalcin NULL, 1325f4259b30SLisandro Dalcin /*20*/ NULL, 1326ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1327f4259b30SLisandro Dalcin NULL, 1328f4259b30SLisandro Dalcin NULL, 132945960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1330f4259b30SLisandro Dalcin NULL, 1331f4259b30SLisandro Dalcin NULL, 1332f4259b30SLisandro Dalcin NULL, 1333f4259b30SLisandro Dalcin NULL, 1334f4259b30SLisandro Dalcin /*29*/ NULL, 1335f4259b30SLisandro Dalcin NULL, 1336f4259b30SLisandro Dalcin NULL, 1337f4259b30SLisandro Dalcin NULL, 1338f4259b30SLisandro Dalcin NULL, 1339cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1340f4259b30SLisandro Dalcin NULL, 1341f4259b30SLisandro Dalcin NULL, 1342f4259b30SLisandro Dalcin NULL, 1343f4259b30SLisandro Dalcin NULL, 13449f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1345f4259b30SLisandro Dalcin NULL, 1346f4259b30SLisandro Dalcin NULL, 1347f4259b30SLisandro Dalcin NULL, 1348cb8c8a77SBarry Smith MatCopy_Shell, 1349f4259b30SLisandro Dalcin /*44*/ NULL, 1350ef66eb69SBarry Smith MatScale_Shell, 1351ef66eb69SBarry Smith MatShift_Shell, 13526464bf51SAlex Fikl MatDiagonalSet_Shell, 135345960306SStefano Zampini MatZeroRowsColumns_Shell, 1354f4259b30SLisandro Dalcin /*49*/ NULL, 1355f4259b30SLisandro Dalcin NULL, 1356f4259b30SLisandro Dalcin NULL, 1357f4259b30SLisandro Dalcin NULL, 1358f4259b30SLisandro Dalcin NULL, 1359f4259b30SLisandro Dalcin /*54*/ NULL, 1360f4259b30SLisandro Dalcin NULL, 1361f4259b30SLisandro Dalcin NULL, 1362f4259b30SLisandro Dalcin NULL, 1363f4259b30SLisandro Dalcin NULL, 1364f4259b30SLisandro Dalcin /*59*/ NULL, 1365b9b97703SBarry Smith MatDestroy_Shell, 1366f4259b30SLisandro Dalcin NULL, 1367251fad3fSStefano Zampini MatConvertFrom_Shell, 1368f4259b30SLisandro Dalcin NULL, 1369f4259b30SLisandro Dalcin /*64*/ NULL, 1370f4259b30SLisandro Dalcin NULL, 1371f4259b30SLisandro Dalcin NULL, 1372f4259b30SLisandro Dalcin NULL, 1373f4259b30SLisandro Dalcin NULL, 1374f4259b30SLisandro Dalcin /*69*/ NULL, 1375f4259b30SLisandro Dalcin NULL, 1376c87e5d42SMatthew Knepley MatConvert_Shell, 1377f4259b30SLisandro Dalcin NULL, 1378f4259b30SLisandro Dalcin NULL, 1379f4259b30SLisandro Dalcin /*74*/ NULL, 1380f4259b30SLisandro Dalcin NULL, 1381f4259b30SLisandro Dalcin NULL, 1382f4259b30SLisandro Dalcin NULL, 1383f4259b30SLisandro Dalcin NULL, 1384f4259b30SLisandro Dalcin /*79*/ NULL, 1385f4259b30SLisandro Dalcin NULL, 1386f4259b30SLisandro Dalcin NULL, 1387f4259b30SLisandro Dalcin NULL, 1388f4259b30SLisandro Dalcin NULL, 1389f4259b30SLisandro Dalcin /*84*/ NULL, 1390f4259b30SLisandro Dalcin NULL, 1391f4259b30SLisandro Dalcin NULL, 1392f4259b30SLisandro Dalcin NULL, 1393f4259b30SLisandro Dalcin NULL, 1394f4259b30SLisandro Dalcin /*89*/ NULL, 1395f4259b30SLisandro Dalcin NULL, 1396f4259b30SLisandro Dalcin NULL, 1397f4259b30SLisandro Dalcin NULL, 1398f4259b30SLisandro Dalcin NULL, 1399f4259b30SLisandro Dalcin /*94*/ NULL, 1400f4259b30SLisandro Dalcin NULL, 1401f4259b30SLisandro Dalcin NULL, 1402f4259b30SLisandro Dalcin NULL, 1403f4259b30SLisandro Dalcin NULL, 1404f4259b30SLisandro Dalcin /*99*/ NULL, 1405f4259b30SLisandro Dalcin NULL, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin NULL, 1408f4259b30SLisandro Dalcin NULL, 1409f4259b30SLisandro Dalcin /*104*/ NULL, 1410f4259b30SLisandro Dalcin NULL, 1411f4259b30SLisandro Dalcin NULL, 1412f4259b30SLisandro Dalcin NULL, 1413f4259b30SLisandro Dalcin NULL, 1414f4259b30SLisandro Dalcin /*109*/ NULL, 1415f4259b30SLisandro Dalcin NULL, 1416f4259b30SLisandro Dalcin NULL, 1417f4259b30SLisandro Dalcin NULL, 14183b49f96aSBarry Smith MatMissingDiagonal_Shell, 1419f4259b30SLisandro Dalcin /*114*/ NULL, 1420f4259b30SLisandro Dalcin NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin NULL, 1423f4259b30SLisandro Dalcin NULL, 1424f4259b30SLisandro Dalcin /*119*/ NULL, 1425f4259b30SLisandro Dalcin NULL, 1426f4259b30SLisandro Dalcin NULL, 1427f4259b30SLisandro Dalcin NULL, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin /*124*/ NULL, 1430f4259b30SLisandro Dalcin NULL, 1431f4259b30SLisandro Dalcin NULL, 1432f4259b30SLisandro Dalcin NULL, 1433f4259b30SLisandro Dalcin NULL, 1434f4259b30SLisandro Dalcin /*129*/ NULL, 1435f4259b30SLisandro Dalcin NULL, 1436f4259b30SLisandro Dalcin NULL, 1437f4259b30SLisandro Dalcin NULL, 1438f4259b30SLisandro Dalcin NULL, 1439f4259b30SLisandro Dalcin /*134*/ NULL, 1440f4259b30SLisandro Dalcin NULL, 1441f4259b30SLisandro Dalcin NULL, 1442f4259b30SLisandro Dalcin NULL, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin /*139*/ NULL, 1445f4259b30SLisandro Dalcin NULL, 1446d70f29a3SPierre Jolivet NULL, 1447d70f29a3SPierre Jolivet NULL, 1448d70f29a3SPierre Jolivet NULL, 1449d70f29a3SPierre Jolivet /*144*/ NULL, 1450d70f29a3SPierre Jolivet NULL, 1451d70f29a3SPierre Jolivet NULL, 145299a7f59eSMark Adams NULL, 145399a7f59eSMark Adams NULL, 14547fb60732SBarry Smith NULL, 1455*dec0b466SHong Zhang /*150*/ NULL, 1456*dec0b466SHong Zhang NULL}; 1457273d9f13SBarry Smith 1458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx) 1459d71ae5a4SJacob Faibussowitsch { 1460789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1461789d8953SBarry Smith 1462789d8953SBarry Smith PetscFunctionBegin; 1463800f99ffSJeremy L Thompson if (ctx) { 1464800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 1465800f99ffSJeremy L Thompson PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer)); 1466800f99ffSJeremy L Thompson PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 1467800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer)); 1468800f99ffSJeremy L Thompson shell->ctxcontainer = ctxcontainer; 1469800f99ffSJeremy L Thompson PetscCall(PetscContainerDestroy(&ctxcontainer)); 1470800f99ffSJeremy L Thompson } else { 1471800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL)); 1472800f99ffSJeremy L Thompson shell->ctxcontainer = NULL; 1473800f99ffSJeremy L Thompson } 1474800f99ffSJeremy L Thompson 1475800f99ffSJeremy L Thompson PetscFunctionReturn(0); 1476800f99ffSJeremy L Thompson } 1477800f99ffSJeremy L Thompson 1478d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *)) 1479d71ae5a4SJacob Faibussowitsch { 1480800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 1481800f99ffSJeremy L Thompson 1482800f99ffSJeremy L Thompson PetscFunctionBegin; 1483800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f)); 1484789d8953SBarry Smith PetscFunctionReturn(0); 1485789d8953SBarry Smith } 1486789d8953SBarry Smith 1487d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype) 1488d71ae5a4SJacob Faibussowitsch { 1489db77db73SJeremy L Thompson PetscFunctionBegin; 14909566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 14919566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype)); 1492db77db73SJeremy L Thompson PetscFunctionReturn(0); 1493db77db73SJeremy L Thompson } 1494db77db73SJeremy L Thompson 1495d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1496d71ae5a4SJacob Faibussowitsch { 1497789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 1498789d8953SBarry Smith 1499789d8953SBarry Smith PetscFunctionBegin; 1500789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1501789d8953SBarry Smith A->ops->diagonalset = NULL; 1502789d8953SBarry Smith A->ops->diagonalscale = NULL; 1503789d8953SBarry Smith A->ops->scale = NULL; 1504789d8953SBarry Smith A->ops->shift = NULL; 1505789d8953SBarry Smith A->ops->axpy = NULL; 1506789d8953SBarry Smith PetscFunctionReturn(0); 1507789d8953SBarry Smith } 1508789d8953SBarry Smith 1509d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void)) 1510d71ae5a4SJacob Faibussowitsch { 1511feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell *)mat->data; 1512789d8953SBarry Smith 1513789d8953SBarry Smith PetscFunctionBegin; 1514789d8953SBarry Smith switch (op) { 1515d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1516d71ae5a4SJacob Faibussowitsch shell->ops->destroy = (PetscErrorCode(*)(Mat))f; 1517d71ae5a4SJacob Faibussowitsch break; 1518789d8953SBarry Smith case MATOP_VIEW: 1519ad540459SPierre Jolivet if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view; 1520789d8953SBarry Smith mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f; 1521789d8953SBarry Smith break; 1522d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1523d71ae5a4SJacob Faibussowitsch shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f; 1524d71ae5a4SJacob Faibussowitsch break; 1525789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1526789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1527789d8953SBarry Smith case MATOP_SHIFT: 1528789d8953SBarry Smith case MATOP_SCALE: 1529789d8953SBarry Smith case MATOP_AXPY: 1530789d8953SBarry Smith case MATOP_ZERO_ROWS: 1531789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 153228b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1533789d8953SBarry Smith (((void (**)(void))mat->ops)[op]) = f; 1534789d8953SBarry Smith break; 1535789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1536789d8953SBarry Smith if (shell->managescalingshifts) { 1537789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1538789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1539789d8953SBarry Smith } else { 1540789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1541789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1542789d8953SBarry Smith } 1543789d8953SBarry Smith break; 1544789d8953SBarry Smith case MATOP_MULT: 1545789d8953SBarry Smith if (shell->managescalingshifts) { 1546789d8953SBarry Smith shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1547789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1548789d8953SBarry Smith } else { 1549789d8953SBarry Smith shell->ops->mult = NULL; 1550789d8953SBarry Smith mat->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1551789d8953SBarry Smith } 1552789d8953SBarry Smith break; 1553789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1554789d8953SBarry Smith if (shell->managescalingshifts) { 1555789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1556789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1557789d8953SBarry Smith } else { 1558789d8953SBarry Smith shell->ops->multtranspose = NULL; 1559789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1560789d8953SBarry Smith } 1561789d8953SBarry Smith break; 1562d71ae5a4SJacob Faibussowitsch default: 1563d71ae5a4SJacob Faibussowitsch (((void (**)(void))mat->ops)[op]) = f; 1564d71ae5a4SJacob Faibussowitsch break; 1565789d8953SBarry Smith } 1566789d8953SBarry Smith PetscFunctionReturn(0); 1567789d8953SBarry Smith } 1568789d8953SBarry Smith 1569d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void)) 1570d71ae5a4SJacob Faibussowitsch { 1571789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1572789d8953SBarry Smith 1573789d8953SBarry Smith PetscFunctionBegin; 1574789d8953SBarry Smith switch (op) { 1575d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1576d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->destroy; 1577d71ae5a4SJacob Faibussowitsch break; 1578d71ae5a4SJacob Faibussowitsch case MATOP_VIEW: 1579d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))mat->ops->view; 1580d71ae5a4SJacob Faibussowitsch break; 1581d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1582d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->copy; 1583d71ae5a4SJacob Faibussowitsch break; 1584789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1585789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1586789d8953SBarry Smith case MATOP_SHIFT: 1587789d8953SBarry Smith case MATOP_SCALE: 1588789d8953SBarry Smith case MATOP_AXPY: 1589789d8953SBarry Smith case MATOP_ZERO_ROWS: 1590d71ae5a4SJacob Faibussowitsch case MATOP_ZERO_ROWS_COLUMNS: 1591d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1592d71ae5a4SJacob Faibussowitsch break; 1593789d8953SBarry Smith case MATOP_GET_DIAGONAL: 15949371c9d4SSatish Balay if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal; 15959371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1596789d8953SBarry Smith break; 1597789d8953SBarry Smith case MATOP_MULT: 15989371c9d4SSatish Balay if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult; 15999371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1600789d8953SBarry Smith break; 1601789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 16029371c9d4SSatish Balay if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose; 16039371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1604789d8953SBarry Smith break; 1605d71ae5a4SJacob Faibussowitsch default: 1606d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1607789d8953SBarry Smith } 1608789d8953SBarry Smith PetscFunctionReturn(0); 1609789d8953SBarry Smith } 1610789d8953SBarry Smith 16110bad9183SKris Buschelman /*MC 1612fafad747SKris Buschelman MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 16130bad9183SKris Buschelman 16140bad9183SKris Buschelman Level: advanced 16150bad9183SKris Buschelman 161611a5261eSBarry Smith .seealso: `Mat`, `MatCreateShell()` 16170bad9183SKris Buschelman M*/ 16180bad9183SKris Buschelman 1619d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1620d71ae5a4SJacob Faibussowitsch { 1621273d9f13SBarry Smith Mat_Shell *b; 1622273d9f13SBarry Smith 1623273d9f13SBarry Smith PetscFunctionBegin; 16249566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps))); 1625273d9f13SBarry Smith 16264dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&b)); 1627273d9f13SBarry Smith A->data = (void *)b; 1628273d9f13SBarry Smith 1629800f99ffSJeremy L Thompson b->ctxcontainer = NULL; 1630ef66eb69SBarry Smith b->vshift = 0.0; 1631ef66eb69SBarry Smith b->vscale = 1.0; 16320c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1633273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1634210f0121SBarry Smith A->preallocated = PETSC_FALSE; 16352205254eSKarl Rupp 16369566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell)); 16379566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell)); 1638800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell)); 16399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell)); 16409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell)); 16419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell)); 16429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell)); 16439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell)); 16449566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL)); 1645273d9f13SBarry Smith PetscFunctionReturn(0); 1646273d9f13SBarry Smith } 1647e51e0e81SBarry Smith 16484b828684SBarry Smith /*@C 164911a5261eSBarry Smith MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined 1650ff756334SLois Curfman McInnes private data storage format. 1651e51e0e81SBarry Smith 1652d083f849SBarry Smith Collective 1653c7fcc2eaSBarry Smith 1654e51e0e81SBarry Smith Input Parameters: 1655c7fcc2eaSBarry Smith + comm - MPI communicator 1656c7fcc2eaSBarry Smith . m - number of local rows (must be given) 1657c7fcc2eaSBarry Smith . n - number of local columns (must be given) 1658c7fcc2eaSBarry Smith . M - number of global rows (may be PETSC_DETERMINE) 1659c7fcc2eaSBarry Smith . N - number of global columns (may be PETSC_DETERMINE) 1660c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1661e51e0e81SBarry Smith 1662ff756334SLois Curfman McInnes Output Parameter: 166344cd7ae7SLois Curfman McInnes . A - the matrix 1664e51e0e81SBarry Smith 1665ff2fd236SBarry Smith Level: advanced 1666ff2fd236SBarry Smith 1667f39d1f56SLois Curfman McInnes Usage: 16685bd1e576SStefano Zampini $ extern PetscErrorCode mult(Mat,Vec,Vec); 1669f39d1f56SLois Curfman McInnes $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 1670c134de8dSSatish Balay $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1671f39d1f56SLois Curfman McInnes $ [ Use matrix for operations that have been set ] 1672f39d1f56SLois Curfman McInnes $ MatDestroy(mat); 1673f39d1f56SLois Curfman McInnes 1674ff756334SLois Curfman McInnes Notes: 1675ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 167611a5261eSBarry Smith with `KSP` (such as, for use with matrix-free methods). You should not 1677ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1678e51e0e81SBarry Smith 1679f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1680f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 1681645985a0SLois Curfman McInnes creating a shell matrix, A, that supports parallel matrix-vector 168211a5261eSBarry Smith products using `MatMult`(A,x,y) the user should set the number 1683645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1684645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1685645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1686645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1687645985a0SLois Curfman McInnes For example, 1688f39d1f56SLois Curfman McInnes 1689f39d1f56SLois Curfman McInnes $ 1690f39d1f56SLois Curfman McInnes $ Vec x, y 16915bd1e576SStefano Zampini $ extern PetscErrorCode mult(Mat,Vec,Vec); 1692645985a0SLois Curfman McInnes $ Mat A 1693f39d1f56SLois Curfman McInnes $ 1694c94f878dSBarry Smith $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 1695c94f878dSBarry Smith $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 1696f39d1f56SLois Curfman McInnes $ VecGetLocalSize(y,&m); 1697c7fcc2eaSBarry Smith $ VecGetLocalSize(x,&n); 1698c7fcc2eaSBarry Smith $ MatCreateShell(comm,m,n,M,N,ctx,&A); 1699c134de8dSSatish Balay $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1700645985a0SLois Curfman McInnes $ MatMult(A,x,y); 170145960306SStefano Zampini $ MatDestroy(&A); 170245960306SStefano Zampini $ VecDestroy(&y); 170345960306SStefano Zampini $ VecDestroy(&x); 1704645985a0SLois Curfman McInnes $ 1705e51e0e81SBarry Smith 170611a5261eSBarry Smith `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` internally, so these 170711a5261eSBarry Smith operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called. 17089b53d762SBarry Smith 17090c0fd78eSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 17100c0fd78eSBarry Smith 171195452b02SPatrick Sanan Developers Notes: 171295452b02SPatrick Sanan Regarding shifting and scaling. The general form is 17130c0fd78eSBarry Smith 17140c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 17150c0fd78eSBarry Smith 17160c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 17170c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 17180c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 17190c0fd78eSBarry Smith 17200c0fd78eSBarry Smith A is the user provided function. 17210c0fd78eSBarry Smith 172211a5261eSBarry Smith `KSP`/`PC` uses changes in the` Mat`'s "state" to decide if preconditioners need to be rebuilt: `PCSetUp()` only calls the setup() for 172311a5261eSBarry Smith for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger 172411a5261eSBarry Smith an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat); 172511a5261eSBarry Smith each time the `MATSHELL` matrix has changed. 1726ad2f5c3fSBarry Smith 172711a5261eSBarry Smith Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()` 1728b77ba244SStefano Zampini 172911a5261eSBarry Smith Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided 173011a5261eSBarry Smith with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`. 1731ad2f5c3fSBarry Smith 173211a5261eSBarry Smith Fortran Note: 173311a5261eSBarry Smith To use this from Fortran with a ctx you must write an interface definition for this 173411a5261eSBarry Smith function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing 173511a5261eSBarry Smith in as the ctx argument. 173611a5261eSBarry Smith 173711a5261eSBarry Smith .seealso: `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MATSHELL`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 1738e51e0e81SBarry Smith @*/ 1739d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A) 1740d71ae5a4SJacob Faibussowitsch { 17413a40ed3dSBarry Smith PetscFunctionBegin; 17429566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, A)); 17439566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A, m, n, M, N)); 17449566063dSJacob Faibussowitsch PetscCall(MatSetType(*A, MATSHELL)); 17459566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A, ctx)); 17469566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 1747273d9f13SBarry Smith PetscFunctionReturn(0); 1748c7fcc2eaSBarry Smith } 1749c7fcc2eaSBarry Smith 1750c6866cfdSSatish Balay /*@ 175111a5261eSBarry Smith MatShellSetContext - sets the context for a `MATSHELL` shell matrix 1752c7fcc2eaSBarry Smith 175311a5261eSBarry Smith Logically Collective on mat 1754c7fcc2eaSBarry Smith 1755273d9f13SBarry Smith Input Parameters: 175611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1757273d9f13SBarry Smith - ctx - the context 1758273d9f13SBarry Smith 1759273d9f13SBarry Smith Level: advanced 1760273d9f13SBarry Smith 176111a5261eSBarry Smith Fortran Note: 176295452b02SPatrick Sanan To use this from Fortran you must write a Fortran interface definition for this 1763daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 1764273d9f13SBarry Smith 176511a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()` 17660bc0a719SBarry Smith @*/ 1767d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx) 1768d71ae5a4SJacob Faibussowitsch { 1769273d9f13SBarry Smith PetscFunctionBegin; 17700700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1771cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx)); 17723a40ed3dSBarry Smith PetscFunctionReturn(0); 1773e51e0e81SBarry Smith } 1774e51e0e81SBarry Smith 1775800f99ffSJeremy L Thompson /*@ 177611a5261eSBarry Smith MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context 1777800f99ffSJeremy L Thompson 177811a5261eSBarry Smith Logically Collective on mat 1779800f99ffSJeremy L Thompson 1780800f99ffSJeremy L Thompson Input Parameters: 1781800f99ffSJeremy L Thompson + mat - the shell matrix 1782800f99ffSJeremy L Thompson - f - the context destroy function 1783800f99ffSJeremy L Thompson 1784800f99ffSJeremy L Thompson Note: 1785800f99ffSJeremy L Thompson If the `MatShell` is never duplicated, the behavior of this function is equivalent 178611a5261eSBarry Smith to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()` 1787800f99ffSJeremy L Thompson ensures proper reference counting for the user provided context data in the case that 178811a5261eSBarry Smith the `MATSHELL` is duplicated. 1789800f99ffSJeremy L Thompson 1790800f99ffSJeremy L Thompson Level: advanced 1791800f99ffSJeremy L Thompson 179211a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()` 1793800f99ffSJeremy L Thompson @*/ 1794d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *)) 1795d71ae5a4SJacob Faibussowitsch { 1796800f99ffSJeremy L Thompson PetscFunctionBegin; 1797800f99ffSJeremy L Thompson PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1798800f99ffSJeremy L Thompson PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f)); 1799800f99ffSJeremy L Thompson PetscFunctionReturn(0); 1800800f99ffSJeremy L Thompson } 1801800f99ffSJeremy L Thompson 1802db77db73SJeremy L Thompson /*@C 180311a5261eSBarry Smith MatShellSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1804db77db73SJeremy L Thompson 1805db77db73SJeremy L Thompson Logically collective 1806db77db73SJeremy L Thompson 1807db77db73SJeremy L Thompson Input Parameters: 180811a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1809db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1810db77db73SJeremy L Thompson 1811db77db73SJeremy L Thompson Level: advanced 1812db77db73SJeremy L Thompson 181311a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateVecs()` 1814db77db73SJeremy L Thompson @*/ 1815d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype) 1816d71ae5a4SJacob Faibussowitsch { 1817db77db73SJeremy L Thompson PetscFunctionBegin; 1818cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype)); 1819db77db73SJeremy L Thompson PetscFunctionReturn(0); 1820db77db73SJeremy L Thompson } 1821db77db73SJeremy L Thompson 18220c0fd78eSBarry Smith /*@ 182311a5261eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately 182411a5261eSBarry Smith after `MatCreateShell()` 18250c0fd78eSBarry Smith 182611a5261eSBarry Smith Logically Collective on A 18270c0fd78eSBarry Smith 18280c0fd78eSBarry Smith Input Parameter: 182911a5261eSBarry Smith . mat - the `MATSHELL` shell matrix 18300c0fd78eSBarry Smith 18310c0fd78eSBarry Smith Level: advanced 18320c0fd78eSBarry Smith 183311a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()` 18340c0fd78eSBarry Smith @*/ 1835d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1836d71ae5a4SJacob Faibussowitsch { 18370c0fd78eSBarry Smith PetscFunctionBegin; 18380c0fd78eSBarry Smith PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1839cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A)); 18400c0fd78eSBarry Smith PetscFunctionReturn(0); 18410c0fd78eSBarry Smith } 18420c0fd78eSBarry Smith 1843c16cb8f2SBarry Smith /*@C 184411a5261eSBarry Smith MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function. 1845f3b1f45cSBarry Smith 184611a5261eSBarry Smith Logically Collective on mat 1847f3b1f45cSBarry Smith 1848f3b1f45cSBarry Smith Input Parameters: 184911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1850f3b1f45cSBarry Smith . f - the function 185111a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1852f3b1f45cSBarry Smith - ctx - an optional context for the function 1853f3b1f45cSBarry Smith 1854f3b1f45cSBarry Smith Output Parameter: 185511a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1856f3b1f45cSBarry Smith 1857f3b1f45cSBarry Smith Options Database: 1858f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1859f3b1f45cSBarry Smith 1860f3b1f45cSBarry Smith Level: advanced 1861f3b1f45cSBarry Smith 186211a5261eSBarry Smith Fortran Note: 186395452b02SPatrick Sanan Not supported from Fortran 1864f3b1f45cSBarry Smith 186511a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()` 1866f3b1f45cSBarry Smith @*/ 1867d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1868d71ae5a4SJacob Faibussowitsch { 1869f3b1f45cSBarry Smith PetscInt m, n; 1870f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1871f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 187274e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1873f3b1f45cSBarry Smith 1874f3b1f45cSBarry Smith PetscFunctionBegin; 1875f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 18769566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v)); 18779566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 18789566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf)); 18799566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 18809566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 1881f3b1f45cSBarry Smith 18829566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 18839566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat)); 1884f3b1f45cSBarry Smith 18859566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 18869566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 18879566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 18889566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 1889f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 1890f3b1f45cSBarry Smith flag = PETSC_FALSE; 1891f3b1f45cSBarry Smith if (v) { 18929566063dSJacob Faibussowitsch 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))); 18939566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view")); 18949566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view")); 18959566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view")); 1896f3b1f45cSBarry Smith } 1897f3b1f45cSBarry Smith } else if (v) { 18989566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix free multiple appear to produce the same results\n")); 1899f3b1f45cSBarry Smith } 1900f3b1f45cSBarry Smith if (flg) *flg = flag; 19019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19029566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19039566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19049566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 1905f3b1f45cSBarry Smith PetscFunctionReturn(0); 1906f3b1f45cSBarry Smith } 1907f3b1f45cSBarry Smith 1908f3b1f45cSBarry Smith /*@C 190911a5261eSBarry Smith MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function. 1910f3b1f45cSBarry Smith 191111a5261eSBarry Smith Logically Collective on mat 1912f3b1f45cSBarry Smith 1913f3b1f45cSBarry Smith Input Parameters: 191411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1915f3b1f45cSBarry Smith . f - the function 191611a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1917f3b1f45cSBarry Smith - ctx - an optional context for the function 1918f3b1f45cSBarry Smith 1919f3b1f45cSBarry Smith Output Parameter: 192011a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1921f3b1f45cSBarry Smith 1922f3b1f45cSBarry Smith Options Database: 1923f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1924f3b1f45cSBarry Smith 1925f3b1f45cSBarry Smith Level: advanced 1926f3b1f45cSBarry Smith 192711a5261eSBarry Smith Fortran Note: 192895452b02SPatrick Sanan Not supported from Fortran 1929f3b1f45cSBarry Smith 193011a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()` 1931f3b1f45cSBarry Smith @*/ 1932d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1933d71ae5a4SJacob Faibussowitsch { 1934f3b1f45cSBarry Smith Vec x, y, z; 1935f3b1f45cSBarry Smith PetscInt m, n, M, N; 1936f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1937f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 193874e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1939f3b1f45cSBarry Smith 1940f3b1f45cSBarry Smith PetscFunctionBegin; 1941f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 19429566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v)); 19439566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &y)); 19449566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &z)); 19459566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 19469566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 19479566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf)); 19489566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 19499566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 19509566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 19519566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf)); 19529566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat)); 1953f3b1f45cSBarry Smith 19549566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 19559566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 19569566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 19579566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 1958f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 1959f3b1f45cSBarry Smith flag = PETSC_FALSE; 1960f3b1f45cSBarry Smith if (v) { 19619566063dSJacob Faibussowitsch 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))); 19629566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 19639566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 19649566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 1965f3b1f45cSBarry Smith } 1966f3b1f45cSBarry Smith } else if (v) { 19679566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix free multiple appear to produce the same results\n")); 1968f3b1f45cSBarry Smith } 1969f3b1f45cSBarry Smith if (flg) *flg = flag; 19709566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19719566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 19729566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 19759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 19769566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 1977f3b1f45cSBarry Smith PetscFunctionReturn(0); 1978f3b1f45cSBarry Smith } 1979f3b1f45cSBarry Smith 1980f3b1f45cSBarry Smith /*@C 198111a5261eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix. 1982e51e0e81SBarry Smith 198311a5261eSBarry Smith Logically Collective on mat 1984fee21e36SBarry Smith 1985c7fcc2eaSBarry Smith Input Parameters: 198611a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1987c7fcc2eaSBarry Smith . op - the name of the operation 1988789d8953SBarry Smith - g - the function that provides the operation. 1989c7fcc2eaSBarry Smith 199015091d37SBarry Smith Level: advanced 199115091d37SBarry Smith 1992fae171e0SBarry Smith Usage: 1993e93bc3c1Svictor $ extern PetscErrorCode usermult(Mat,Vec,Vec); 1994b77ba244SStefano Zampini $ MatCreateShell(comm,m,n,M,N,ctx,&A); 1995b77ba244SStefano Zampini $ MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 19960b627109SLois Curfman McInnes 1997a62d957aSLois Curfman McInnes Notes: 1998e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 19991c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2000a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 200111a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2002a62d957aSLois Curfman McInnes 200311a5261eSBarry Smith All user-provided functions (except for `MATOP_DESTROY`) should have the same calling 2004deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2005deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2006deebb3c3SLois Curfman McInnes routines, e.g., 2007a62d957aSLois Curfman McInnes $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2008a62d957aSLois Curfman McInnes 20094aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 20104aa34b0aSBarry Smith nonzero on failure. 20114aa34b0aSBarry Smith 2012a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 201311a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 201411a5261eSBarry Smith set by `MatCreateShell()`. 2015a62d957aSLois Curfman McInnes 201611a5261eSBarry Smith Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) use `MatShellSetMatProductOperation()` 2017b77ba244SStefano Zampini 201811a5261eSBarry Smith Fortran Note: 201911a5261eSBarry Smith For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not 2020c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2021501d9185SBarry Smith 202211a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 2023e51e0e81SBarry Smith @*/ 2024d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void)) 2025d71ae5a4SJacob Faibussowitsch { 20263a40ed3dSBarry Smith PetscFunctionBegin; 20270700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2028cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g)); 20293a40ed3dSBarry Smith PetscFunctionReturn(0); 2030e51e0e81SBarry Smith } 2031f0479e8cSBarry Smith 2032d4bb536fSBarry Smith /*@C 203311a5261eSBarry Smith MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix. 2034d4bb536fSBarry Smith 2035c7fcc2eaSBarry Smith Not Collective 2036c7fcc2eaSBarry Smith 2037d4bb536fSBarry Smith Input Parameters: 203811a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2039c7fcc2eaSBarry Smith - op - the name of the operation 2040d4bb536fSBarry Smith 2041d4bb536fSBarry Smith Output Parameter: 2042789d8953SBarry Smith . g - the function that provides the operation. 2043d4bb536fSBarry Smith 204415091d37SBarry Smith Level: advanced 204515091d37SBarry Smith 204611a5261eSBarry Smith Note: 2047e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2048d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2049d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 205011a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2051d4bb536fSBarry Smith 2052d4bb536fSBarry Smith All user-provided functions have the same calling 2053d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2054d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2055d4bb536fSBarry Smith routines, e.g., 2056d4bb536fSBarry Smith $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2057d4bb536fSBarry Smith 2058d4bb536fSBarry Smith Within each user-defined routine, the user should call 205911a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 206011a5261eSBarry Smith set by `MatCreateShell()`. 2061d4bb536fSBarry Smith 206211a5261eSBarry Smith .seealso: `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()` 2063d4bb536fSBarry Smith @*/ 2064d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void)) 2065d71ae5a4SJacob Faibussowitsch { 20663a40ed3dSBarry Smith PetscFunctionBegin; 20670700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2068cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g)); 20693a40ed3dSBarry Smith PetscFunctionReturn(0); 2070d4bb536fSBarry Smith } 2071b77ba244SStefano Zampini 2072b77ba244SStefano Zampini /*@ 207311a5261eSBarry Smith MatIsShell - Inquires if a matrix is derived from `MATSHELL` 2074b77ba244SStefano Zampini 2075b77ba244SStefano Zampini Input Parameter: 2076b77ba244SStefano Zampini . mat - the matrix 2077b77ba244SStefano Zampini 2078b77ba244SStefano Zampini Output Parameter: 2079b77ba244SStefano Zampini . flg - the boolean value 2080b77ba244SStefano Zampini 2081b77ba244SStefano Zampini Level: developer 2082b77ba244SStefano Zampini 208311a5261eSBarry Smith Developer Note: 2084013e2dc7SBarry Smith In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc) 2085b77ba244SStefano Zampini 2086013e2dc7SBarry Smith .seealso: `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` 2087b77ba244SStefano Zampini @*/ 2088d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2089d71ae5a4SJacob Faibussowitsch { 2090b77ba244SStefano Zampini PetscFunctionBegin; 2091b77ba244SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2092dadcf809SJacob Faibussowitsch PetscValidBoolPointer(flg, 2); 2093b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 2094b77ba244SStefano Zampini PetscFunctionReturn(0); 2095b77ba244SStefano Zampini } 2096