1e51e0e81SBarry Smith /* 220563c6bSBarry Smith This provides a simple shell for Fortran (and C programmers) to 320563c6bSBarry Smith create a very simple matrix class for use with KSP without coding 4ed3cc1f0SBarry Smith much of anything. 5e51e0e81SBarry Smith */ 6e51e0e81SBarry Smith 7af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 845960306SStefano Zampini #include <petsc/private/vecimpl.h> 9e51e0e81SBarry Smith 1028f357e3SAlex Fikl struct _MatShellOps { 11976e8c5aSLisandro Dalcin /* 3 */ PetscErrorCode (*mult)(Mat, Vec, Vec); 12976e8c5aSLisandro Dalcin /* 5 */ PetscErrorCode (*multtranspose)(Mat, Vec, Vec); 13976e8c5aSLisandro Dalcin /* 17 */ PetscErrorCode (*getdiagonal)(Mat, Vec); 14976e8c5aSLisandro Dalcin /* 43 */ PetscErrorCode (*copy)(Mat, Mat, MatStructure); 15976e8c5aSLisandro Dalcin /* 60 */ PetscErrorCode (*destroy)(Mat); 16*f8e07d23SBlanca Mellado Pinto /* 121 */ PetscErrorCode (*multhermitiantranspose)(Mat, Vec, Vec); 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 } 873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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 } 1003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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 } 1263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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 } 1403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14145960306SStefano Zampini } 14245960306SStefano Zampini 1438fe8eb27SJed Brown /* 1440c0fd78eSBarry Smith xx = diag(left)*x 1458fe8eb27SJed Brown */ 146*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPreScaleLeft(Mat A, Vec x, Vec *xx, PetscBool conjugate) 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)); 156*f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 157*f8e07d23SBlanca Mellado Pinto PetscInt i, m; 158*f8e07d23SBlanca Mellado Pinto const PetscScalar *d, *xarray; 159*f8e07d23SBlanca Mellado Pinto PetscScalar *w; 160*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 161*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->left, &d)); 162*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(x, &xarray)); 163*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayWrite(shell->left_work, &w)); 164*f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) w[i] = PetscConj(d[i]) * xarray[i]; 165*f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 166*f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(x, &xarray)); 167*f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayWrite(shell->left_work, &w)); 168*f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(shell->left_work, x, shell->left)); 1698fe8eb27SJed Brown *xx = shell->left_work; 1708fe8eb27SJed Brown } 1713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1728fe8eb27SJed Brown } 1738fe8eb27SJed Brown 1740c0fd78eSBarry Smith /* 1750c0fd78eSBarry Smith xx = diag(right)*x 1760c0fd78eSBarry Smith */ 177d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPreScaleRight(Mat A, Vec x, Vec *xx) 178d71ae5a4SJacob Faibussowitsch { 1798fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1808fe8eb27SJed Brown 1818fe8eb27SJed Brown PetscFunctionBegin; 1820298fd71SBarry Smith *xx = NULL; 1838fe8eb27SJed Brown if (!shell->right) { 1848fe8eb27SJed Brown *xx = x; 1858fe8eb27SJed Brown } else { 1869566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right, &shell->right_work)); 1879566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, x, shell->right)); 1888fe8eb27SJed Brown *xx = shell->right_work; 1898fe8eb27SJed Brown } 1903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1918fe8eb27SJed Brown } 1928fe8eb27SJed Brown 1930c0fd78eSBarry Smith /* 1940c0fd78eSBarry Smith x = diag(left)*x 1950c0fd78eSBarry Smith */ 196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellPostScaleLeft(Mat A, Vec x) 197d71ae5a4SJacob Faibussowitsch { 1988fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 1998fe8eb27SJed Brown 2008fe8eb27SJed Brown PetscFunctionBegin; 2019566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x, x, shell->left)); 2023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2038fe8eb27SJed Brown } 2048fe8eb27SJed Brown 2050c0fd78eSBarry Smith /* 2060c0fd78eSBarry Smith x = diag(right)*x 2070c0fd78eSBarry Smith */ 208*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellPostScaleRight(Mat A, Vec x, PetscBool conjugate) 209d71ae5a4SJacob Faibussowitsch { 2108fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 2118fe8eb27SJed Brown 2128fe8eb27SJed Brown PetscFunctionBegin; 213*f8e07d23SBlanca Mellado Pinto if (shell->right) { 214*f8e07d23SBlanca Mellado Pinto if (conjugate) { /* get arrays because there is no VecPointwiseMultConj() */ 215*f8e07d23SBlanca Mellado Pinto PetscInt i, m; 216*f8e07d23SBlanca Mellado Pinto const PetscScalar *d; 217*f8e07d23SBlanca Mellado Pinto PetscScalar *xarray; 218*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetLocalSize(x, &m)); 219*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArrayRead(shell->right, &d)); 220*f8e07d23SBlanca Mellado Pinto PetscCall(VecGetArray(x, &xarray)); 221*f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) xarray[i] = PetscConj(d[i]) * xarray[i]; 222*f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 223*f8e07d23SBlanca Mellado Pinto PetscCall(VecRestoreArray(x, &xarray)); 224*f8e07d23SBlanca Mellado Pinto } else PetscCall(VecPointwiseMult(x, x, shell->right)); 225*f8e07d23SBlanca Mellado Pinto } 2263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2278fe8eb27SJed Brown } 2288fe8eb27SJed Brown 2290c0fd78eSBarry Smith /* 2300c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 2310c0fd78eSBarry Smith 2320c0fd78eSBarry Smith On input Y already contains A*x 233*f8e07d23SBlanca Mellado Pinto 234*f8e07d23SBlanca Mellado Pinto If conjugate=PETSC_TRUE then vscale, dshift, and vshift are conjugated 2350c0fd78eSBarry Smith */ 236*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatShellShiftAndScale(Mat A, Vec X, Vec Y, PetscBool conjugate) 237d71ae5a4SJacob Faibussowitsch { 2388fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 239*f8e07d23SBlanca Mellado Pinto PetscScalar vscale = conjugate ? PetscConj(shell->vscale) : shell->vscale; 240*f8e07d23SBlanca Mellado Pinto PetscScalar vshift = conjugate ? PetscConj(shell->vshift) : shell->vshift; 2418fe8eb27SJed Brown 2428fe8eb27SJed Brown PetscFunctionBegin; 2438fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 2448fe8eb27SJed Brown PetscInt i, m; 2458fe8eb27SJed Brown const PetscScalar *x, *d; 2468fe8eb27SJed Brown PetscScalar *y; 2479566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &m)); 2489566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift, &d)); 2499566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 2509566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y, &y)); 251*f8e07d23SBlanca Mellado Pinto if (conjugate) 252*f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + PetscConj(d[i]) * x[i]; 253*f8e07d23SBlanca Mellado Pinto else 254*f8e07d23SBlanca Mellado Pinto for (i = 0; i < m; i++) y[i] = vscale * y[i] + d[i] * x[i]; 2559566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift, &d)); 2569566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 2579566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y, &y)); 2580c0fd78eSBarry Smith } else { 259*f8e07d23SBlanca Mellado Pinto PetscCall(VecScale(Y, vscale)); 2608fe8eb27SJed Brown } 261*f8e07d23SBlanca Mellado Pinto if (vshift != 0.0) PetscCall(VecAXPY(Y, vshift, X)); /* if test is for non-square matrices */ 2623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2638fe8eb27SJed Brown } 264e51e0e81SBarry Smith 265d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetContext_Shell(Mat mat, void *ctx) 266d71ae5a4SJacob Faibussowitsch { 267800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 268800f99ffSJeremy L Thompson 269789d8953SBarry Smith PetscFunctionBegin; 270800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerGetPointer(shell->ctxcontainer, (void **)ctx)); 271800f99ffSJeremy L Thompson else *(void **)ctx = NULL; 2723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 273789d8953SBarry Smith } 274789d8953SBarry Smith 2759d225801SJed Brown /*@ 27611a5261eSBarry Smith MatShellGetContext - Returns the user-provided context associated with a `MATSHELL` shell matrix. 277b4fd4287SBarry Smith 278c7fcc2eaSBarry Smith Not Collective 279c7fcc2eaSBarry Smith 280b4fd4287SBarry Smith Input Parameter: 28111a5261eSBarry Smith . mat - the matrix, should have been created with `MatCreateShell()` 282b4fd4287SBarry Smith 283b4fd4287SBarry Smith Output Parameter: 284b4fd4287SBarry Smith . ctx - the user provided context 285b4fd4287SBarry Smith 28615091d37SBarry Smith Level: advanced 28715091d37SBarry Smith 288fe59aa6dSJacob Faibussowitsch Fortran Notes: 28927430b45SBarry Smith You must write a Fortran interface definition for this 290daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 291a62d957aSLois Curfman McInnes 2921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetOperation()`, `MatShellSetContext()` 2930bc0a719SBarry Smith @*/ 294d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetContext(Mat mat, void *ctx) 295d71ae5a4SJacob Faibussowitsch { 2963a40ed3dSBarry Smith PetscFunctionBegin; 2970700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2984f572ea9SToby Isaac PetscAssertPointer(ctx, 2); 299cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetContext_C", (Mat, void *), (mat, ctx)); 3003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 301b4fd4287SBarry Smith } 302b4fd4287SBarry Smith 303d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat, PetscInt nr, PetscInt rows[], PetscInt nc, PetscInt cols[], PetscScalar diag, PetscBool rc) 304d71ae5a4SJacob Faibussowitsch { 30545960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 30645960306SStefano Zampini Vec x = NULL, b = NULL; 30745960306SStefano Zampini IS is1, is2; 30845960306SStefano Zampini const PetscInt *ridxs; 30945960306SStefano Zampini PetscInt *idxs, *gidxs; 31045960306SStefano Zampini PetscInt cum, rst, cst, i; 31145960306SStefano Zampini 31245960306SStefano Zampini PetscFunctionBegin; 31348a46eb9SPierre Jolivet if (!shell->zvals) PetscCall(MatCreateVecs(mat, NULL, &shell->zvals)); 31448a46eb9SPierre Jolivet if (!shell->zvals_w) PetscCall(VecDuplicate(shell->zvals, &shell->zvals_w)); 3159566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat, &rst, NULL)); 3169566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat, &cst, NULL)); 31745960306SStefano Zampini 31845960306SStefano Zampini /* Expand/create index set of zeroed rows */ 3199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &idxs)); 32045960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 3219566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nr, idxs, PETSC_OWN_POINTER, &is1)); 3229566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 3239566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals, is1, diag)); 32445960306SStefano Zampini if (shell->zrows) { 3259566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows, is1, &is2)); 3269566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 3279566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 32845960306SStefano Zampini shell->zrows = is2; 32945960306SStefano Zampini } else shell->zrows = is1; 33045960306SStefano Zampini 33145960306SStefano Zampini /* Create scatters for diagonal values communications */ 3329566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 3339566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 33445960306SStefano Zampini 33545960306SStefano Zampini /* row scatter: from/to left vector */ 3369566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &b)); 3379566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b, shell->zrows, shell->zvals_w, shell->zrows, &shell->zvals_sct_r)); 33845960306SStefano Zampini 33945960306SStefano Zampini /* col scatter: from right vector to left vector */ 3409566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows, &ridxs)); 3419566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows, &nr)); 3429566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &gidxs)); 34345960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 34445960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 34545960306SStefano Zampini gidxs[cum] = ridxs[i]; 34645960306SStefano Zampini cum++; 34745960306SStefano Zampini } 3489566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), cum, gidxs, PETSC_OWN_POINTER, &is1)); 3499566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x, is1, shell->zvals_w, is1, &shell->zvals_sct_c)); 3509566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 3519566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 3529566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 35345960306SStefano Zampini 35445960306SStefano Zampini /* Expand/create index set of zeroed columns */ 35545960306SStefano Zampini if (rc) { 3569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &idxs)); 35745960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 3589566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nc, idxs, PETSC_OWN_POINTER, &is1)); 3599566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 36045960306SStefano Zampini if (shell->zcols) { 3619566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols, is1, &is2)); 3629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3639566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 36445960306SStefano Zampini shell->zcols = is2; 36545960306SStefano Zampini } else shell->zcols = is1; 36645960306SStefano Zampini } 3673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 36845960306SStefano Zampini } 36945960306SStefano Zampini 370d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_Shell(Mat mat, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 371d71ae5a4SJacob Faibussowitsch { 372ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 37345960306SStefano Zampini PetscInt nr, *lrows; 37445960306SStefano Zampini 37545960306SStefano Zampini PetscFunctionBegin; 37645960306SStefano Zampini if (x && b) { 37745960306SStefano Zampini Vec xt; 37845960306SStefano Zampini PetscScalar *vals; 37945960306SStefano Zampini PetscInt *gcols, i, st, nl, nc; 38045960306SStefano Zampini 3819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &gcols)); 3829371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 3839371c9d4SSatish Balay if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 38445960306SStefano Zampini 3859566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, NULL)); 3869566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 3879566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc, &vals)); 3889566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 3899566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3909566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3919566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3929566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt, -1.0, x)); /* xt = [0, x2] */ 39345960306SStefano Zampini 3949566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 3959566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 3969566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 39745960306SStefano Zampini for (i = 0; i < nl; i++) { 39845960306SStefano Zampini PetscInt g = i + st; 39945960306SStefano Zampini if (g > mat->rmap->N) continue; 40045960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4019566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, diag * vals[i], INSERT_VALUES)); 40245960306SStefano Zampini } 4039566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4049566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4059566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 4069566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4079566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 40845960306SStefano Zampini } 4099566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rows, &nr, &lrows, NULL)); 4109566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, 0, NULL, diag, PETSC_FALSE)); 4111baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRows(shell->axpy, n, rows, 0.0, NULL, NULL)); 4129566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 41445960306SStefano Zampini } 41545960306SStefano Zampini 416d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat, PetscInt n, const PetscInt rowscols[], PetscScalar diag, Vec x, Vec b) 417d71ae5a4SJacob Faibussowitsch { 418ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell *)mat->data; 41945960306SStefano Zampini PetscInt *lrows, *lcols; 42045960306SStefano Zampini PetscInt nr, nc; 42145960306SStefano Zampini PetscBool congruent; 42245960306SStefano Zampini 42345960306SStefano Zampini PetscFunctionBegin; 42445960306SStefano Zampini if (x && b) { 42545960306SStefano Zampini Vec xt, bt; 42645960306SStefano Zampini PetscScalar *vals; 42745960306SStefano Zampini PetscInt *grows, *gcols, i, st, nl; 42845960306SStefano Zampini 4299566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &grows, n, &gcols)); 4309371c9d4SSatish Balay for (i = 0, nr = 0; i < n; i++) 4319371c9d4SSatish Balay if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 4329371c9d4SSatish Balay for (i = 0, nc = 0; i < n; i++) 4339371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 4349566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n, &vals)); 43545960306SStefano Zampini 4369566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &xt, &bt)); 4379566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xt)); 4389566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt, nc, gcols, vals, INSERT_VALUES)); /* xt = [x1, 0] */ 4399566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 4409566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 4419566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt, -1.0, x)); /* xt = [0, -x2] */ 4429566063dSJacob Faibussowitsch PetscCall(MatMult(mat, xt, bt)); /* bt = [-A12*x2,-A22*x2] */ 4439566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* bt = [-A12*x2,0] */ 4449566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4459566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4469566063dSJacob Faibussowitsch PetscCall(VecAXPY(b, 1.0, bt)); /* b = [b1 - A12*x2, b2] */ 4479566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt, nr, grows, vals, INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 4489566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4499566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4509566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 45145960306SStefano Zampini 4529566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt, &st, NULL)); 4539566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt, &nl)); 4549566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt, &vals)); 45545960306SStefano Zampini for (i = 0; i < nl; i++) { 45645960306SStefano Zampini PetscInt g = i + st; 45745960306SStefano Zampini if (g > mat->rmap->N) continue; 45845960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4599566063dSJacob Faibussowitsch PetscCall(VecSetValue(b, g, -diag * vals[i], INSERT_VALUES)); 46045960306SStefano Zampini } 4619566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt, &vals)); 4629566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4639566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4649566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4659566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4669566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows, gcols)); 46745960306SStefano Zampini } 4689566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap, n, rowscols, &nr, &lrows, NULL)); 4699566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat, &congruent)); 47045960306SStefano Zampini if (congruent) { 47145960306SStefano Zampini nc = nr; 47245960306SStefano Zampini lcols = lrows; 47345960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 47445960306SStefano Zampini PetscInt i, nt, *t; 47545960306SStefano Zampini 4769566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &t)); 4779371c9d4SSatish Balay for (i = 0, nt = 0; i < n; i++) 4789371c9d4SSatish Balay if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4799566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap, nt, t, &nc, &lcols, NULL)); 4809566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 48145960306SStefano Zampini } 4829566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat, nr, lrows, nc, lcols, diag, PETSC_TRUE)); 48348a46eb9SPierre Jolivet if (!congruent) PetscCall(PetscFree(lcols)); 4849566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 4851baa6e33SBarry Smith if (shell->axpy) PetscCall(MatZeroRowsColumns(shell->axpy, n, rowscols, 0.0, NULL, NULL)); 4863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 48745960306SStefano Zampini } 48845960306SStefano Zampini 489d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Shell(Mat mat) 490d71ae5a4SJacob Faibussowitsch { 491bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell *)mat->data; 492b77ba244SStefano Zampini MatShellMatFunctionList matmat; 493ed3cc1f0SBarry Smith 4943a40ed3dSBarry Smith PetscFunctionBegin; 4951baa6e33SBarry Smith if (shell->ops->destroy) PetscCall((*shell->ops->destroy)(mat)); 4969566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops, sizeof(struct _MatShellOps))); 4979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 5009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 5019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 5029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 5039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 5049566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 5059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 5069566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 5079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 5089566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 5099566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 5109566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 5119566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 5129566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 513b77ba244SStefano Zampini 514b77ba244SStefano Zampini matmat = shell->matmat; 515b77ba244SStefano Zampini while (matmat) { 516b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 517b77ba244SStefano Zampini 5189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, matmat->composedname, NULL)); 5199566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 5209566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 5219566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 522b77ba244SStefano Zampini matmat = next; 523b77ba244SStefano Zampini } 524800f99ffSJeremy L Thompson PetscCall(MatShellSetContext(mat, NULL)); 5259566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetContext_C", NULL)); 5269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 527800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContextDestroy_C", NULL)); 5289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetVecType_C", NULL)); 5299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetManageScalingShifts_C", NULL)); 5309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetOperation_C", NULL)); 5319566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellGetOperation_C", NULL)); 5329566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetMatProductOperation_C", NULL)); 5339566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 5343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 535b77ba244SStefano Zampini } 536b77ba244SStefano Zampini 537b77ba244SStefano Zampini typedef struct { 538b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat, Mat, Mat, void *); 539b77ba244SStefano Zampini PetscErrorCode (*destroy)(void *); 540b77ba244SStefano Zampini void *userdata; 541b77ba244SStefano Zampini Mat B; 542b77ba244SStefano Zampini Mat Bt; 543b77ba244SStefano Zampini Mat axpy; 544b77ba244SStefano Zampini } MatMatDataShell; 545b77ba244SStefano Zampini 546d71ae5a4SJacob Faibussowitsch static PetscErrorCode DestroyMatMatDataShell(void *data) 547d71ae5a4SJacob Faibussowitsch { 548b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 549b77ba244SStefano Zampini 550b77ba244SStefano Zampini PetscFunctionBegin; 5511baa6e33SBarry Smith if (mmdata->destroy) PetscCall((*mmdata->destroy)(mmdata->userdata)); 5529566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 5539566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 5549566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 5559566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 5563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 557b77ba244SStefano Zampini } 558b77ba244SStefano Zampini 559d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 560d71ae5a4SJacob Faibussowitsch { 561b77ba244SStefano Zampini Mat_Product *product; 562b77ba244SStefano Zampini Mat A, B; 563b77ba244SStefano Zampini MatMatDataShell *mdata; 564b77ba244SStefano Zampini PetscScalar zero = 0.0; 565b77ba244SStefano Zampini 566b77ba244SStefano Zampini PetscFunctionBegin; 567b77ba244SStefano Zampini MatCheckProduct(D, 1); 568b77ba244SStefano Zampini product = D->product; 56928b400f6SJacob Faibussowitsch PetscCheck(product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty"); 570b77ba244SStefano Zampini A = product->A; 571b77ba244SStefano Zampini B = product->B; 572b77ba244SStefano Zampini mdata = (MatMatDataShell *)product->data; 573b77ba244SStefano Zampini if (mdata->numeric) { 574b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 575b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 576b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 577b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 578b77ba244SStefano Zampini 579b77ba244SStefano Zampini if (shell->managescalingshifts) { 58008401ef6SPierre Jolivet PetscCheck(!shell->zcols && !shell->zrows, PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "MatProduct not supported with zeroed rows/columns"); 581b77ba244SStefano Zampini if (shell->right || shell->left) { 582b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 583b77ba244SStefano Zampini if (!mdata->B) { 5849566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B, MAT_SHARE_NONZERO_PATTERN, &mdata->B)); 585b77ba244SStefano Zampini } else { 586b77ba244SStefano Zampini newB = PETSC_FALSE; 587b77ba244SStefano Zampini } 5889566063dSJacob Faibussowitsch PetscCall(MatCopy(B, mdata->B, SAME_NONZERO_PATTERN)); 589b77ba244SStefano Zampini } 590b77ba244SStefano Zampini switch (product->type) { 591b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 5921baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 593b77ba244SStefano Zampini break; 594b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 5951baa6e33SBarry Smith if (shell->left) PetscCall(MatDiagonalScale(mdata->B, shell->left, NULL)); 596b77ba244SStefano Zampini break; 597b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 5981baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 599b77ba244SStefano Zampini break; 600b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 601b77ba244SStefano Zampini if (shell->right && shell->left) { 602b77ba244SStefano Zampini PetscBool flg; 603b77ba244SStefano Zampini 6049566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 6059371c9d4SSatish 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, 6069371c9d4SSatish Balay ((PetscObject)B)->type_name); 607b77ba244SStefano Zampini } 6081baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, NULL, shell->right)); 609b77ba244SStefano Zampini break; 610b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 611b77ba244SStefano Zampini if (shell->right && shell->left) { 612b77ba244SStefano Zampini PetscBool flg; 613b77ba244SStefano Zampini 6149566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right, shell->left, &flg)); 6159371c9d4SSatish 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, 6169371c9d4SSatish Balay ((PetscObject)B)->type_name); 617b77ba244SStefano Zampini } 6181baa6e33SBarry Smith if (shell->right) PetscCall(MatDiagonalScale(mdata->B, shell->right, NULL)); 619b77ba244SStefano Zampini break; 620d71ae5a4SJacob Faibussowitsch default: 621d71ae5a4SJacob 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); 622b77ba244SStefano Zampini } 623b77ba244SStefano Zampini } 624b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 625b77ba244SStefano Zampini D->product = NULL; 626b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 627b77ba244SStefano Zampini D->ops->productnumeric = NULL; 628b77ba244SStefano Zampini 6299566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A, useBmdata ? mdata->B : B, D, mdata->userdata)); 630b77ba244SStefano Zampini 631b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 6329566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 633b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 634b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 635b77ba244SStefano Zampini D->product = product; 636b77ba244SStefano Zampini 637b77ba244SStefano Zampini if (shell->managescalingshifts) { 6389566063dSJacob Faibussowitsch PetscCall(MatScale(D, shell->vscale)); 639b77ba244SStefano Zampini switch (product->type) { 640b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 641b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 642b77ba244SStefano Zampini if (shell->left) { 6439566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->left, NULL)); 644b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 6459566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A, NULL, &shell->left_work)); 646b77ba244SStefano Zampini if (shell->dshift) { 6479566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->left_work)); 6489566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work, shell->vshift)); 6499566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work, shell->left_work, shell->left)); 650b77ba244SStefano Zampini } else { 6519566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work, shell->vshift)); 652b77ba244SStefano Zampini } 653b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 654b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 655b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 656b77ba244SStefano Zampini 6579566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B, reuse, &mdata->Bt)); 6589566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt, shell->left_work, NULL)); 6599566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->Bt, str)); 660b77ba244SStefano Zampini } else { 661b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 662b77ba244SStefano Zampini 6639566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->left_work, NULL)); 6649566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 665b77ba244SStefano Zampini } 666b77ba244SStefano Zampini } 667b77ba244SStefano Zampini } 668b77ba244SStefano Zampini break; 669b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 670b77ba244SStefano Zampini if (shell->right) { 6719566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D, shell->right, NULL)); 672b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 673b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 674b77ba244SStefano Zampini 6759566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A, &shell->right_work, NULL)); 676b77ba244SStefano Zampini if (shell->dshift) { 6779566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift, shell->right_work)); 6789566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work, shell->vshift)); 6799566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work, shell->right_work, shell->right)); 680b77ba244SStefano Zampini } else { 6819566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work, shell->vshift)); 682b77ba244SStefano Zampini } 6839566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B, shell->right_work, NULL)); 6849566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, 1.0, mdata->B, str)); 685b77ba244SStefano Zampini } 686b77ba244SStefano Zampini } 687b77ba244SStefano Zampini break; 688b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 689b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6909371c9d4SSatish 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, 6919371c9d4SSatish Balay ((PetscObject)B)->type_name); 692b77ba244SStefano Zampini break; 693d71ae5a4SJacob Faibussowitsch default: 694d71ae5a4SJacob 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); 695b77ba244SStefano Zampini } 696b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 697b77ba244SStefano Zampini Mat X; 698b77ba244SStefano Zampini PetscObjectState axpy_state; 699b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 700b77ba244SStefano Zampini 7019566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 7029566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 70308401ef6SPierre 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,...)"); 704b77ba244SStefano Zampini if (!mdata->axpy) { 705b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 7069566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy, B, NULL, &mdata->axpy)); 7079566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy, product->type)); 7089566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 7099566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 710b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 711b77ba244SStefano Zampini PetscBool flg; 712b77ba244SStefano Zampini 7139566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy, B, NULL, mdata->axpy)); 7149566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy, MATOP_PRODUCTSYMBOLIC, &flg)); 715b77ba244SStefano Zampini if (!flg) { 716b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 7179566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 7189566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 719b77ba244SStefano Zampini } 720b77ba244SStefano Zampini } 7219566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 7229566063dSJacob Faibussowitsch PetscCall(MatAXPY(D, shell->axpy_vscale, mdata->axpy, str)); 723b77ba244SStefano Zampini } 724b77ba244SStefano Zampini } 725b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Missing numeric operation"); 7263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 727b77ba244SStefano Zampini } 728b77ba244SStefano Zampini 729d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 730d71ae5a4SJacob Faibussowitsch { 731b77ba244SStefano Zampini Mat_Product *product; 732b77ba244SStefano Zampini Mat A, B; 733b77ba244SStefano Zampini MatShellMatFunctionList matmat; 734b77ba244SStefano Zampini Mat_Shell *shell; 735eae3dc7dSJacob Faibussowitsch PetscBool flg = PETSC_FALSE; 736b77ba244SStefano Zampini char composedname[256]; 737b77ba244SStefano Zampini MatMatDataShell *mdata; 738b77ba244SStefano Zampini 739b77ba244SStefano Zampini PetscFunctionBegin; 740b77ba244SStefano Zampini MatCheckProduct(D, 1); 741b77ba244SStefano Zampini product = D->product; 74228b400f6SJacob Faibussowitsch PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty"); 743b77ba244SStefano Zampini A = product->A; 744b77ba244SStefano Zampini B = product->B; 745b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 746b77ba244SStefano Zampini matmat = shell->matmat; 7479566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 748b77ba244SStefano Zampini while (matmat) { 7499566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 750b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 751b77ba244SStefano Zampini if (flg) break; 752b77ba244SStefano Zampini matmat = matmat->next; 753b77ba244SStefano Zampini } 75428b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Composedname \"%s\" for product type %s not found", composedname, MatProductTypes[product->type]); 755b77ba244SStefano Zampini switch (product->type) { 756d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AB: 757d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); 758d71ae5a4SJacob Faibussowitsch break; 759d71ae5a4SJacob Faibussowitsch case MATPRODUCT_AtB: 760d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); 761d71ae5a4SJacob Faibussowitsch break; 762d71ae5a4SJacob Faibussowitsch case MATPRODUCT_ABt: 763d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N)); 764d71ae5a4SJacob Faibussowitsch break; 765d71ae5a4SJacob Faibussowitsch case MATPRODUCT_RARt: 766d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->rmap->n, B->rmap->n, B->rmap->N, B->rmap->N)); 767d71ae5a4SJacob Faibussowitsch break; 768d71ae5a4SJacob Faibussowitsch case MATPRODUCT_PtAP: 769d71ae5a4SJacob Faibussowitsch PetscCall(MatSetSizes(D, B->cmap->n, B->cmap->n, B->cmap->N, B->cmap->N)); 770d71ae5a4SJacob Faibussowitsch break; 771d71ae5a4SJacob Faibussowitsch default: 772d71ae5a4SJacob 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); 773b77ba244SStefano Zampini } 774b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 775b77ba244SStefano Zampini if (matmat->resultname) { 7769566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D, matmat->resultname, &flg)); 77748a46eb9SPierre Jolivet if (!flg) PetscCall(MatSetType(D, matmat->resultname)); 778b77ba244SStefano Zampini } 779b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 780b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 781b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 782b77ba244SStefano Zampini /* attach product data */ 7839566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 784b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 785b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 786b77ba244SStefano Zampini if (matmat->symbolic) { 7879566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A, B, D, &mdata->userdata)); 788b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7899566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 790b77ba244SStefano Zampini } 79128b400f6SJacob Faibussowitsch PetscCheck(D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product disappeared after user symbolic phase"); 79228b400f6SJacob Faibussowitsch PetscCheck(!D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_COR, "Product data not empty after user symbolic phase"); 793b77ba244SStefano Zampini D->product->data = mdata; 794b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 795b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 796b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 797b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 7983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 799b77ba244SStefano Zampini } 800b77ba244SStefano Zampini 801d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 802d71ae5a4SJacob Faibussowitsch { 803b77ba244SStefano Zampini Mat_Product *product; 804b77ba244SStefano Zampini Mat A, B; 805b77ba244SStefano Zampini MatShellMatFunctionList matmat; 806b77ba244SStefano Zampini Mat_Shell *shell; 807b77ba244SStefano Zampini PetscBool flg; 808b77ba244SStefano Zampini char composedname[256]; 809b77ba244SStefano Zampini 810b77ba244SStefano Zampini PetscFunctionBegin; 811b77ba244SStefano Zampini MatCheckProduct(D, 1); 812b77ba244SStefano Zampini product = D->product; 813b77ba244SStefano Zampini A = product->A; 814b77ba244SStefano Zampini B = product->B; 8159566063dSJacob Faibussowitsch PetscCall(MatIsShell(A, &flg)); 8163ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 817b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 818b77ba244SStefano Zampini matmat = shell->matmat; 8199566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, ((PetscObject)B)->type_name)); 820b77ba244SStefano Zampini while (matmat) { 8219566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, matmat->composedname, &flg)); 822b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 823b77ba244SStefano Zampini if (flg) break; 824b77ba244SStefano Zampini matmat = matmat->next; 825b77ba244SStefano Zampini } 8269371c9d4SSatish Balay if (flg) { 8279371c9d4SSatish Balay D->ops->productsymbolic = MatProductSymbolic_Shell_X; 8289371c9d4SSatish Balay } else PetscCall(PetscInfo(D, " symbolic product %s not registered for product type %s\n", composedname, MatProductTypes[product->type])); 8293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 830b77ba244SStefano Zampini } 831b77ba244SStefano Zampini 832d71ae5a4SJacob 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) 833d71ae5a4SJacob Faibussowitsch { 834b77ba244SStefano Zampini PetscBool flg; 835b77ba244SStefano Zampini Mat_Shell *shell; 836b77ba244SStefano Zampini MatShellMatFunctionList matmat; 837b77ba244SStefano Zampini 838b77ba244SStefano Zampini PetscFunctionBegin; 83928b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing numeric routine"); 84028b400f6SJacob Faibussowitsch PetscCheck(composedname, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing composed name"); 841b77ba244SStefano Zampini 842b77ba244SStefano Zampini /* add product callback */ 843b77ba244SStefano Zampini shell = (Mat_Shell *)A->data; 844b77ba244SStefano Zampini matmat = shell->matmat; 845b77ba244SStefano Zampini if (!matmat) { 8469566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 847b77ba244SStefano Zampini matmat = shell->matmat; 848b77ba244SStefano Zampini } else { 849b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 850b77ba244SStefano Zampini while (entry) { 8519566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname, entry->composedname, &flg)); 852b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 853b77ba244SStefano Zampini matmat = entry; 8542e956fe4SStefano Zampini if (flg) goto set; 855b77ba244SStefano Zampini entry = entry->next; 856b77ba244SStefano Zampini } 8579566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 858b77ba244SStefano Zampini matmat = matmat->next; 859b77ba244SStefano Zampini } 860b77ba244SStefano Zampini 861843d480fSStefano Zampini set: 862b77ba244SStefano Zampini matmat->symbolic = symbolic; 863b77ba244SStefano Zampini matmat->numeric = numeric; 864b77ba244SStefano Zampini matmat->destroy = destroy; 865b77ba244SStefano Zampini matmat->ptype = ptype; 8669566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8679566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8689566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname, &matmat->composedname)); 8699566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname, &matmat->resultname)); 8709566063dSJacob 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")); 8719566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, matmat->composedname, MatProductSetFromOptions_Shell_X)); 8723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 873b77ba244SStefano Zampini } 874b77ba244SStefano Zampini 875b77ba244SStefano Zampini /*@C 87611a5261eSBarry Smith MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a `MATSHELL` shell matrix. 877b77ba244SStefano Zampini 87827430b45SBarry Smith Logically Collective; No Fortran Support 879b77ba244SStefano Zampini 880b77ba244SStefano Zampini Input Parameters: 88111a5261eSBarry Smith + A - the `MATSHELL` shell matrix 882b77ba244SStefano Zampini . ptype - the product type 8832ef1f0ffSBarry Smith . symbolic - the function for the symbolic phase (can be `NULL`) 884b77ba244SStefano Zampini . numeric - the function for the numerical phase 8852ef1f0ffSBarry Smith . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be `NULL`) 886b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 8872ef1f0ffSBarry Smith - Ctype - the matrix type for the result (can be `NULL`) 888b77ba244SStefano Zampini 889b77ba244SStefano Zampini Level: advanced 890b77ba244SStefano Zampini 8912920cce0SJacob Faibussowitsch Example Usage: 892cf53795eSBarry Smith .vb 893cf53795eSBarry Smith extern PetscErrorCode usersymbolic(Mat, Mat, Mat, void**); 894cf53795eSBarry Smith extern PetscErrorCode usernumeric(Mat, Mat, Mat, void*); 895cf53795eSBarry Smith extern PetscErrorCode userdestroy(void*); 8962920cce0SJacob Faibussowitsch 897cf53795eSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 8982920cce0SJacob Faibussowitsch MatShellSetMatProductOperation( 8992920cce0SJacob Faibussowitsch A, MATPRODUCT_AB, usersymbolic, usernumeric, userdestroy,MATSEQAIJ, MATDENSE 9002920cce0SJacob Faibussowitsch ); 9012920cce0SJacob Faibussowitsch // create B of type SEQAIJ etc.. 9022920cce0SJacob Faibussowitsch MatProductCreate(A, B, PETSC_NULLPTR, &C); 903cf53795eSBarry Smith MatProductSetType(C, MATPRODUCT_AB); 904cf53795eSBarry Smith MatProductSetFromOptions(C); 9052920cce0SJacob Faibussowitsch MatProductSymbolic(C); // actually runs the user defined symbolic operation 9062920cce0SJacob Faibussowitsch MatProductNumeric(C); // actually runs the user defined numeric operation 9072920cce0SJacob Faibussowitsch // use C = A * B 908cf53795eSBarry Smith .ve 909b77ba244SStefano Zampini 910b77ba244SStefano Zampini Notes: 911cf53795eSBarry Smith `MATPRODUCT_ABC` is not supported yet. 91211a5261eSBarry Smith 9132ef1f0ffSBarry 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`. 91411a5261eSBarry Smith 915b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 916b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 917b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 91827430b45SBarry Smith The couple (Btype,ptype) uniquely identifies the operation, the last specified callbacks takes precedence. 919b77ba244SStefano Zampini 9201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatProductType`, `MatType`, `MatSetUp()` 921b77ba244SStefano Zampini @*/ 922d71ae5a4SJacob 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) 923d71ae5a4SJacob Faibussowitsch { 924b77ba244SStefano Zampini PetscFunctionBegin; 925b77ba244SStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 926b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A, ptype, 2); 92708401ef6SPierre Jolivet PetscCheck(ptype != MATPRODUCT_ABC, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for product type %s", MatProductTypes[ptype]); 92828b400f6SJacob Faibussowitsch PetscCheck(numeric, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Missing numeric routine, argument 4"); 9294f572ea9SToby Isaac PetscAssertPointer(Btype, 6); 9304f572ea9SToby Isaac if (Ctype) PetscAssertPointer(Ctype, 7); 931cac4c232SBarry 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)); 9323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 933b77ba244SStefano Zampini } 934b77ba244SStefano Zampini 935d71ae5a4SJacob 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) 936d71ae5a4SJacob Faibussowitsch { 937b77ba244SStefano Zampini PetscBool flg; 938b77ba244SStefano Zampini char composedname[256]; 939b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 940b77ba244SStefano Zampini PetscMPIInt size; 941b77ba244SStefano Zampini 942b77ba244SStefano Zampini PetscFunctionBegin; 943b77ba244SStefano Zampini PetscValidType(A, 1); 944b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 9459566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype, Bnames->rname, &flg)); 946b77ba244SStefano Zampini if (flg) break; 947b77ba244SStefano Zampini Bnames = Bnames->next; 948b77ba244SStefano Zampini } 949b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 9509566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype, Cnames->rname, &flg)); 951b77ba244SStefano Zampini if (flg) break; 952b77ba244SStefano Zampini Cnames = Cnames->next; 953b77ba244SStefano Zampini } 9549566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 955b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 956b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9579566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname, sizeof(composedname), "MatProductSetFromOptions_%s_%s_C", ((PetscObject)A)->type_name, Btype)); 9589566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A, ptype, symbolic, numeric, destroy, composedname, Ctype)); 9593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 960e51e0e81SBarry Smith } 961e51e0e81SBarry Smith 962d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Shell(Mat A, Mat B, MatStructure str) 963d71ae5a4SJacob Faibussowitsch { 96428f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell *)A->data, *shellB = (Mat_Shell *)B->data; 965cb8c8a77SBarry Smith PetscBool matflg; 966b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9677fabda3fSAlex Fikl 9687fabda3fSAlex Fikl PetscFunctionBegin; 9699566063dSJacob Faibussowitsch PetscCall(MatIsShell(B, &matflg)); 97028b400f6SJacob Faibussowitsch PetscCheck(matflg, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Matrix %s not derived from MATSHELL", ((PetscObject)B)->type_name); 9717fabda3fSAlex Fikl 972aea10558SJacob Faibussowitsch B->ops[0] = A->ops[0]; 973aea10558SJacob Faibussowitsch shellB->ops[0] = shellA->ops[0]; 9747fabda3fSAlex Fikl 9751baa6e33SBarry Smith if (shellA->ops->copy) PetscCall((*shellA->ops->copy)(A, B, str)); 9767fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9777fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9780c0fd78eSBarry Smith if (shellA->dshift) { 97948a46eb9SPierre Jolivet if (!shellB->dshift) PetscCall(VecDuplicate(shellA->dshift, &shellB->dshift)); 9809566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift, shellB->dshift)); 9817fabda3fSAlex Fikl } else { 9829566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9837fabda3fSAlex Fikl } 9840c0fd78eSBarry Smith if (shellA->left) { 98548a46eb9SPierre Jolivet if (!shellB->left) PetscCall(VecDuplicate(shellA->left, &shellB->left)); 9869566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left, shellB->left)); 9877fabda3fSAlex Fikl } else { 9889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9897fabda3fSAlex Fikl } 9900c0fd78eSBarry Smith if (shellA->right) { 99148a46eb9SPierre Jolivet if (!shellB->right) PetscCall(VecDuplicate(shellA->right, &shellB->right)); 9929566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right, shellB->right)); 9937fabda3fSAlex Fikl } else { 9949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9957fabda3fSAlex Fikl } 9969566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 997ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 998ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 99940e381c3SBarry Smith if (shellA->axpy) { 10009566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 100140e381c3SBarry Smith shellB->axpy = shellA->axpy; 100240e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 1003ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 100440e381c3SBarry Smith } 100545960306SStefano Zampini if (shellA->zrows) { 10069566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows, &shellB->zrows)); 100748a46eb9SPierre Jolivet if (shellA->zcols) PetscCall(ISDuplicate(shellA->zcols, &shellB->zcols)); 10089566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals, &shellB->zvals)); 10099566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals, shellB->zvals)); 10109566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w, &shellB->zvals_w)); 10119566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 10129566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 101345960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 101445960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 101545960306SStefano Zampini } 1016b77ba244SStefano Zampini 1017b77ba244SStefano Zampini matmatA = shellA->matmat; 1018b77ba244SStefano Zampini if (matmatA) { 1019b77ba244SStefano Zampini while (matmatA->next) { 10209566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B, matmatA->ptype, matmatA->symbolic, matmatA->numeric, matmatA->destroy, matmatA->composedname, matmatA->resultname)); 1021b77ba244SStefano Zampini matmatA = matmatA->next; 1022b77ba244SStefano Zampini } 1023b77ba244SStefano Zampini } 10243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10257fabda3fSAlex Fikl } 10267fabda3fSAlex Fikl 1027d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Shell(Mat mat, MatDuplicateOption op, Mat *M) 1028d71ae5a4SJacob Faibussowitsch { 1029cb8c8a77SBarry Smith PetscFunctionBegin; 1030800f99ffSJeremy L Thompson PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat), mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N, NULL, M)); 1031800f99ffSJeremy L Thompson ((Mat_Shell *)(*M)->data)->ctxcontainer = ((Mat_Shell *)mat->data)->ctxcontainer; 1032800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)(*M), "MatShell ctx", (PetscObject)((Mat_Shell *)(*M)->data)->ctxcontainer)); 10339566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)(*M), ((PetscObject)mat)->type_name)); 103448a46eb9SPierre Jolivet if (op != MAT_DO_NOT_COPY_VALUES) PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN)); 103501f93aa2SJose E. Roman PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)mat, (PetscObject)*M)); 10363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1037cb8c8a77SBarry Smith } 1038cb8c8a77SBarry Smith 103966976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Shell(Mat A, Vec x, Vec y) 1040d71ae5a4SJacob Faibussowitsch { 1041ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 104225578ef6SJed Brown Vec xx; 1043e3f487b0SBarry Smith PetscObjectState instate, outstate; 1044ef66eb69SBarry Smith 1045ef66eb69SBarry Smith PetscFunctionBegin; 10469566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A, x, &xx)); 10479566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A, xx, &xx)); 10489566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10499566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A, xx, y)); 10509566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1051e3f487b0SBarry Smith if (instate == outstate) { 1052e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10539566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1054e3f487b0SBarry Smith } 1055*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 10569566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A, y)); 10579566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A, y)); 10589f137db4SBarry Smith 10599f137db4SBarry Smith if (shell->axpy) { 1060ef5c7bd2SStefano Zampini Mat X; 1061ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1062ef5c7bd2SStefano Zampini 10639566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 10649566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 106508401ef6SPierre 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,...)"); 1066b77ba244SStefano Zampini 10679566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 10689566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_right)); 10699566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy, shell->axpy_right, shell->axpy_left)); 10709566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_left)); 10719f137db4SBarry Smith } 10723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1073ef66eb69SBarry Smith } 1074ef66eb69SBarry Smith 1075d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1076d71ae5a4SJacob Faibussowitsch { 10775edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 10785edf6516SJed Brown 10795edf6516SJed Brown PetscFunctionBegin; 10805edf6516SJed Brown if (y == z) { 10819566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z, &shell->right_add_work)); 10829566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, shell->right_add_work)); 10839566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->right_add_work)); 10845edf6516SJed Brown } else { 10859566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, z)); 10869566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 10875edf6516SJed Brown } 10883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10895edf6516SJed Brown } 10905edf6516SJed Brown 1091d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Shell(Mat A, Vec x, Vec y) 1092d71ae5a4SJacob Faibussowitsch { 109318be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 109425578ef6SJed Brown Vec xx; 1095e3f487b0SBarry Smith PetscObjectState instate, outstate; 109618be62a5SSatish Balay 109718be62a5SSatish Balay PetscFunctionBegin; 10989566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1099*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_FALSE)); 11009566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 11019566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A, xx, y)); 11029566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1103e3f487b0SBarry Smith if (instate == outstate) { 1104e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 11059566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1106e3f487b0SBarry Smith } 1107*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_FALSE)); 1108*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_FALSE)); 11099566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A, y)); 1110350ec83bSStefano Zampini 1111350ec83bSStefano Zampini if (shell->axpy) { 1112ef5c7bd2SStefano Zampini Mat X; 1113ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1114ef5c7bd2SStefano Zampini 11159566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 11169566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 111708401ef6SPierre 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,...)"); 11189566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 11199566063dSJacob Faibussowitsch PetscCall(VecCopy(x, shell->axpy_left)); 11209566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 11219566063dSJacob Faibussowitsch PetscCall(VecAXPY(y, shell->axpy_vscale, shell->axpy_right)); 1122350ec83bSStefano Zampini } 11233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 112418be62a5SSatish Balay } 112518be62a5SSatish Balay 1126*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Shell(Mat A, Vec x, Vec y) 1127*f8e07d23SBlanca Mellado Pinto { 1128*f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1129*f8e07d23SBlanca Mellado Pinto Vec xx; 1130*f8e07d23SBlanca Mellado Pinto PetscObjectState instate, outstate; 1131*f8e07d23SBlanca Mellado Pinto 1132*f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1133*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreZeroLeft(A, x, &xx)); 1134*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPreScaleLeft(A, xx, &xx, PETSC_TRUE)); 1135*f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 1136*f8e07d23SBlanca Mellado Pinto PetscCall((*shell->ops->multhermitiantranspose)(A, xx, y)); 1137*f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1138*f8e07d23SBlanca Mellado Pinto if (instate == outstate) { 1139*f8e07d23SBlanca Mellado Pinto /* increase the state of the output vector since the user did not update its state themself as should have been done */ 1140*f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1141*f8e07d23SBlanca Mellado Pinto } 1142*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellShiftAndScale(A, xx, y, PETSC_TRUE)); 1143*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostScaleRight(A, y, PETSC_TRUE)); 1144*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellPostZeroRight(A, y)); 1145*f8e07d23SBlanca Mellado Pinto 1146*f8e07d23SBlanca Mellado Pinto if (shell->axpy) { 1147*f8e07d23SBlanca Mellado Pinto Mat X; 1148*f8e07d23SBlanca Mellado Pinto PetscObjectState axpy_state; 1149*f8e07d23SBlanca Mellado Pinto 1150*f8e07d23SBlanca Mellado Pinto PetscCall(MatShellGetContext(shell->axpy, &X)); 1151*f8e07d23SBlanca Mellado Pinto PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 1152*f8e07d23SBlanca Mellado Pinto PetscCheck(shell->axpy_state == axpy_state, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)"); 1153*f8e07d23SBlanca Mellado Pinto PetscCall(MatCreateVecs(shell->axpy, shell->axpy_right ? NULL : &shell->axpy_right, shell->axpy_left ? NULL : &shell->axpy_left)); 1154*f8e07d23SBlanca Mellado Pinto PetscCall(VecCopy(x, shell->axpy_left)); 1155*f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(shell->axpy, shell->axpy_left, shell->axpy_right)); 1156*f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(y, PetscConj(shell->axpy_vscale), shell->axpy_right)); 1157*f8e07d23SBlanca Mellado Pinto } 1158*f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1159*f8e07d23SBlanca Mellado Pinto } 1160*f8e07d23SBlanca Mellado Pinto 1161d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1162d71ae5a4SJacob Faibussowitsch { 11635edf6516SJed Brown Mat_Shell *shell = (Mat_Shell *)A->data; 11645edf6516SJed Brown 11655edf6516SJed Brown PetscFunctionBegin; 11665edf6516SJed Brown if (y == z) { 11679566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 11689566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, shell->left_add_work)); 11699566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 11705edf6516SJed Brown } else { 11719566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, z)); 11729566063dSJacob Faibussowitsch PetscCall(VecAXPY(z, 1.0, y)); 11735edf6516SJed Brown } 11743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11755edf6516SJed Brown } 11765edf6516SJed Brown 1177*f8e07d23SBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Shell(Mat A, Vec x, Vec y, Vec z) 1178*f8e07d23SBlanca Mellado Pinto { 1179*f8e07d23SBlanca Mellado Pinto Mat_Shell *shell = (Mat_Shell *)A->data; 1180*f8e07d23SBlanca Mellado Pinto 1181*f8e07d23SBlanca Mellado Pinto PetscFunctionBegin; 1182*f8e07d23SBlanca Mellado Pinto if (y == z) { 1183*f8e07d23SBlanca Mellado Pinto if (!shell->left_add_work) PetscCall(VecDuplicate(z, &shell->left_add_work)); 1184*f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, shell->left_add_work)); 1185*f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, shell->left_add_work)); 1186*f8e07d23SBlanca Mellado Pinto } else { 1187*f8e07d23SBlanca Mellado Pinto PetscCall(MatMultHermitianTranspose(A, x, z)); 1188*f8e07d23SBlanca Mellado Pinto PetscCall(VecAXPY(z, 1.0, y)); 1189*f8e07d23SBlanca Mellado Pinto } 1190*f8e07d23SBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 1191*f8e07d23SBlanca Mellado Pinto } 1192*f8e07d23SBlanca Mellado Pinto 11930c0fd78eSBarry Smith /* 11940c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11950c0fd78eSBarry Smith */ 1196d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Shell(Mat A, Vec v) 1197d71ae5a4SJacob Faibussowitsch { 119818be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell *)A->data; 119918be62a5SSatish Balay 120018be62a5SSatish Balay PetscFunctionBegin; 12010c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 12029566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A, v)); 1203305211d5SBarry 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,...)"); 12049566063dSJacob Faibussowitsch PetscCall(VecScale(v, shell->vscale)); 12051baa6e33SBarry Smith if (shell->dshift) PetscCall(VecAXPY(v, 1.0, shell->dshift)); 12069566063dSJacob Faibussowitsch PetscCall(VecShift(v, shell->vshift)); 12079566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v, v, shell->left)); 12089566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v, v, shell->right)); 120945960306SStefano Zampini if (shell->zrows) { 12109566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 12119566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r, shell->zvals, v, INSERT_VALUES, SCATTER_REVERSE)); 121245960306SStefano Zampini } 121381c02519SBarry Smith if (shell->axpy) { 1214ef5c7bd2SStefano Zampini Mat X; 1215ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1216ef5c7bd2SStefano Zampini 12179566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy, &X)); 12189566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &axpy_state)); 121908401ef6SPierre 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,...)"); 12209566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy, NULL, shell->axpy_left ? NULL : &shell->axpy_left)); 12219566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy, shell->axpy_left)); 12229566063dSJacob Faibussowitsch PetscCall(VecAXPY(v, shell->axpy_vscale, shell->axpy_left)); 122381c02519SBarry Smith } 12243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 122518be62a5SSatish Balay } 122618be62a5SSatish Balay 1227d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Shell(Mat Y, PetscScalar a) 1228d71ae5a4SJacob Faibussowitsch { 1229ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1230789d8953SBarry Smith PetscBool flg; 1231b24ad042SBarry Smith 1232ef66eb69SBarry Smith PetscFunctionBegin; 12339566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y, &flg)); 123428b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot shift shell matrix if it is not congruent"); 12350c0fd78eSBarry Smith if (shell->left || shell->right) { 12368fe8eb27SJed Brown if (!shell->dshift) { 12379566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 12389566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift, a)); 12390c0fd78eSBarry Smith } else { 12409566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->left)); 12419566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift, shell->dshift, shell->right)); 12429566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift, a)); 12430c0fd78eSBarry Smith } 12449566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->left)); 12459566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift, shell->dshift, shell->right)); 12468fe8eb27SJed Brown } else shell->vshift += a; 12471baa6e33SBarry Smith if (shell->zrows) PetscCall(VecShift(shell->zvals, a)); 12483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1249ef66eb69SBarry Smith } 1250ef66eb69SBarry Smith 1251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell_Private(Mat A, Vec D, PetscScalar s) 1252d71ae5a4SJacob Faibussowitsch { 12536464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell *)A->data; 12546464bf51SAlex Fikl 12556464bf51SAlex Fikl PetscFunctionBegin; 12569566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D, &shell->dshift)); 12570c0fd78eSBarry Smith if (shell->left || shell->right) { 12589566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 12599f137db4SBarry Smith if (shell->left && shell->right) { 12609566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12619566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, shell->right_work, shell->right)); 12629f137db4SBarry Smith } else if (shell->left) { 12639566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->left)); 12649f137db4SBarry Smith } else { 12659566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work, D, shell->right)); 12669f137db4SBarry Smith } 12679566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, shell->right_work)); 12680c0fd78eSBarry Smith } else { 12699566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift, s, D)); 1270b253ae0bS“Marek } 12713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1272b253ae0bS“Marek } 1273b253ae0bS“Marek 127466976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Shell(Mat A, Vec D, InsertMode ins) 1275d71ae5a4SJacob Faibussowitsch { 127645960306SStefano Zampini Mat_Shell *shell = (Mat_Shell *)A->data; 1277b253ae0bS“Marek Vec d; 1278789d8953SBarry Smith PetscBool flg; 1279b253ae0bS“Marek 1280b253ae0bS“Marek PetscFunctionBegin; 12819566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &flg)); 128228b400f6SJacob Faibussowitsch PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot diagonal set or shift shell matrix if it is not congruent"); 1283b253ae0bS“Marek if (ins == INSERT_VALUES) { 12849566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D, &d)); 12859566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A, d)); 12869566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, d, -1.)); 12879566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 12891baa6e33SBarry Smith if (shell->zrows) PetscCall(VecCopy(D, shell->zvals)); 1290b253ae0bS“Marek } else { 12919566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A, D, 1.)); 12921baa6e33SBarry Smith if (shell->zrows) PetscCall(VecAXPY(shell->zvals, 1.0, D)); 12936464bf51SAlex Fikl } 12943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12956464bf51SAlex Fikl } 12966464bf51SAlex Fikl 1297d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Shell(Mat Y, PetscScalar a) 1298d71ae5a4SJacob Faibussowitsch { 1299ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1300b24ad042SBarry Smith 1301ef66eb69SBarry Smith PetscFunctionBegin; 1302f4df32b1SMatthew Knepley shell->vscale *= a; 13030c0fd78eSBarry Smith shell->vshift *= a; 13041baa6e33SBarry Smith if (shell->dshift) PetscCall(VecScale(shell->dshift, a)); 130581c02519SBarry Smith shell->axpy_vscale *= a; 13061baa6e33SBarry Smith if (shell->zrows) PetscCall(VecScale(shell->zvals, a)); 13073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130818be62a5SSatish Balay } 13098fe8eb27SJed Brown 1310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Shell(Mat Y, Vec left, Vec right) 1311d71ae5a4SJacob Faibussowitsch { 13128fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell *)Y->data; 13138fe8eb27SJed Brown 13148fe8eb27SJed Brown PetscFunctionBegin; 13158fe8eb27SJed Brown if (left) { 13160c0fd78eSBarry Smith if (!shell->left) { 13179566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left, &shell->left)); 13189566063dSJacob Faibussowitsch PetscCall(VecCopy(left, shell->left)); 13190c0fd78eSBarry Smith } else { 13209566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left, shell->left, left)); 132118be62a5SSatish Balay } 13221baa6e33SBarry Smith if (shell->zrows) PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, left)); 1323ef66eb69SBarry Smith } 13248fe8eb27SJed Brown if (right) { 13250c0fd78eSBarry Smith if (!shell->right) { 13269566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right, &shell->right)); 13279566063dSJacob Faibussowitsch PetscCall(VecCopy(right, shell->right)); 13280c0fd78eSBarry Smith } else { 13299566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right, shell->right, right)); 13308fe8eb27SJed Brown } 133145960306SStefano Zampini if (shell->zrows) { 133248a46eb9SPierre Jolivet if (!shell->left_work) PetscCall(MatCreateVecs(Y, NULL, &shell->left_work)); 13339566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w, 1.0)); 13349566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 13359566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c, right, shell->zvals_w, INSERT_VALUES, SCATTER_FORWARD)); 13369566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals, shell->zvals, shell->zvals_w)); 133745960306SStefano Zampini } 13388fe8eb27SJed Brown } 13391baa6e33SBarry Smith if (shell->axpy) PetscCall(MatDiagonalScale(shell->axpy, left, right)); 13403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1341ef66eb69SBarry Smith } 1342ef66eb69SBarry Smith 134366976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Shell(Mat Y, MatAssemblyType t) 1344d71ae5a4SJacob Faibussowitsch { 1345ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 1346ef66eb69SBarry Smith 1347ef66eb69SBarry Smith PetscFunctionBegin; 13488fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1349ef66eb69SBarry Smith shell->vshift = 0.0; 1350ef66eb69SBarry Smith shell->vscale = 1.0; 1351ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1352ef5c7bd2SStefano Zampini shell->axpy_state = 0; 13539566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 13549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 13559566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 13569566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 13579566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 13589566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 13599566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 13609566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 13619566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 13629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1363ef66eb69SBarry Smith } 13643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1365ef66eb69SBarry Smith } 1366ef66eb69SBarry Smith 1367d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Shell(Mat A, PetscBool *missing, PetscInt *d) 1368d71ae5a4SJacob Faibussowitsch { 13693b49f96aSBarry Smith PetscFunctionBegin; 13703b49f96aSBarry Smith *missing = PETSC_FALSE; 13713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13723b49f96aSBarry Smith } 13733b49f96aSBarry Smith 137466976f2fSJacob Faibussowitsch static PetscErrorCode MatAXPY_Shell(Mat Y, PetscScalar a, Mat X, MatStructure str) 1375d71ae5a4SJacob Faibussowitsch { 13769f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell *)Y->data; 13779f137db4SBarry Smith 13789f137db4SBarry Smith PetscFunctionBegin; 1379ef5c7bd2SStefano Zampini if (X == Y) { 13809566063dSJacob Faibussowitsch PetscCall(MatScale(Y, 1.0 + a)); 13813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1382ef5c7bd2SStefano Zampini } 1383ef5c7bd2SStefano Zampini if (!shell->axpy) { 13849566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X, MATSHELL, MAT_INITIAL_MATRIX, &shell->axpy)); 13859f137db4SBarry Smith shell->axpy_vscale = a; 13869566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X, &shell->axpy_state)); 1387ef5c7bd2SStefano Zampini } else { 13889566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy, a / shell->axpy_vscale, X, str)); 1389ef5c7bd2SStefano Zampini } 13903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 13919f137db4SBarry Smith } 13929f137db4SBarry Smith 1393f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1394f4259b30SLisandro Dalcin NULL, 1395f4259b30SLisandro Dalcin NULL, 1396f4259b30SLisandro Dalcin NULL, 13970c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1398f4259b30SLisandro Dalcin NULL, 13990c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1400f4259b30SLisandro Dalcin NULL, 1401f4259b30SLisandro Dalcin NULL, 1402f4259b30SLisandro Dalcin NULL, 1403f4259b30SLisandro Dalcin /*10*/ NULL, 1404f4259b30SLisandro Dalcin NULL, 1405f4259b30SLisandro Dalcin NULL, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin NULL, 1408f4259b30SLisandro Dalcin /*15*/ NULL, 1409f4259b30SLisandro Dalcin NULL, 1410f4259b30SLisandro Dalcin NULL, 14118fe8eb27SJed Brown MatDiagonalScale_Shell, 1412f4259b30SLisandro Dalcin NULL, 1413f4259b30SLisandro Dalcin /*20*/ NULL, 1414ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1415f4259b30SLisandro Dalcin NULL, 1416f4259b30SLisandro Dalcin NULL, 141745960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1418f4259b30SLisandro Dalcin NULL, 1419f4259b30SLisandro Dalcin NULL, 1420f4259b30SLisandro Dalcin NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin /*29*/ NULL, 1423f4259b30SLisandro Dalcin NULL, 1424f4259b30SLisandro Dalcin NULL, 1425f4259b30SLisandro Dalcin NULL, 1426f4259b30SLisandro Dalcin NULL, 1427cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin NULL, 1430f4259b30SLisandro Dalcin NULL, 1431f4259b30SLisandro Dalcin NULL, 14329f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1433f4259b30SLisandro Dalcin NULL, 1434f4259b30SLisandro Dalcin NULL, 1435f4259b30SLisandro Dalcin NULL, 1436cb8c8a77SBarry Smith MatCopy_Shell, 1437f4259b30SLisandro Dalcin /*44*/ NULL, 1438ef66eb69SBarry Smith MatScale_Shell, 1439ef66eb69SBarry Smith MatShift_Shell, 14406464bf51SAlex Fikl MatDiagonalSet_Shell, 144145960306SStefano Zampini MatZeroRowsColumns_Shell, 1442f4259b30SLisandro Dalcin /*49*/ NULL, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin NULL, 1445f4259b30SLisandro Dalcin NULL, 1446f4259b30SLisandro Dalcin NULL, 1447f4259b30SLisandro Dalcin /*54*/ NULL, 1448f4259b30SLisandro Dalcin NULL, 1449f4259b30SLisandro Dalcin NULL, 1450f4259b30SLisandro Dalcin NULL, 1451f4259b30SLisandro Dalcin NULL, 1452f4259b30SLisandro Dalcin /*59*/ NULL, 1453b9b97703SBarry Smith MatDestroy_Shell, 1454f4259b30SLisandro Dalcin NULL, 1455251fad3fSStefano Zampini MatConvertFrom_Shell, 1456f4259b30SLisandro Dalcin NULL, 1457f4259b30SLisandro Dalcin /*64*/ NULL, 1458f4259b30SLisandro Dalcin NULL, 1459f4259b30SLisandro Dalcin NULL, 1460f4259b30SLisandro Dalcin NULL, 1461f4259b30SLisandro Dalcin NULL, 1462f4259b30SLisandro Dalcin /*69*/ NULL, 1463f4259b30SLisandro Dalcin NULL, 1464c87e5d42SMatthew Knepley MatConvert_Shell, 1465f4259b30SLisandro Dalcin NULL, 1466f4259b30SLisandro Dalcin NULL, 1467f4259b30SLisandro Dalcin /*74*/ NULL, 1468f4259b30SLisandro Dalcin NULL, 1469f4259b30SLisandro Dalcin NULL, 1470f4259b30SLisandro Dalcin NULL, 1471f4259b30SLisandro Dalcin NULL, 1472f4259b30SLisandro Dalcin /*79*/ NULL, 1473f4259b30SLisandro Dalcin NULL, 1474f4259b30SLisandro Dalcin NULL, 1475f4259b30SLisandro Dalcin NULL, 1476f4259b30SLisandro Dalcin NULL, 1477f4259b30SLisandro Dalcin /*84*/ NULL, 1478f4259b30SLisandro Dalcin NULL, 1479f4259b30SLisandro Dalcin NULL, 1480f4259b30SLisandro Dalcin NULL, 1481f4259b30SLisandro Dalcin NULL, 1482f4259b30SLisandro Dalcin /*89*/ NULL, 1483f4259b30SLisandro Dalcin NULL, 1484f4259b30SLisandro Dalcin NULL, 1485f4259b30SLisandro Dalcin NULL, 1486f4259b30SLisandro Dalcin NULL, 1487f4259b30SLisandro Dalcin /*94*/ NULL, 1488f4259b30SLisandro Dalcin NULL, 1489f4259b30SLisandro Dalcin NULL, 1490f4259b30SLisandro Dalcin NULL, 1491f4259b30SLisandro Dalcin NULL, 1492f4259b30SLisandro Dalcin /*99*/ NULL, 1493f4259b30SLisandro Dalcin NULL, 1494f4259b30SLisandro Dalcin NULL, 1495f4259b30SLisandro Dalcin NULL, 1496f4259b30SLisandro Dalcin NULL, 1497f4259b30SLisandro Dalcin /*104*/ NULL, 1498f4259b30SLisandro Dalcin NULL, 1499f4259b30SLisandro Dalcin NULL, 1500f4259b30SLisandro Dalcin NULL, 1501f4259b30SLisandro Dalcin NULL, 1502f4259b30SLisandro Dalcin /*109*/ NULL, 1503f4259b30SLisandro Dalcin NULL, 1504f4259b30SLisandro Dalcin NULL, 1505f4259b30SLisandro Dalcin NULL, 15063b49f96aSBarry Smith MatMissingDiagonal_Shell, 1507f4259b30SLisandro Dalcin /*114*/ NULL, 1508f4259b30SLisandro Dalcin NULL, 1509f4259b30SLisandro Dalcin NULL, 1510f4259b30SLisandro Dalcin NULL, 1511f4259b30SLisandro Dalcin NULL, 1512f4259b30SLisandro Dalcin /*119*/ NULL, 1513f4259b30SLisandro Dalcin NULL, 1514f4259b30SLisandro Dalcin NULL, 1515*f8e07d23SBlanca Mellado Pinto MatMultHermitianTransposeAdd_Shell, 1516f4259b30SLisandro Dalcin NULL, 1517f4259b30SLisandro Dalcin /*124*/ NULL, 1518f4259b30SLisandro Dalcin NULL, 1519f4259b30SLisandro Dalcin NULL, 1520f4259b30SLisandro Dalcin NULL, 1521f4259b30SLisandro Dalcin NULL, 1522f4259b30SLisandro Dalcin /*129*/ NULL, 1523f4259b30SLisandro Dalcin NULL, 1524f4259b30SLisandro Dalcin NULL, 1525f4259b30SLisandro Dalcin NULL, 1526f4259b30SLisandro Dalcin NULL, 1527f4259b30SLisandro Dalcin /*134*/ NULL, 1528f4259b30SLisandro Dalcin NULL, 1529f4259b30SLisandro Dalcin NULL, 1530f4259b30SLisandro Dalcin NULL, 1531f4259b30SLisandro Dalcin NULL, 1532f4259b30SLisandro Dalcin /*139*/ NULL, 1533f4259b30SLisandro Dalcin NULL, 1534d70f29a3SPierre Jolivet NULL, 1535d70f29a3SPierre Jolivet NULL, 1536d70f29a3SPierre Jolivet NULL, 1537d70f29a3SPierre Jolivet /*144*/ NULL, 1538d70f29a3SPierre Jolivet NULL, 1539d70f29a3SPierre Jolivet NULL, 154099a7f59eSMark Adams NULL, 154199a7f59eSMark Adams NULL, 15427fb60732SBarry Smith NULL, 1543dec0b466SHong Zhang /*150*/ NULL, 1544dec0b466SHong Zhang NULL}; 1545273d9f13SBarry Smith 1546d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetContext_Shell(Mat mat, void *ctx) 1547d71ae5a4SJacob Faibussowitsch { 1548789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1549789d8953SBarry Smith 1550789d8953SBarry Smith PetscFunctionBegin; 1551800f99ffSJeremy L Thompson if (ctx) { 1552800f99ffSJeremy L Thompson PetscContainer ctxcontainer; 1553800f99ffSJeremy L Thompson PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)mat), &ctxcontainer)); 1554800f99ffSJeremy L Thompson PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 1555800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", (PetscObject)ctxcontainer)); 1556800f99ffSJeremy L Thompson shell->ctxcontainer = ctxcontainer; 1557800f99ffSJeremy L Thompson PetscCall(PetscContainerDestroy(&ctxcontainer)); 1558800f99ffSJeremy L Thompson } else { 1559800f99ffSJeremy L Thompson PetscCall(PetscObjectCompose((PetscObject)mat, "MatShell ctx", NULL)); 1560800f99ffSJeremy L Thompson shell->ctxcontainer = NULL; 1561800f99ffSJeremy L Thompson } 1562800f99ffSJeremy L Thompson 15633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1564800f99ffSJeremy L Thompson } 1565800f99ffSJeremy L Thompson 156666976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetContextDestroy_Shell(Mat mat, PetscErrorCode (*f)(void *)) 1567d71ae5a4SJacob Faibussowitsch { 1568800f99ffSJeremy L Thompson Mat_Shell *shell = (Mat_Shell *)mat->data; 1569800f99ffSJeremy L Thompson 1570800f99ffSJeremy L Thompson PetscFunctionBegin; 1571800f99ffSJeremy L Thompson if (shell->ctxcontainer) PetscCall(PetscContainerSetUserDestroy(shell->ctxcontainer, f)); 15723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1573789d8953SBarry Smith } 1574789d8953SBarry Smith 1575d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetVecType_Shell(Mat mat, VecType vtype) 1576d71ae5a4SJacob Faibussowitsch { 1577db77db73SJeremy L Thompson PetscFunctionBegin; 15789566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 15799566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype, (char **)&mat->defaultvectype)); 15803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1581db77db73SJeremy L Thompson } 1582db77db73SJeremy L Thompson 158366976f2fSJacob Faibussowitsch static PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1584d71ae5a4SJacob Faibussowitsch { 1585789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)A->data; 1586789d8953SBarry Smith 1587789d8953SBarry Smith PetscFunctionBegin; 1588789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1589789d8953SBarry Smith A->ops->diagonalset = NULL; 1590789d8953SBarry Smith A->ops->diagonalscale = NULL; 1591789d8953SBarry Smith A->ops->scale = NULL; 1592789d8953SBarry Smith A->ops->shift = NULL; 1593789d8953SBarry Smith A->ops->axpy = NULL; 15943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1595789d8953SBarry Smith } 1596789d8953SBarry Smith 1597d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellSetOperation_Shell(Mat mat, MatOperation op, void (*f)(void)) 1598d71ae5a4SJacob Faibussowitsch { 1599feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell *)mat->data; 1600789d8953SBarry Smith 1601789d8953SBarry Smith PetscFunctionBegin; 1602789d8953SBarry Smith switch (op) { 1603d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1604d71ae5a4SJacob Faibussowitsch shell->ops->destroy = (PetscErrorCode(*)(Mat))f; 1605d71ae5a4SJacob Faibussowitsch break; 1606789d8953SBarry Smith case MATOP_VIEW: 1607ad540459SPierre Jolivet if (!mat->ops->viewnative) mat->ops->viewnative = mat->ops->view; 1608789d8953SBarry Smith mat->ops->view = (PetscErrorCode(*)(Mat, PetscViewer))f; 1609789d8953SBarry Smith break; 1610d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1611d71ae5a4SJacob Faibussowitsch shell->ops->copy = (PetscErrorCode(*)(Mat, Mat, MatStructure))f; 1612d71ae5a4SJacob Faibussowitsch break; 1613789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1614789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1615789d8953SBarry Smith case MATOP_SHIFT: 1616789d8953SBarry Smith case MATOP_SCALE: 1617789d8953SBarry Smith case MATOP_AXPY: 1618789d8953SBarry Smith case MATOP_ZERO_ROWS: 1619789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 162028b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1621789d8953SBarry Smith (((void (**)(void))mat->ops)[op]) = f; 1622789d8953SBarry Smith break; 1623789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1624789d8953SBarry Smith if (shell->managescalingshifts) { 1625789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1626789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1627789d8953SBarry Smith } else { 1628789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1629789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode(*)(Mat, Vec))f; 1630789d8953SBarry Smith } 1631789d8953SBarry Smith break; 1632789d8953SBarry Smith case MATOP_MULT: 1633789d8953SBarry Smith if (shell->managescalingshifts) { 1634789d8953SBarry Smith shell->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1635789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1636789d8953SBarry Smith } else { 1637789d8953SBarry Smith shell->ops->mult = NULL; 1638789d8953SBarry Smith mat->ops->mult = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1639789d8953SBarry Smith } 1640789d8953SBarry Smith break; 1641789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1642789d8953SBarry Smith if (shell->managescalingshifts) { 1643789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1644789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1645789d8953SBarry Smith } else { 1646789d8953SBarry Smith shell->ops->multtranspose = NULL; 1647789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1648789d8953SBarry Smith } 1649789d8953SBarry Smith break; 1650*f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1651*f8e07d23SBlanca Mellado Pinto if (shell->managescalingshifts) { 1652*f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1653*f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = MatMultHermitianTranspose_Shell; 1654*f8e07d23SBlanca Mellado Pinto } else { 1655*f8e07d23SBlanca Mellado Pinto shell->ops->multhermitiantranspose = NULL; 1656*f8e07d23SBlanca Mellado Pinto mat->ops->multhermitiantranspose = (PetscErrorCode(*)(Mat, Vec, Vec))f; 1657*f8e07d23SBlanca Mellado Pinto } 1658*f8e07d23SBlanca Mellado Pinto break; 1659d71ae5a4SJacob Faibussowitsch default: 1660d71ae5a4SJacob Faibussowitsch (((void (**)(void))mat->ops)[op]) = f; 1661d71ae5a4SJacob Faibussowitsch break; 1662789d8953SBarry Smith } 16633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1664789d8953SBarry Smith } 1665789d8953SBarry Smith 1666d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShellGetOperation_Shell(Mat mat, MatOperation op, void (**f)(void)) 1667d71ae5a4SJacob Faibussowitsch { 1668789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell *)mat->data; 1669789d8953SBarry Smith 1670789d8953SBarry Smith PetscFunctionBegin; 1671789d8953SBarry Smith switch (op) { 1672d71ae5a4SJacob Faibussowitsch case MATOP_DESTROY: 1673d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->destroy; 1674d71ae5a4SJacob Faibussowitsch break; 1675d71ae5a4SJacob Faibussowitsch case MATOP_VIEW: 1676d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))mat->ops->view; 1677d71ae5a4SJacob Faibussowitsch break; 1678d71ae5a4SJacob Faibussowitsch case MATOP_COPY: 1679d71ae5a4SJacob Faibussowitsch *f = (void (*)(void))shell->ops->copy; 1680d71ae5a4SJacob Faibussowitsch break; 1681789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1682789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1683789d8953SBarry Smith case MATOP_SHIFT: 1684789d8953SBarry Smith case MATOP_SCALE: 1685789d8953SBarry Smith case MATOP_AXPY: 1686789d8953SBarry Smith case MATOP_ZERO_ROWS: 1687d71ae5a4SJacob Faibussowitsch case MATOP_ZERO_ROWS_COLUMNS: 1688d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1689d71ae5a4SJacob Faibussowitsch break; 1690789d8953SBarry Smith case MATOP_GET_DIAGONAL: 16919371c9d4SSatish Balay if (shell->ops->getdiagonal) *f = (void (*)(void))shell->ops->getdiagonal; 16929371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1693789d8953SBarry Smith break; 1694789d8953SBarry Smith case MATOP_MULT: 16959371c9d4SSatish Balay if (shell->ops->mult) *f = (void (*)(void))shell->ops->mult; 16969371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1697789d8953SBarry Smith break; 1698789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 16999371c9d4SSatish Balay if (shell->ops->multtranspose) *f = (void (*)(void))shell->ops->multtranspose; 17009371c9d4SSatish Balay else *f = (((void (**)(void))mat->ops)[op]); 1701789d8953SBarry Smith break; 1702*f8e07d23SBlanca Mellado Pinto case MATOP_MULT_HERMITIAN_TRANSPOSE: 1703*f8e07d23SBlanca Mellado Pinto if (shell->ops->multhermitiantranspose) *f = (void (*)(void))shell->ops->multhermitiantranspose; 1704*f8e07d23SBlanca Mellado Pinto else *f = (((void (**)(void))mat->ops)[op]); 1705*f8e07d23SBlanca Mellado Pinto break; 1706d71ae5a4SJacob Faibussowitsch default: 1707d71ae5a4SJacob Faibussowitsch *f = (((void (**)(void))mat->ops)[op]); 1708789d8953SBarry Smith } 17093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1710789d8953SBarry Smith } 1711789d8953SBarry Smith 17120bad9183SKris Buschelman /*MC 171301c1178eSBarry Smith MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix-free. 17140bad9183SKris Buschelman 17150bad9183SKris Buschelman Level: advanced 17160bad9183SKris Buschelman 17171cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateShell()` 17180bad9183SKris Buschelman M*/ 17190bad9183SKris Buschelman 1720d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1721d71ae5a4SJacob Faibussowitsch { 1722273d9f13SBarry Smith Mat_Shell *b; 1723273d9f13SBarry Smith 1724273d9f13SBarry Smith PetscFunctionBegin; 17254dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&b)); 1726273d9f13SBarry Smith A->data = (void *)b; 1727aea10558SJacob Faibussowitsch A->ops[0] = MatOps_Values; 1728273d9f13SBarry Smith 1729800f99ffSJeremy L Thompson b->ctxcontainer = NULL; 1730ef66eb69SBarry Smith b->vshift = 0.0; 1731ef66eb69SBarry Smith b->vscale = 1.0; 17320c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1733273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1734210f0121SBarry Smith A->preallocated = PETSC_FALSE; 17352205254eSKarl Rupp 17369566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetContext_C", MatShellGetContext_Shell)); 17379566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Shell)); 1738800f99ffSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Shell)); 17399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetVecType_C", MatShellSetVecType_Shell)); 17409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Shell)); 17419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetOperation_C", MatShellSetOperation_Shell)); 17429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellGetOperation_C", MatShellGetOperation_Shell)); 17439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetMatProductOperation_C", MatShellSetMatProductOperation_Shell)); 17449566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSHELL)); 17453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1746273d9f13SBarry Smith } 1747e51e0e81SBarry Smith 17484b828684SBarry Smith /*@C 174911a5261eSBarry Smith MatCreateShell - Creates a new matrix of `MatType` `MATSHELL` for use with a user-defined 1750ff756334SLois Curfman McInnes private data storage format. 1751e51e0e81SBarry Smith 1752d083f849SBarry Smith Collective 1753c7fcc2eaSBarry Smith 1754e51e0e81SBarry Smith Input Parameters: 1755c7fcc2eaSBarry Smith + comm - MPI communicator 175645f401ebSJose E. Roman . m - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given) 175745f401ebSJose E. Roman . n - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given) 175845f401ebSJose E. Roman . M - number of global rows (may be `PETSC_DETERMINE` to have calculated if `m` is given) 175945f401ebSJose E. Roman . N - number of global columns (may be `PETSC_DETERMINE` to have calculated if `n` is given) 1760c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1761e51e0e81SBarry Smith 1762ff756334SLois Curfman McInnes Output Parameter: 176344cd7ae7SLois Curfman McInnes . A - the matrix 1764e51e0e81SBarry Smith 1765ff2fd236SBarry Smith Level: advanced 1766ff2fd236SBarry Smith 17672920cce0SJacob Faibussowitsch Example Usage: 176827430b45SBarry Smith .vb 176927430b45SBarry Smith extern PetscErrorCode mult(Mat, Vec, Vec); 17702920cce0SJacob Faibussowitsch 177127430b45SBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &mat); 177227430b45SBarry Smith MatShellSetOperation(mat, MATOP_MULT, (void(*)(void))mult); 17732920cce0SJacob Faibussowitsch // Use matrix for operations that have been set 177427430b45SBarry Smith MatDestroy(mat); 177527430b45SBarry Smith .ve 1776f39d1f56SLois Curfman McInnes 1777ff756334SLois Curfman McInnes Notes: 1778ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 177911a5261eSBarry Smith with `KSP` (such as, for use with matrix-free methods). You should not 1780ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1781e51e0e81SBarry Smith 1782f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1783f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 17842ef1f0ffSBarry Smith creating a shell matrix, `A`, that supports parallel matrix-vector 178511a5261eSBarry Smith products using `MatMult`(A,x,y) the user should set the number 1786645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1787645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1788645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1789645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1790645985a0SLois Curfman McInnes For example, 1791f39d1f56SLois Curfman McInnes 179227430b45SBarry Smith .vb 179327430b45SBarry Smith Vec x, y 179427430b45SBarry Smith extern PetscErrorCode mult(Mat,Vec,Vec); 179527430b45SBarry Smith Mat A 179627430b45SBarry Smith 179727430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,M,&y); 179827430b45SBarry Smith VecCreateMPI(comm,PETSC_DECIDE,N,&x); 179927430b45SBarry Smith VecGetLocalSize(y,&m); 180027430b45SBarry Smith VecGetLocalSize(x,&n); 180127430b45SBarry Smith MatCreateShell(comm,m,n,M,N,ctx,&A); 180227430b45SBarry Smith MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 180327430b45SBarry Smith MatMult(A,x,y); 180427430b45SBarry Smith MatDestroy(&A); 180527430b45SBarry Smith VecDestroy(&y); 180627430b45SBarry Smith VecDestroy(&x); 180727430b45SBarry Smith .ve 1808e51e0e81SBarry Smith 18092ef1f0ffSBarry Smith `MATSHELL` handles `MatShift()`, `MatDiagonalSet()`, `MatDiagonalScale()`, `MatAXPY()`, `MatScale()`, `MatZeroRows()` and `MatZeroRowsColumns()` 18102ef1f0ffSBarry Smith internally, so these operations cannot be overwritten unless `MatShellSetManageScalingShifts()` is called. 18110c0fd78eSBarry Smith 181227430b45SBarry Smith Developer Notes: 18132ef1f0ffSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 18142ef1f0ffSBarry Smith 181595452b02SPatrick Sanan Regarding shifting and scaling. The general form is 18160c0fd78eSBarry Smith 18170c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 18180c0fd78eSBarry Smith 18190c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 18200c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 18210c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 18220c0fd78eSBarry Smith 18230c0fd78eSBarry Smith A is the user provided function. 18240c0fd78eSBarry Smith 182527430b45SBarry Smith `KSP`/`PC` uses changes in the `Mat`'s "state" to decide if preconditioners need to be rebuilt `PCSetUp()` only calls the setup() for 1826c5dec841SPierre Jolivet for the `PC` implementation if the `Mat` state has increased from the previous call. Thus to get changes in a `MATSHELL` to trigger 182711a5261eSBarry Smith an update in the preconditioner you must call `MatAssemblyBegin()` and `MatAssemblyEnd()` or `PetscObjectStateIncrease`((`PetscObject`)mat); 182811a5261eSBarry Smith each time the `MATSHELL` matrix has changed. 1829ad2f5c3fSBarry Smith 183011a5261eSBarry Smith Matrix product operations (i.e. `MatMat()`, `MatTransposeMat()` etc) can be specified using `MatShellSetMatProductOperation()` 1831b77ba244SStefano Zampini 183211a5261eSBarry Smith Calling `MatAssemblyBegin()`/`MatAssemblyEnd()` on a `MATSHELL` removes any previously supplied shift and scales that were provided 183311a5261eSBarry Smith with `MatDiagonalSet()`, `MatShift()`, `MatScale()`, or `MatDiagonalScale()`. 1834ad2f5c3fSBarry Smith 1835fe59aa6dSJacob Faibussowitsch Fortran Notes: 18362ef1f0ffSBarry Smith To use this from Fortran with a `ctx` you must write an interface definition for this 183711a5261eSBarry Smith function and for `MatShellGetContext()` that tells Fortran the Fortran derived data type you are passing 18382ef1f0ffSBarry Smith in as the `ctx` argument. 183911a5261eSBarry Smith 1840fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatShellSetOperation()`, `MatHasOperation()`, `MatShellGetContext()`, `MatShellSetContext()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 1841e51e0e81SBarry Smith @*/ 1842d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateShell(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, void *ctx, Mat *A) 1843d71ae5a4SJacob Faibussowitsch { 18443a40ed3dSBarry Smith PetscFunctionBegin; 18459566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, A)); 18469566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A, m, n, M, N)); 18479566063dSJacob Faibussowitsch PetscCall(MatSetType(*A, MATSHELL)); 18489566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A, ctx)); 18499566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 18503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1851c7fcc2eaSBarry Smith } 1852c7fcc2eaSBarry Smith 1853c6866cfdSSatish Balay /*@ 185411a5261eSBarry Smith MatShellSetContext - sets the context for a `MATSHELL` shell matrix 1855c7fcc2eaSBarry Smith 1856c3339decSBarry Smith Logically Collective 1857c7fcc2eaSBarry Smith 1858273d9f13SBarry Smith Input Parameters: 185911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1860273d9f13SBarry Smith - ctx - the context 1861273d9f13SBarry Smith 1862273d9f13SBarry Smith Level: advanced 1863273d9f13SBarry Smith 1864fe59aa6dSJacob Faibussowitsch Fortran Notes: 186527430b45SBarry Smith You must write a Fortran interface definition for this 18662ef1f0ffSBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the `ctx` argument. 1867273d9f13SBarry Smith 18681cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()` 18690bc0a719SBarry Smith @*/ 1870d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContext(Mat mat, void *ctx) 1871d71ae5a4SJacob Faibussowitsch { 1872273d9f13SBarry Smith PetscFunctionBegin; 18730700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1874cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetContext_C", (Mat, void *), (mat, ctx)); 18753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1876e51e0e81SBarry Smith } 1877e51e0e81SBarry Smith 1878fe59aa6dSJacob Faibussowitsch /*@C 187911a5261eSBarry Smith MatShellSetContextDestroy - sets the destroy function for a `MATSHELL` shell matrix context 1880800f99ffSJeremy L Thompson 1881c3339decSBarry Smith Logically Collective 1882800f99ffSJeremy L Thompson 1883800f99ffSJeremy L Thompson Input Parameters: 1884800f99ffSJeremy L Thompson + mat - the shell matrix 1885800f99ffSJeremy L Thompson - f - the context destroy function 1886800f99ffSJeremy L Thompson 188727430b45SBarry Smith Level: advanced 188827430b45SBarry Smith 1889800f99ffSJeremy L Thompson Note: 1890800f99ffSJeremy L Thompson If the `MatShell` is never duplicated, the behavior of this function is equivalent 189111a5261eSBarry Smith to `MatShellSetOperation`(`Mat`,`MATOP_DESTROY`,f). However, `MatShellSetContextDestroy()` 1892800f99ffSJeremy L Thompson ensures proper reference counting for the user provided context data in the case that 189311a5261eSBarry Smith the `MATSHELL` is duplicated. 1894800f99ffSJeremy L Thompson 18951cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellSetContext()` 1896800f99ffSJeremy L Thompson @*/ 1897d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetContextDestroy(Mat mat, PetscErrorCode (*f)(void *)) 1898d71ae5a4SJacob Faibussowitsch { 1899800f99ffSJeremy L Thompson PetscFunctionBegin; 1900800f99ffSJeremy L Thompson PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1901800f99ffSJeremy L Thompson PetscTryMethod(mat, "MatShellSetContextDestroy_C", (Mat, PetscErrorCode(*)(void *)), (mat, f)); 19023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1903800f99ffSJeremy L Thompson } 1904800f99ffSJeremy L Thompson 1905db77db73SJeremy L Thompson /*@C 19062ef1f0ffSBarry Smith MatShellSetVecType - Sets the `VecType` of `Vec` returned by `MatCreateVecs()` 1907db77db73SJeremy L Thompson 19082ef1f0ffSBarry Smith Logically Collective 1909db77db73SJeremy L Thompson 1910db77db73SJeremy L Thompson Input Parameters: 191111a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1912db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1913db77db73SJeremy L Thompson 1914db77db73SJeremy L Thompson Level: advanced 1915db77db73SJeremy L Thompson 19161cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateVecs()` 1917db77db73SJeremy L Thompson @*/ 1918d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetVecType(Mat mat, VecType vtype) 1919d71ae5a4SJacob Faibussowitsch { 1920db77db73SJeremy L Thompson PetscFunctionBegin; 1921cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetVecType_C", (Mat, VecType), (mat, vtype)); 19223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1923db77db73SJeremy L Thompson } 1924db77db73SJeremy L Thompson 19250c0fd78eSBarry Smith /*@ 192611a5261eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the `MATSHELL`. Must be called immediately 192711a5261eSBarry Smith after `MatCreateShell()` 19280c0fd78eSBarry Smith 192927430b45SBarry Smith Logically Collective 19300c0fd78eSBarry Smith 19310c0fd78eSBarry Smith Input Parameter: 1932fe59aa6dSJacob Faibussowitsch . A - the `MATSHELL` shell matrix 19330c0fd78eSBarry Smith 19340c0fd78eSBarry Smith Level: advanced 19350c0fd78eSBarry Smith 19361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatShellSetOperation()` 19370c0fd78eSBarry Smith @*/ 1938d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetManageScalingShifts(Mat A) 1939d71ae5a4SJacob Faibussowitsch { 19400c0fd78eSBarry Smith PetscFunctionBegin; 19410c0fd78eSBarry Smith PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1942cac4c232SBarry Smith PetscTryMethod(A, "MatShellSetManageScalingShifts_C", (Mat), (A)); 19433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19440c0fd78eSBarry Smith } 19450c0fd78eSBarry Smith 1946c16cb8f2SBarry Smith /*@C 194711a5261eSBarry Smith MatShellTestMult - Compares the multiply routine provided to the `MATSHELL` with differencing on a given function. 1948f3b1f45cSBarry Smith 1949cf53795eSBarry Smith Logically Collective; No Fortran Support 1950f3b1f45cSBarry Smith 1951f3b1f45cSBarry Smith Input Parameters: 195211a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 1953f3b1f45cSBarry Smith . f - the function 195411a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 1955f3b1f45cSBarry Smith - ctx - an optional context for the function 1956f3b1f45cSBarry Smith 1957f3b1f45cSBarry Smith Output Parameter: 195811a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 1959f3b1f45cSBarry Smith 19603c7db156SBarry Smith Options Database Key: 1961f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1962f3b1f45cSBarry Smith 1963f3b1f45cSBarry Smith Level: advanced 1964f3b1f45cSBarry Smith 19651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMultTranspose()` 1966f3b1f45cSBarry Smith @*/ 1967d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMult(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 1968d71ae5a4SJacob Faibussowitsch { 1969f3b1f45cSBarry Smith PetscInt m, n; 1970f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 1971f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 197274e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1973f3b1f45cSBarry Smith 1974f3b1f45cSBarry Smith PetscFunctionBegin; 1975f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 19769566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_view", &v)); 19779566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 19789566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, PETSC_DECIDE, PETSC_DECIDE, &mf)); 19799566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 19809566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 1981f3b1f45cSBarry Smith 19829566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 19839566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat, MATAIJ, &Dmat)); 1984f3b1f45cSBarry Smith 19859566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 19869566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 19879566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 19889566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 1989f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 1990f3b1f45cSBarry Smith flag = PETSC_FALSE; 1991f3b1f45cSBarry Smith if (v) { 199201c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n", (double)(Diffnorm / Dmfnorm))); 19939566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_view")); 19949566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_view")); 19959566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_view")); 1996f3b1f45cSBarry Smith } 1997f3b1f45cSBarry Smith } else if (v) { 199801c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce the same results\n")); 1999f3b1f45cSBarry Smith } 2000f3b1f45cSBarry Smith if (flg) *flg = flag; 20019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20029566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20039566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 20049566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2006f3b1f45cSBarry Smith } 2007f3b1f45cSBarry Smith 2008f3b1f45cSBarry Smith /*@C 200911a5261eSBarry Smith MatShellTestMultTranspose - Compares the multiply transpose routine provided to the `MATSHELL` with differencing on a given function. 2010f3b1f45cSBarry Smith 2011cf53795eSBarry Smith Logically Collective; No Fortran Support 2012f3b1f45cSBarry Smith 2013f3b1f45cSBarry Smith Input Parameters: 201411a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2015f3b1f45cSBarry Smith . f - the function 201611a5261eSBarry Smith . base - differences are computed around this vector, see `MatMFFDSetBase()`, for Jacobians this is the point at which the Jacobian is being evaluated 2017f3b1f45cSBarry Smith - ctx - an optional context for the function 2018f3b1f45cSBarry Smith 2019f3b1f45cSBarry Smith Output Parameter: 202011a5261eSBarry Smith . flg - `PETSC_TRUE` if the multiply is likely correct 2021f3b1f45cSBarry Smith 20223c7db156SBarry Smith Options Database Key: 2023f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 2024f3b1f45cSBarry Smith 2025f3b1f45cSBarry Smith Level: advanced 2026f3b1f45cSBarry Smith 20271cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellTestMult()` 2028f3b1f45cSBarry Smith @*/ 2029d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellTestMultTranspose(Mat mat, PetscErrorCode (*f)(void *, Vec, Vec), Vec base, void *ctx, PetscBool *flg) 2030d71ae5a4SJacob Faibussowitsch { 2031f3b1f45cSBarry Smith Vec x, y, z; 2032f3b1f45cSBarry Smith PetscInt m, n, M, N; 2033f3b1f45cSBarry Smith Mat mf, Dmf, Dmat, Ddiff; 2034f3b1f45cSBarry Smith PetscReal Diffnorm, Dmfnorm; 203574e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 2036f3b1f45cSBarry Smith 2037f3b1f45cSBarry Smith PetscFunctionBegin; 2038f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 20399566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject)mat)->prefix, "-mat_shell_test_mult_transpose_view", &v)); 20409566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat, &x, &y)); 20419566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y, &z)); 20429566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 20439566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 20449566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat), m, n, M, N, &mf)); 20459566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf, f, ctx)); 20469566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf, base, NULL)); 20479566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf, MATAIJ, &Dmf)); 20489566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf, MAT_INPLACE_MATRIX, &Dmf)); 20499566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat, MATAIJ, &Dmat)); 2050f3b1f45cSBarry Smith 20519566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat, MAT_COPY_VALUES, &Ddiff)); 20529566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff, -1.0, Dmf, DIFFERENT_NONZERO_PATTERN)); 20539566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff, NORM_FROBENIUS, &Diffnorm)); 20549566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf, NORM_FROBENIUS, &Dmfnorm)); 2055f3b1f45cSBarry Smith if (Diffnorm / Dmfnorm > 10 * PETSC_SQRT_MACHINE_EPSILON) { 2056f3b1f45cSBarry Smith flag = PETSC_FALSE; 2057f3b1f45cSBarry Smith if (v) { 205801c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL and matrix-free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n", (double)(Diffnorm / Dmfnorm))); 20599566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20609566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 20619566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat, (PetscObject)mat, "-mat_shell_test_mult_transpose_view")); 2062f3b1f45cSBarry Smith } 2063f3b1f45cSBarry Smith } else if (v) { 206401c1178eSBarry Smith PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "MATSHELL transpose and matrix-free multiple appear to produce the same results\n")); 2065f3b1f45cSBarry Smith } 2066f3b1f45cSBarry Smith if (flg) *flg = flag; 20679566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 20689566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 20699566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 20709566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 20719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 20729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 20739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 20743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2075f3b1f45cSBarry Smith } 2076f3b1f45cSBarry Smith 2077f3b1f45cSBarry Smith /*@C 207811a5261eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a `MATSHELL` shell matrix. 2079e51e0e81SBarry Smith 2080c3339decSBarry Smith Logically Collective 2081fee21e36SBarry Smith 2082c7fcc2eaSBarry Smith Input Parameters: 208311a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2084c7fcc2eaSBarry Smith . op - the name of the operation 2085789d8953SBarry Smith - g - the function that provides the operation. 2086c7fcc2eaSBarry Smith 208715091d37SBarry Smith Level: advanced 208815091d37SBarry Smith 20892920cce0SJacob Faibussowitsch Example Usage: 2090c3339decSBarry Smith .vb 2091c3339decSBarry Smith extern PetscErrorCode usermult(Mat, Vec, Vec); 20922920cce0SJacob Faibussowitsch 2093c3339decSBarry Smith MatCreateShell(comm, m, n, M, N, ctx, &A); 2094c3339decSBarry Smith MatShellSetOperation(A, MATOP_MULT, (void(*)(void))usermult); 2095c3339decSBarry Smith .ve 20960b627109SLois Curfman McInnes 2097a62d957aSLois Curfman McInnes Notes: 2098e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 20991c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2100a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 210111a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2102a62d957aSLois Curfman McInnes 210311a5261eSBarry Smith All user-provided functions (except for `MATOP_DESTROY`) should have the same calling 2104deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2105deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2106deebb3c3SLois Curfman McInnes routines, e.g., 2107a62d957aSLois Curfman McInnes $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2108a62d957aSLois Curfman McInnes 21094aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 21104aa34b0aSBarry Smith nonzero on failure. 21114aa34b0aSBarry Smith 2112a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 211311a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 211411a5261eSBarry Smith set by `MatCreateShell()`. 2115a62d957aSLois Curfman McInnes 21162ef1f0ffSBarry Smith Use `MatSetOperation()` to set an operation for any matrix type. For matrix product operations (i.e. `MatMatXXX()`, `MatTransposeMatXXX()` etc) 21172ef1f0ffSBarry Smith use `MatShellSetMatProductOperation()` 2118b77ba244SStefano Zampini 2119fe59aa6dSJacob Faibussowitsch Fortran Notes: 212011a5261eSBarry Smith For `MatCreateVecs()` the user code should check if the input left or right matrix is -1 and in that case not 2121c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2122501d9185SBarry Smith 21231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`, `MatShellSetContext()`, `MatSetOperation()`, `MatShellSetManageScalingShifts()`, `MatShellSetMatProductOperation()` 2124e51e0e81SBarry Smith @*/ 2125d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellSetOperation(Mat mat, MatOperation op, void (*g)(void)) 2126d71ae5a4SJacob Faibussowitsch { 21273a40ed3dSBarry Smith PetscFunctionBegin; 21280700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2129cac4c232SBarry Smith PetscTryMethod(mat, "MatShellSetOperation_C", (Mat, MatOperation, void (*)(void)), (mat, op, g)); 21303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2131e51e0e81SBarry Smith } 2132f0479e8cSBarry Smith 2133d4bb536fSBarry Smith /*@C 213411a5261eSBarry Smith MatShellGetOperation - Gets a matrix function for a `MATSHELL` shell matrix. 2135d4bb536fSBarry Smith 2136c7fcc2eaSBarry Smith Not Collective 2137c7fcc2eaSBarry Smith 2138d4bb536fSBarry Smith Input Parameters: 213911a5261eSBarry Smith + mat - the `MATSHELL` shell matrix 2140c7fcc2eaSBarry Smith - op - the name of the operation 2141d4bb536fSBarry Smith 2142d4bb536fSBarry Smith Output Parameter: 2143789d8953SBarry Smith . g - the function that provides the operation. 2144d4bb536fSBarry Smith 214515091d37SBarry Smith Level: advanced 214615091d37SBarry Smith 214727430b45SBarry Smith Notes: 2148e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2149d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2150d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 215111a5261eSBarry Smith user interface routine (e.g., `MatMult()` -> `MATOP_MULT`). 2152d4bb536fSBarry Smith 2153d4bb536fSBarry Smith All user-provided functions have the same calling 2154d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2155d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2156d4bb536fSBarry Smith routines, e.g., 2157d4bb536fSBarry Smith $ MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec) 2158d4bb536fSBarry Smith 2159d4bb536fSBarry Smith Within each user-defined routine, the user should call 216011a5261eSBarry Smith `MatShellGetContext()` to obtain the user-defined context that was 216111a5261eSBarry Smith set by `MatCreateShell()`. 2162d4bb536fSBarry Smith 21631cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellSetOperation()`, `MatShellSetContext()` 2164d4bb536fSBarry Smith @*/ 2165d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShellGetOperation(Mat mat, MatOperation op, void (**g)(void)) 2166d71ae5a4SJacob Faibussowitsch { 21673a40ed3dSBarry Smith PetscFunctionBegin; 21680700a824SBarry Smith PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 2169cac4c232SBarry Smith PetscUseMethod(mat, "MatShellGetOperation_C", (Mat, MatOperation, void (**)(void)), (mat, op, g)); 21703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2171d4bb536fSBarry Smith } 2172b77ba244SStefano Zampini 2173b77ba244SStefano Zampini /*@ 217411a5261eSBarry Smith MatIsShell - Inquires if a matrix is derived from `MATSHELL` 2175b77ba244SStefano Zampini 2176b77ba244SStefano Zampini Input Parameter: 2177b77ba244SStefano Zampini . mat - the matrix 2178b77ba244SStefano Zampini 2179b77ba244SStefano Zampini Output Parameter: 2180b77ba244SStefano Zampini . flg - the boolean value 2181b77ba244SStefano Zampini 2182b77ba244SStefano Zampini Level: developer 2183b77ba244SStefano Zampini 2184fe59aa6dSJacob Faibussowitsch Developer Notes: 21852ef1f0ffSBarry Smith In the future, we should allow the object type name to be changed still using the `MATSHELL` data structure for other matrices 21862ef1f0ffSBarry Smith (i.e. `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` etc) 2187b77ba244SStefano Zampini 21881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATSHELL`, `MATMFFD`, `MatCreateShell()`, `MATTRANSPOSEVIRTUAL`, `MATSCHURCOMPLEMENT` 2189b77ba244SStefano Zampini @*/ 2190d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2191d71ae5a4SJacob Faibussowitsch { 2192b77ba244SStefano Zampini PetscFunctionBegin; 2193b77ba244SStefano Zampini PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 21944f572ea9SToby Isaac PetscAssertPointer(flg, 2); 2195b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 21963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2197b77ba244SStefano Zampini } 2198