1be1d678aSKris Buschelman 2e51e0e81SBarry Smith /* 320563c6bSBarry Smith This provides a simple shell for Fortran (and C programmers) to 420563c6bSBarry Smith create a very simple matrix class for use with KSP without coding 5ed3cc1f0SBarry Smith much of anything. 6e51e0e81SBarry Smith */ 7e51e0e81SBarry Smith 8af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 945960306SStefano Zampini #include <petsc/private/vecimpl.h> 10e51e0e81SBarry Smith 1128f357e3SAlex Fikl struct _MatShellOps { 12976e8c5aSLisandro Dalcin /* 3 */ PetscErrorCode (*mult)(Mat,Vec,Vec); 13976e8c5aSLisandro Dalcin /* 5 */ PetscErrorCode (*multtranspose)(Mat,Vec,Vec); 14976e8c5aSLisandro Dalcin /* 17 */ PetscErrorCode (*getdiagonal)(Mat,Vec); 15976e8c5aSLisandro Dalcin /* 43 */ PetscErrorCode (*copy)(Mat,Mat,MatStructure); 16976e8c5aSLisandro Dalcin /* 60 */ PetscErrorCode (*destroy)(Mat); 1728f357e3SAlex Fikl }; 1828f357e3SAlex Fikl 19b77ba244SStefano Zampini struct _n_MatShellMatFunctionList { 20b77ba244SStefano Zampini PetscErrorCode (*symbolic)(Mat,Mat,Mat,void**); 21b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat,Mat,Mat,void*); 22b77ba244SStefano Zampini PetscErrorCode (*destroy)(void*); 23b77ba244SStefano Zampini MatProductType ptype; 24b77ba244SStefano Zampini char *composedname; /* string to identify routine with double dispatch */ 25b77ba244SStefano Zampini char *resultname; /* result matrix type */ 26b77ba244SStefano Zampini 27b77ba244SStefano Zampini struct _n_MatShellMatFunctionList *next; 28b77ba244SStefano Zampini }; 29b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList; 30b77ba244SStefano Zampini 3128f357e3SAlex Fikl typedef struct { 3228f357e3SAlex Fikl struct _MatShellOps ops[1]; 332205254eSKarl Rupp 34b77ba244SStefano Zampini /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 35b77ba244SStefano Zampini PetscBool managescalingshifts; 36b77ba244SStefano Zampini 37b77ba244SStefano Zampini /* support for MatScale, MatShift and MatMultAdd */ 38ef66eb69SBarry Smith PetscScalar vscale,vshift; 398fe8eb27SJed Brown Vec dshift; 408fe8eb27SJed Brown Vec left,right; 418fe8eb27SJed Brown Vec left_work,right_work; 425edf6516SJed Brown Vec left_add_work,right_add_work; 43b77ba244SStefano Zampini 44ef5c7bd2SStefano Zampini /* support for MatAXPY */ 459f137db4SBarry Smith Mat axpy; 469f137db4SBarry Smith PetscScalar axpy_vscale; 47b77ba244SStefano Zampini Vec axpy_left,axpy_right; 48ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 49b77ba244SStefano Zampini 5045960306SStefano Zampini /* support for ZeroRows/Columns operations */ 5145960306SStefano Zampini IS zrows; 5245960306SStefano Zampini IS zcols; 5345960306SStefano Zampini Vec zvals; 5445960306SStefano Zampini Vec zvals_w; 5545960306SStefano Zampini VecScatter zvals_sct_r; 5645960306SStefano Zampini VecScatter zvals_sct_c; 57b77ba244SStefano Zampini 58b77ba244SStefano Zampini /* MatMat operations */ 59b77ba244SStefano Zampini MatShellMatFunctionList matmat; 60b77ba244SStefano Zampini 61b77ba244SStefano Zampini /* user defined context */ 6220563c6bSBarry Smith void *ctx; 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 */ 6945960306SStefano Zampini static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx) 7045960306SStefano Zampini { 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) { 8245960306SStefano Zampini if (!shell->right_work) { 839566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(A,&shell->right_work,NULL)); 8445960306SStefano Zampini } 859566063dSJacob Faibussowitsch PetscCall(VecCopy(x,shell->right_work)); 869566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->right_work,shell->zcols,0.0)); 8745960306SStefano Zampini *xx = shell->right_work; 8845960306SStefano Zampini } 8945960306SStefano Zampini PetscFunctionReturn(0); 9045960306SStefano Zampini } 9145960306SStefano Zampini 9245960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */ 9345960306SStefano Zampini static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x) 9445960306SStefano Zampini { 9545960306SStefano Zampini Mat_Shell *shell = (Mat_Shell*)A->data; 9645960306SStefano Zampini 9745960306SStefano Zampini PetscFunctionBegin; 9845960306SStefano Zampini if (shell->zrows) { 999566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE)); 1009566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE)); 10145960306SStefano Zampini } 10245960306SStefano Zampini PetscFunctionReturn(0); 10345960306SStefano Zampini } 10445960306SStefano Zampini 10545960306SStefano Zampini /* 10645960306SStefano Zampini Store and scale values on zeroed rows 10745960306SStefano Zampini xx = [x_1, 0], 0 on zeroed rows 10845960306SStefano Zampini */ 10945960306SStefano Zampini static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx) 11045960306SStefano Zampini { 11145960306SStefano Zampini Mat_Shell *shell = (Mat_Shell*)A->data; 11245960306SStefano Zampini 11345960306SStefano Zampini PetscFunctionBegin; 11445960306SStefano Zampini *xx = NULL; 11545960306SStefano Zampini if (!shell->zrows) { 11645960306SStefano Zampini *xx = x; 11745960306SStefano Zampini } else { 11845960306SStefano Zampini if (!shell->left_work) { 1199566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(A,NULL,&shell->left_work)); 12045960306SStefano Zampini } 1219566063dSJacob Faibussowitsch PetscCall(VecCopy(x,shell->left_work)); 1229566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w,0.0)); 1239566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE)); 1249566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE)); 1259566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD)); 1269566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD)); 1279566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals)); 12845960306SStefano Zampini *xx = shell->left_work; 12945960306SStefano Zampini } 13045960306SStefano Zampini PetscFunctionReturn(0); 13145960306SStefano Zampini } 13245960306SStefano Zampini 13345960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */ 13445960306SStefano Zampini static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x) 13545960306SStefano Zampini { 13645960306SStefano Zampini Mat_Shell *shell = (Mat_Shell*)A->data; 13745960306SStefano Zampini 13845960306SStefano Zampini PetscFunctionBegin; 13945960306SStefano Zampini if (shell->zcols) { 1409566063dSJacob Faibussowitsch PetscCall(VecISSet(x,shell->zcols,0.0)); 14145960306SStefano Zampini } 14245960306SStefano Zampini if (shell->zrows) { 1439566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE)); 1449566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE)); 14545960306SStefano Zampini } 14645960306SStefano Zampini PetscFunctionReturn(0); 14745960306SStefano Zampini } 14845960306SStefano Zampini 1498fe8eb27SJed Brown /* 1500c0fd78eSBarry Smith xx = diag(left)*x 1518fe8eb27SJed Brown */ 1528fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx) 1538fe8eb27SJed Brown { 1548fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 1558fe8eb27SJed Brown 1568fe8eb27SJed Brown PetscFunctionBegin; 1570298fd71SBarry Smith *xx = NULL; 1588fe8eb27SJed Brown if (!shell->left) { 1598fe8eb27SJed Brown *xx = x; 1608fe8eb27SJed Brown } else { 1619566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(VecDuplicate(shell->left,&shell->left_work)); 1629566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work,x,shell->left)); 1638fe8eb27SJed Brown *xx = shell->left_work; 1648fe8eb27SJed Brown } 1658fe8eb27SJed Brown PetscFunctionReturn(0); 1668fe8eb27SJed Brown } 1678fe8eb27SJed Brown 1680c0fd78eSBarry Smith /* 1690c0fd78eSBarry Smith xx = diag(right)*x 1700c0fd78eSBarry Smith */ 1718fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx) 1728fe8eb27SJed Brown { 1738fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 1748fe8eb27SJed Brown 1758fe8eb27SJed Brown PetscFunctionBegin; 1760298fd71SBarry Smith *xx = NULL; 1778fe8eb27SJed Brown if (!shell->right) { 1788fe8eb27SJed Brown *xx = x; 1798fe8eb27SJed Brown } else { 1809566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->right,&shell->right_work)); 1819566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work,x,shell->right)); 1828fe8eb27SJed Brown *xx = shell->right_work; 1838fe8eb27SJed Brown } 1848fe8eb27SJed Brown PetscFunctionReturn(0); 1858fe8eb27SJed Brown } 1868fe8eb27SJed Brown 1870c0fd78eSBarry Smith /* 1880c0fd78eSBarry Smith x = diag(left)*x 1890c0fd78eSBarry Smith */ 1908fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x) 1918fe8eb27SJed Brown { 1928fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 1938fe8eb27SJed Brown 1948fe8eb27SJed Brown PetscFunctionBegin; 1959566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(x,x,shell->left)); 1968fe8eb27SJed Brown PetscFunctionReturn(0); 1978fe8eb27SJed Brown } 1988fe8eb27SJed Brown 1990c0fd78eSBarry Smith /* 2000c0fd78eSBarry Smith x = diag(right)*x 2010c0fd78eSBarry Smith */ 2028fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x) 2038fe8eb27SJed Brown { 2048fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 2058fe8eb27SJed Brown 2068fe8eb27SJed Brown PetscFunctionBegin; 2079566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(x,x,shell->right)); 2088fe8eb27SJed Brown PetscFunctionReturn(0); 2098fe8eb27SJed Brown } 2108fe8eb27SJed Brown 2110c0fd78eSBarry Smith /* 2120c0fd78eSBarry Smith Y = vscale*Y + diag(dshift)*X + vshift*X 2130c0fd78eSBarry Smith 2140c0fd78eSBarry Smith On input Y already contains A*x 2150c0fd78eSBarry Smith */ 2168fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y) 2178fe8eb27SJed Brown { 2188fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 2198fe8eb27SJed Brown 2208fe8eb27SJed Brown PetscFunctionBegin; 2218fe8eb27SJed Brown if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 2228fe8eb27SJed Brown PetscInt i,m; 2238fe8eb27SJed Brown const PetscScalar *x,*d; 2248fe8eb27SJed Brown PetscScalar *y; 2259566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X,&m)); 2269566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(shell->dshift,&d)); 2279566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X,&x)); 2289566063dSJacob Faibussowitsch PetscCall(VecGetArray(Y,&y)); 2298fe8eb27SJed Brown for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i]; 2309566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(shell->dshift,&d)); 2319566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X,&x)); 2329566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Y,&y)); 2330c0fd78eSBarry Smith } else { 2349566063dSJacob Faibussowitsch PetscCall(VecScale(Y,shell->vscale)); 2358fe8eb27SJed Brown } 2369566063dSJacob Faibussowitsch if (shell->vshift != 0.0) PetscCall(VecAXPY(Y,shell->vshift,X)); /* if test is for non-square matrices */ 2378fe8eb27SJed Brown PetscFunctionReturn(0); 2388fe8eb27SJed Brown } 239e51e0e81SBarry Smith 240789d8953SBarry Smith PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx) 241789d8953SBarry Smith { 242789d8953SBarry Smith PetscFunctionBegin; 243789d8953SBarry Smith *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx; 244789d8953SBarry Smith PetscFunctionReturn(0); 245789d8953SBarry Smith } 246789d8953SBarry Smith 2479d225801SJed Brown /*@ 248a62d957aSLois Curfman McInnes MatShellGetContext - Returns the user-provided context associated with a shell matrix. 249b4fd4287SBarry Smith 250c7fcc2eaSBarry Smith Not Collective 251c7fcc2eaSBarry Smith 252b4fd4287SBarry Smith Input Parameter: 253b4fd4287SBarry Smith . mat - the matrix, should have been created with MatCreateShell() 254b4fd4287SBarry Smith 255b4fd4287SBarry Smith Output Parameter: 256b4fd4287SBarry Smith . ctx - the user provided context 257b4fd4287SBarry Smith 25815091d37SBarry Smith Level: advanced 25915091d37SBarry Smith 26095452b02SPatrick Sanan Fortran Notes: 26195452b02SPatrick Sanan To use this from Fortran you must write a Fortran interface definition for this 262daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 263a62d957aSLois Curfman McInnes 264ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 2650bc0a719SBarry Smith @*/ 2668fe8eb27SJed Brown PetscErrorCode MatShellGetContext(Mat mat,void *ctx) 267b4fd4287SBarry Smith { 2683a40ed3dSBarry Smith PetscFunctionBegin; 2690700a824SBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2704482741eSBarry Smith PetscValidPointer(ctx,2); 271*cac4c232SBarry Smith PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx)); 2723a40ed3dSBarry Smith PetscFunctionReturn(0); 273b4fd4287SBarry Smith } 274b4fd4287SBarry Smith 27545960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc) 27645960306SStefano Zampini { 27745960306SStefano Zampini Mat_Shell *shell = (Mat_Shell*)mat->data; 27845960306SStefano Zampini Vec x = NULL,b = NULL; 27945960306SStefano Zampini IS is1, is2; 28045960306SStefano Zampini const PetscInt *ridxs; 28145960306SStefano Zampini PetscInt *idxs,*gidxs; 28245960306SStefano Zampini PetscInt cum,rst,cst,i; 28345960306SStefano Zampini 28445960306SStefano Zampini PetscFunctionBegin; 28545960306SStefano Zampini if (!shell->zvals) { 2869566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat,NULL,&shell->zvals)); 28745960306SStefano Zampini } 28845960306SStefano Zampini if (!shell->zvals_w) { 2899566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->zvals,&shell->zvals_w)); 29045960306SStefano Zampini } 2919566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(mat,&rst,NULL)); 2929566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(mat,&cst,NULL)); 29345960306SStefano Zampini 29445960306SStefano Zampini /* Expand/create index set of zeroed rows */ 2959566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr,&idxs)); 29645960306SStefano Zampini for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst; 2979566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1)); 2989566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 2999566063dSJacob Faibussowitsch PetscCall(VecISSet(shell->zvals,is1,diag)); 30045960306SStefano Zampini if (shell->zrows) { 3019566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zrows,is1,&is2)); 3029566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 3039566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 30445960306SStefano Zampini shell->zrows = is2; 30545960306SStefano Zampini } else shell->zrows = is1; 30645960306SStefano Zampini 30745960306SStefano Zampini /* Create scatters for diagonal values communications */ 3089566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 3099566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 31045960306SStefano Zampini 31145960306SStefano Zampini /* row scatter: from/to left vector */ 3129566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat,&x,&b)); 3139566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r)); 31445960306SStefano Zampini 31545960306SStefano Zampini /* col scatter: from right vector to left vector */ 3169566063dSJacob Faibussowitsch PetscCall(ISGetIndices(shell->zrows,&ridxs)); 3179566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(shell->zrows,&nr)); 3189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr,&gidxs)); 31945960306SStefano Zampini for (i = 0, cum = 0; i < nr; i++) { 32045960306SStefano Zampini if (ridxs[i] >= mat->cmap->N) continue; 32145960306SStefano Zampini gidxs[cum] = ridxs[i]; 32245960306SStefano Zampini cum++; 32345960306SStefano Zampini } 3249566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1)); 3259566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c)); 3269566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 3279566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 3289566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b)); 32945960306SStefano Zampini 33045960306SStefano Zampini /* Expand/create index set of zeroed columns */ 33145960306SStefano Zampini if (rc) { 3329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc,&idxs)); 33345960306SStefano Zampini for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst; 3349566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1)); 3359566063dSJacob Faibussowitsch PetscCall(ISSort(is1)); 33645960306SStefano Zampini if (shell->zcols) { 3379566063dSJacob Faibussowitsch PetscCall(ISSum(shell->zcols,is1,&is2)); 3389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 3399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is1)); 34045960306SStefano Zampini shell->zcols = is2; 34145960306SStefano Zampini } else shell->zcols = is1; 34245960306SStefano Zampini } 34345960306SStefano Zampini PetscFunctionReturn(0); 34445960306SStefano Zampini } 34545960306SStefano Zampini 34645960306SStefano Zampini static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 34745960306SStefano Zampini { 348ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell*)mat->data; 34945960306SStefano Zampini PetscInt nr, *lrows; 35045960306SStefano Zampini 35145960306SStefano Zampini PetscFunctionBegin; 35245960306SStefano Zampini if (x && b) { 35345960306SStefano Zampini Vec xt; 35445960306SStefano Zampini PetscScalar *vals; 35545960306SStefano Zampini PetscInt *gcols,i,st,nl,nc; 35645960306SStefano Zampini 3579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n,&gcols)); 35845960306SStefano Zampini for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i]; 35945960306SStefano Zampini 3609566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat,&xt,NULL)); 3619566063dSJacob Faibussowitsch PetscCall(VecCopy(x,xt)); 3629566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nc,&vals)); 3639566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */ 3649566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 3659566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 3669566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 3679566063dSJacob Faibussowitsch PetscCall(VecAYPX(xt,-1.0,x)); /* xt = [0, x2] */ 36845960306SStefano Zampini 3699566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt,&st,NULL)); 3709566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt,&nl)); 3719566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt,&vals)); 37245960306SStefano Zampini for (i = 0; i < nl; i++) { 37345960306SStefano Zampini PetscInt g = i + st; 37445960306SStefano Zampini if (g > mat->rmap->N) continue; 37545960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 3769566063dSJacob Faibussowitsch PetscCall(VecSetValue(b,g,diag*vals[i],INSERT_VALUES)); 37745960306SStefano Zampini } 3789566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt,&vals)); 3799566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 3809566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1, x2 * diag] */ 3819566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 3829566063dSJacob Faibussowitsch PetscCall(PetscFree(gcols)); 38345960306SStefano Zampini } 3849566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL)); 3859566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE)); 386ef5c7bd2SStefano Zampini if (shell->axpy) { 3879566063dSJacob Faibussowitsch PetscCall(MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL)); 388ef5c7bd2SStefano Zampini } 3899566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 39045960306SStefano Zampini PetscFunctionReturn(0); 39145960306SStefano Zampini } 39245960306SStefano Zampini 39345960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b) 39445960306SStefano Zampini { 395ef5c7bd2SStefano Zampini Mat_Shell *shell = (Mat_Shell*)mat->data; 39645960306SStefano Zampini PetscInt *lrows, *lcols; 39745960306SStefano Zampini PetscInt nr, nc; 39845960306SStefano Zampini PetscBool congruent; 39945960306SStefano Zampini 40045960306SStefano Zampini PetscFunctionBegin; 40145960306SStefano Zampini if (x && b) { 40245960306SStefano Zampini Vec xt, bt; 40345960306SStefano Zampini PetscScalar *vals; 40445960306SStefano Zampini PetscInt *grows,*gcols,i,st,nl; 40545960306SStefano Zampini 4069566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n,&grows,n,&gcols)); 40745960306SStefano Zampini for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i]; 40845960306SStefano Zampini for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i]; 4099566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(n,&vals)); 41045960306SStefano Zampini 4119566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat,&xt,&bt)); 4129566063dSJacob Faibussowitsch PetscCall(VecCopy(x,xt)); 4139566063dSJacob Faibussowitsch PetscCall(VecSetValues(xt,nc,gcols,vals,INSERT_VALUES)); /* xt = [x1, 0] */ 4149566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(xt)); 4159566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(xt)); 4169566063dSJacob Faibussowitsch PetscCall(VecAXPY(xt,-1.0,x)); /* xt = [0, -x2] */ 4179566063dSJacob Faibussowitsch PetscCall(MatMult(mat,xt,bt)); /* bt = [-A12*x2,-A22*x2] */ 4189566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* bt = [-A12*x2,0] */ 4199566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4209566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4219566063dSJacob Faibussowitsch PetscCall(VecAXPY(b,1.0,bt)); /* b = [b1 - A12*x2, b2] */ 4229566063dSJacob Faibussowitsch PetscCall(VecSetValues(bt,nr,grows,vals,INSERT_VALUES)); /* b = [b1 - A12*x2, 0] */ 4239566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(bt)); 4249566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(bt)); 4259566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 42645960306SStefano Zampini 4279566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(xt,&st,NULL)); 4289566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(xt,&nl)); 4299566063dSJacob Faibussowitsch PetscCall(VecGetArray(xt,&vals)); 43045960306SStefano Zampini for (i = 0; i < nl; i++) { 43145960306SStefano Zampini PetscInt g = i + st; 43245960306SStefano Zampini if (g > mat->rmap->N) continue; 43345960306SStefano Zampini if (PetscAbsScalar(vals[i]) == 0.0) continue; 4349566063dSJacob Faibussowitsch PetscCall(VecSetValue(b,g,-diag*vals[i],INSERT_VALUES)); 43545960306SStefano Zampini } 4369566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(xt,&vals)); 4379566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(b)); 4389566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(b)); /* b = [b1 - A12*x2, x2 * diag] */ 4399566063dSJacob Faibussowitsch PetscCall(VecDestroy(&xt)); 4409566063dSJacob Faibussowitsch PetscCall(VecDestroy(&bt)); 4419566063dSJacob Faibussowitsch PetscCall(PetscFree2(grows,gcols)); 44245960306SStefano Zampini } 4439566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL)); 4449566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(mat,&congruent)); 44545960306SStefano Zampini if (congruent) { 44645960306SStefano Zampini nc = nr; 44745960306SStefano Zampini lcols = lrows; 44845960306SStefano Zampini } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */ 44945960306SStefano Zampini PetscInt i,nt,*t; 45045960306SStefano Zampini 4519566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n,&t)); 45245960306SStefano Zampini for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i]; 4539566063dSJacob Faibussowitsch PetscCall(PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL)); 4549566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 45545960306SStefano Zampini } 4569566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE)); 45745960306SStefano Zampini if (!congruent) { 4589566063dSJacob Faibussowitsch PetscCall(PetscFree(lcols)); 45945960306SStefano Zampini } 4609566063dSJacob Faibussowitsch PetscCall(PetscFree(lrows)); 461ef5c7bd2SStefano Zampini if (shell->axpy) { 4629566063dSJacob Faibussowitsch PetscCall(MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL)); 463ef5c7bd2SStefano Zampini } 46445960306SStefano Zampini PetscFunctionReturn(0); 46545960306SStefano Zampini } 46645960306SStefano Zampini 467dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat) 468e51e0e81SBarry Smith { 469bf0cc555SLisandro Dalcin Mat_Shell *shell = (Mat_Shell*)mat->data; 470b77ba244SStefano Zampini MatShellMatFunctionList matmat; 471ed3cc1f0SBarry Smith 4723a40ed3dSBarry Smith PetscFunctionBegin; 47328f357e3SAlex Fikl if (shell->ops->destroy) { 4749566063dSJacob Faibussowitsch PetscCall((*shell->ops->destroy)(mat)); 475bf0cc555SLisandro Dalcin } 4769566063dSJacob Faibussowitsch PetscCall(PetscMemzero(shell->ops,sizeof(struct _MatShellOps))); 4779566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 4789566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 4799566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 4809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_work)); 4819566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_work)); 4829566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left_add_work)); 4839566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right_add_work)); 4849566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 4859566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 4869566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 4879566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals_w)); 4889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->zvals)); 4899566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 4909566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 4919566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 4929566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 493b77ba244SStefano Zampini 494b77ba244SStefano Zampini matmat = shell->matmat; 495b77ba244SStefano Zampini while (matmat) { 496b77ba244SStefano Zampini MatShellMatFunctionList next = matmat->next; 497b77ba244SStefano Zampini 4989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL)); 4999566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 5009566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 5019566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat)); 502b77ba244SStefano Zampini matmat = next; 503b77ba244SStefano Zampini } 5049566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL)); 5059566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL)); 5069566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL)); 5079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL)); 5089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL)); 5099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL)); 5109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL)); 5119566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->data)); 512b77ba244SStefano Zampini PetscFunctionReturn(0); 513b77ba244SStefano Zampini } 514b77ba244SStefano Zampini 515b77ba244SStefano Zampini typedef struct { 516b77ba244SStefano Zampini PetscErrorCode (*numeric)(Mat,Mat,Mat,void*); 517b77ba244SStefano Zampini PetscErrorCode (*destroy)(void*); 518b77ba244SStefano Zampini void *userdata; 519b77ba244SStefano Zampini Mat B; 520b77ba244SStefano Zampini Mat Bt; 521b77ba244SStefano Zampini Mat axpy; 522b77ba244SStefano Zampini } MatMatDataShell; 523b77ba244SStefano Zampini 524b77ba244SStefano Zampini static PetscErrorCode DestroyMatMatDataShell(void *data) 525b77ba244SStefano Zampini { 526b77ba244SStefano Zampini MatMatDataShell *mmdata = (MatMatDataShell *)data; 527b77ba244SStefano Zampini 528b77ba244SStefano Zampini PetscFunctionBegin; 529b77ba244SStefano Zampini if (mmdata->destroy) { 5309566063dSJacob Faibussowitsch PetscCall((*mmdata->destroy)(mmdata->userdata)); 531b77ba244SStefano Zampini } 5329566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->B)); 5339566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->Bt)); 5349566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mmdata->axpy)); 5359566063dSJacob Faibussowitsch PetscCall(PetscFree(mmdata)); 536b77ba244SStefano Zampini PetscFunctionReturn(0); 537b77ba244SStefano Zampini } 538b77ba244SStefano Zampini 539b77ba244SStefano Zampini static PetscErrorCode MatProductNumeric_Shell_X(Mat D) 540b77ba244SStefano Zampini { 541b77ba244SStefano Zampini Mat_Product *product; 542b77ba244SStefano Zampini Mat A, B; 543b77ba244SStefano Zampini MatMatDataShell *mdata; 544b77ba244SStefano Zampini PetscScalar zero = 0.0; 545b77ba244SStefano Zampini 546b77ba244SStefano Zampini PetscFunctionBegin; 547b77ba244SStefano Zampini MatCheckProduct(D,1); 548b77ba244SStefano Zampini product = D->product; 54928b400f6SJacob Faibussowitsch PetscCheck(product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty"); 550b77ba244SStefano Zampini A = product->A; 551b77ba244SStefano Zampini B = product->B; 552b77ba244SStefano Zampini mdata = (MatMatDataShell*)product->data; 553b77ba244SStefano Zampini if (mdata->numeric) { 554b77ba244SStefano Zampini Mat_Shell *shell = (Mat_Shell*)A->data; 555b77ba244SStefano Zampini PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic; 556b77ba244SStefano Zampini PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric; 557b77ba244SStefano Zampini PetscBool useBmdata = PETSC_FALSE, newB = PETSC_TRUE; 558b77ba244SStefano Zampini 559b77ba244SStefano Zampini if (shell->managescalingshifts) { 5602c71b3e2SJacob Faibussowitsch PetscCheckFalse(shell->zcols || shell->zrows,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns"); 561b77ba244SStefano Zampini if (shell->right || shell->left) { 562b77ba244SStefano Zampini useBmdata = PETSC_TRUE; 563b77ba244SStefano Zampini if (!mdata->B) { 5649566063dSJacob Faibussowitsch PetscCall(MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B)); 565b77ba244SStefano Zampini } else { 566b77ba244SStefano Zampini newB = PETSC_FALSE; 567b77ba244SStefano Zampini } 5689566063dSJacob Faibussowitsch PetscCall(MatCopy(B,mdata->B,SAME_NONZERO_PATTERN)); 569b77ba244SStefano Zampini } 570b77ba244SStefano Zampini switch (product->type) { 571b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 572b77ba244SStefano Zampini if (shell->right) { 5739566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL)); 574b77ba244SStefano Zampini } 575b77ba244SStefano Zampini break; 576b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 577b77ba244SStefano Zampini if (shell->left) { 5789566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,shell->left,NULL)); 579b77ba244SStefano Zampini } 580b77ba244SStefano Zampini break; 581b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 582b77ba244SStefano Zampini if (shell->right) { 5839566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right)); 584b77ba244SStefano Zampini } 585b77ba244SStefano Zampini break; 586b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 587b77ba244SStefano Zampini if (shell->right && shell->left) { 588b77ba244SStefano Zampini PetscBool flg; 589b77ba244SStefano Zampini 5909566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right,shell->left,&flg)); 59128b400f6SJacob Faibussowitsch 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,((PetscObject)B)->type_name); 592b77ba244SStefano Zampini } 593b77ba244SStefano Zampini if (shell->right) { 5949566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,NULL,shell->right)); 595b77ba244SStefano Zampini } 596b77ba244SStefano Zampini break; 597b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 598b77ba244SStefano Zampini if (shell->right && shell->left) { 599b77ba244SStefano Zampini PetscBool flg; 600b77ba244SStefano Zampini 6019566063dSJacob Faibussowitsch PetscCall(VecEqual(shell->right,shell->left,&flg)); 60228b400f6SJacob Faibussowitsch 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,((PetscObject)B)->type_name); 603b77ba244SStefano Zampini } 604b77ba244SStefano Zampini if (shell->right) { 6059566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,shell->right,NULL)); 606b77ba244SStefano Zampini } 607b77ba244SStefano Zampini break; 60898921bdaSJacob Faibussowitsch default: 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); 609b77ba244SStefano Zampini } 610b77ba244SStefano Zampini } 611b77ba244SStefano Zampini /* allow the user to call MatMat operations on D */ 612b77ba244SStefano Zampini D->product = NULL; 613b77ba244SStefano Zampini D->ops->productsymbolic = NULL; 614b77ba244SStefano Zampini D->ops->productnumeric = NULL; 615b77ba244SStefano Zampini 6169566063dSJacob Faibussowitsch PetscCall((*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata)); 617b77ba244SStefano Zampini 618b77ba244SStefano Zampini /* clear any leftover user data and restore D pointers */ 6199566063dSJacob Faibussowitsch PetscCall(MatProductClear(D)); 620b77ba244SStefano Zampini D->ops->productsymbolic = stashsym; 621b77ba244SStefano Zampini D->ops->productnumeric = stashnum; 622b77ba244SStefano Zampini D->product = product; 623b77ba244SStefano Zampini 624b77ba244SStefano Zampini if (shell->managescalingshifts) { 6259566063dSJacob Faibussowitsch PetscCall(MatScale(D,shell->vscale)); 626b77ba244SStefano Zampini switch (product->type) { 627b77ba244SStefano Zampini case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */ 628b77ba244SStefano Zampini case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */ 629b77ba244SStefano Zampini if (shell->left) { 6309566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D,shell->left,NULL)); 631b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 6329566063dSJacob Faibussowitsch if (!shell->left_work) PetscCall(MatCreateVecs(A,NULL,&shell->left_work)); 633b77ba244SStefano Zampini if (shell->dshift) { 6349566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift,shell->left_work)); 6359566063dSJacob Faibussowitsch PetscCall(VecShift(shell->left_work,shell->vshift)); 6369566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left_work,shell->left_work,shell->left)); 637b77ba244SStefano Zampini } else { 6389566063dSJacob Faibussowitsch PetscCall(VecSet(shell->left_work,shell->vshift)); 639b77ba244SStefano Zampini } 640b77ba244SStefano Zampini if (product->type == MATPRODUCT_ABt) { 641b77ba244SStefano Zampini MatReuse reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 642b77ba244SStefano Zampini MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN; 643b77ba244SStefano Zampini 6449566063dSJacob Faibussowitsch PetscCall(MatTranspose(mdata->B,reuse,&mdata->Bt)); 6459566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->Bt,shell->left_work,NULL)); 6469566063dSJacob Faibussowitsch PetscCall(MatAXPY(D,1.0,mdata->Bt,str)); 647b77ba244SStefano Zampini } else { 648b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 649b77ba244SStefano Zampini 6509566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,shell->left_work,NULL)); 6519566063dSJacob Faibussowitsch PetscCall(MatAXPY(D,1.0,mdata->B,str)); 652b77ba244SStefano Zampini } 653b77ba244SStefano Zampini } 654b77ba244SStefano Zampini } 655b77ba244SStefano Zampini break; 656b77ba244SStefano Zampini case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */ 657b77ba244SStefano Zampini if (shell->right) { 6589566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(D,shell->right,NULL)); 659b77ba244SStefano Zampini if (shell->dshift || shell->vshift != zero) { 660b77ba244SStefano Zampini MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN; 661b77ba244SStefano Zampini 6629566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(MatCreateVecs(A,&shell->right_work,NULL)); 663b77ba244SStefano Zampini if (shell->dshift) { 6649566063dSJacob Faibussowitsch PetscCall(VecCopy(shell->dshift,shell->right_work)); 6659566063dSJacob Faibussowitsch PetscCall(VecShift(shell->right_work,shell->vshift)); 6669566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right_work,shell->right_work,shell->right)); 667b77ba244SStefano Zampini } else { 6689566063dSJacob Faibussowitsch PetscCall(VecSet(shell->right_work,shell->vshift)); 669b77ba244SStefano Zampini } 6709566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(mdata->B,shell->right_work,NULL)); 6719566063dSJacob Faibussowitsch PetscCall(MatAXPY(D,1.0,mdata->B,str)); 672b77ba244SStefano Zampini } 673b77ba244SStefano Zampini } 674b77ba244SStefano Zampini break; 675b77ba244SStefano Zampini case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */ 676b77ba244SStefano Zampini case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */ 6772c71b3e2SJacob Faibussowitsch PetscCheckFalse(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,((PetscObject)B)->type_name); 678b77ba244SStefano Zampini break; 67998921bdaSJacob Faibussowitsch default: 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); 680b77ba244SStefano Zampini } 681b77ba244SStefano Zampini if (shell->axpy && shell->axpy_vscale != zero) { 682b77ba244SStefano Zampini Mat X; 683b77ba244SStefano Zampini PetscObjectState axpy_state; 684b77ba244SStefano Zampini MatStructure str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */ 685b77ba244SStefano Zampini 6869566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy,&X)); 6879566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state)); 6882c71b3e2SJacob Faibussowitsch PetscCheckFalse(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,...)"); 689b77ba244SStefano Zampini if (!mdata->axpy) { 690b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 6919566063dSJacob Faibussowitsch PetscCall(MatProductCreate(shell->axpy,B,NULL,&mdata->axpy)); 6929566063dSJacob Faibussowitsch PetscCall(MatProductSetType(mdata->axpy,product->type)); 6939566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 6949566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 695b77ba244SStefano Zampini } else { /* May be that shell->axpy has changed */ 696b77ba244SStefano Zampini PetscBool flg; 697b77ba244SStefano Zampini 6989566063dSJacob Faibussowitsch PetscCall(MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy)); 6999566063dSJacob Faibussowitsch PetscCall(MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg)); 700b77ba244SStefano Zampini if (!flg) { 701b77ba244SStefano Zampini str = DIFFERENT_NONZERO_PATTERN; 7029566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(mdata->axpy)); 7039566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(mdata->axpy)); 704b77ba244SStefano Zampini } 705b77ba244SStefano Zampini } 7069566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(mdata->axpy)); 7079566063dSJacob Faibussowitsch PetscCall(MatAXPY(D,shell->axpy_vscale,mdata->axpy,str)); 708b77ba244SStefano Zampini } 709b77ba244SStefano Zampini } 710b77ba244SStefano Zampini } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation"); 711b77ba244SStefano Zampini PetscFunctionReturn(0); 712b77ba244SStefano Zampini } 713b77ba244SStefano Zampini 714b77ba244SStefano Zampini static PetscErrorCode MatProductSymbolic_Shell_X(Mat D) 715b77ba244SStefano Zampini { 716b77ba244SStefano Zampini Mat_Product *product; 717b77ba244SStefano Zampini Mat A,B; 718b77ba244SStefano Zampini MatShellMatFunctionList matmat; 719b77ba244SStefano Zampini Mat_Shell *shell; 720b77ba244SStefano Zampini PetscBool flg; 721b77ba244SStefano Zampini char composedname[256]; 722b77ba244SStefano Zampini MatMatDataShell *mdata; 723b77ba244SStefano Zampini 724b77ba244SStefano Zampini PetscFunctionBegin; 725b77ba244SStefano Zampini MatCheckProduct(D,1); 726b77ba244SStefano Zampini product = D->product; 72728b400f6SJacob Faibussowitsch PetscCheck(!product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty"); 728b77ba244SStefano Zampini A = product->A; 729b77ba244SStefano Zampini B = product->B; 730b77ba244SStefano Zampini shell = (Mat_Shell*)A->data; 731b77ba244SStefano Zampini matmat = shell->matmat; 7329566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name)); 733b77ba244SStefano Zampini while (matmat) { 7349566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg)); 735b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 736b77ba244SStefano Zampini if (flg) break; 737b77ba244SStefano Zampini matmat = matmat->next; 738b77ba244SStefano Zampini } 73928b400f6SJacob Faibussowitsch PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]); 740b77ba244SStefano Zampini switch (product->type) { 741b77ba244SStefano Zampini case MATPRODUCT_AB: 7429566063dSJacob Faibussowitsch PetscCall(MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N)); 743b77ba244SStefano Zampini break; 744b77ba244SStefano Zampini case MATPRODUCT_AtB: 7459566063dSJacob Faibussowitsch PetscCall(MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N)); 746b77ba244SStefano Zampini break; 747b77ba244SStefano Zampini case MATPRODUCT_ABt: 7489566063dSJacob Faibussowitsch PetscCall(MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N)); 749b77ba244SStefano Zampini break; 750b77ba244SStefano Zampini case MATPRODUCT_RARt: 7519566063dSJacob Faibussowitsch PetscCall(MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N)); 752b77ba244SStefano Zampini break; 753b77ba244SStefano Zampini case MATPRODUCT_PtAP: 7549566063dSJacob Faibussowitsch PetscCall(MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N)); 755b77ba244SStefano Zampini break; 75698921bdaSJacob Faibussowitsch default: 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); 757b77ba244SStefano Zampini } 758b77ba244SStefano Zampini /* respect users who passed in a matrix for which resultname is the base type */ 759b77ba244SStefano Zampini if (matmat->resultname) { 7609566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg)); 761b77ba244SStefano Zampini if (!flg) { 7629566063dSJacob Faibussowitsch PetscCall(MatSetType(D,matmat->resultname)); 763b77ba244SStefano Zampini } 764b77ba244SStefano Zampini } 765b77ba244SStefano Zampini /* If matrix type was not set or different, we need to reset this pointers */ 766b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 767b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 768b77ba244SStefano Zampini /* attach product data */ 7699566063dSJacob Faibussowitsch PetscCall(PetscNew(&mdata)); 770b77ba244SStefano Zampini mdata->numeric = matmat->numeric; 771b77ba244SStefano Zampini mdata->destroy = matmat->destroy; 772b77ba244SStefano Zampini if (matmat->symbolic) { 7739566063dSJacob Faibussowitsch PetscCall((*matmat->symbolic)(A,B,D,&mdata->userdata)); 774b77ba244SStefano Zampini } else { /* call general setup if symbolic operation not provided */ 7759566063dSJacob Faibussowitsch PetscCall(MatSetUp(D)); 776b77ba244SStefano Zampini } 77728b400f6SJacob Faibussowitsch PetscCheck(D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase"); 77828b400f6SJacob Faibussowitsch PetscCheck(!D->product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase"); 779b77ba244SStefano Zampini D->product->data = mdata; 780b77ba244SStefano Zampini D->product->destroy = DestroyMatMatDataShell; 781b77ba244SStefano Zampini /* Be sure to reset these pointers if the user did something unexpected */ 782b77ba244SStefano Zampini D->ops->productsymbolic = MatProductSymbolic_Shell_X; 783b77ba244SStefano Zampini D->ops->productnumeric = MatProductNumeric_Shell_X; 784b77ba244SStefano Zampini PetscFunctionReturn(0); 785b77ba244SStefano Zampini } 786b77ba244SStefano Zampini 787b77ba244SStefano Zampini static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D) 788b77ba244SStefano Zampini { 789b77ba244SStefano Zampini Mat_Product *product; 790b77ba244SStefano Zampini Mat A,B; 791b77ba244SStefano Zampini MatShellMatFunctionList matmat; 792b77ba244SStefano Zampini Mat_Shell *shell; 793b77ba244SStefano Zampini PetscBool flg; 794b77ba244SStefano Zampini char composedname[256]; 795b77ba244SStefano Zampini 796b77ba244SStefano Zampini PetscFunctionBegin; 797b77ba244SStefano Zampini MatCheckProduct(D,1); 798b77ba244SStefano Zampini product = D->product; 799b77ba244SStefano Zampini A = product->A; 800b77ba244SStefano Zampini B = product->B; 8019566063dSJacob Faibussowitsch PetscCall(MatIsShell(A,&flg)); 802b77ba244SStefano Zampini if (!flg) PetscFunctionReturn(0); 803b77ba244SStefano Zampini shell = (Mat_Shell*)A->data; 804b77ba244SStefano Zampini matmat = shell->matmat; 8059566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name)); 806b77ba244SStefano Zampini while (matmat) { 8079566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname,matmat->composedname,&flg)); 808b77ba244SStefano Zampini flg = (PetscBool)(flg && (matmat->ptype == product->type)); 809b77ba244SStefano Zampini if (flg) break; 810b77ba244SStefano Zampini matmat = matmat->next; 811b77ba244SStefano Zampini } 812b77ba244SStefano Zampini if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; } 8139566063dSJacob Faibussowitsch else PetscCall(PetscInfo(D," symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type])); 814b77ba244SStefano Zampini PetscFunctionReturn(0); 815b77ba244SStefano Zampini } 816b77ba244SStefano Zampini 817b77ba244SStefano Zampini 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) 818b77ba244SStefano Zampini { 819b77ba244SStefano Zampini PetscBool flg; 820b77ba244SStefano Zampini Mat_Shell *shell; 821b77ba244SStefano Zampini MatShellMatFunctionList matmat; 822b77ba244SStefano Zampini 823b77ba244SStefano Zampini PetscFunctionBegin; 82428b400f6SJacob Faibussowitsch PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine"); 82528b400f6SJacob Faibussowitsch PetscCheck(composedname,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name"); 826b77ba244SStefano Zampini 827b77ba244SStefano Zampini /* add product callback */ 828b77ba244SStefano Zampini shell = (Mat_Shell*)A->data; 829b77ba244SStefano Zampini matmat = shell->matmat; 830b77ba244SStefano Zampini if (!matmat) { 8319566063dSJacob Faibussowitsch PetscCall(PetscNew(&shell->matmat)); 832b77ba244SStefano Zampini matmat = shell->matmat; 833b77ba244SStefano Zampini } else { 834b77ba244SStefano Zampini MatShellMatFunctionList entry = matmat; 835b77ba244SStefano Zampini while (entry) { 8369566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(composedname,entry->composedname,&flg)); 837b77ba244SStefano Zampini flg = (PetscBool)(flg && (entry->ptype == ptype)); 838843d480fSStefano Zampini if (flg) goto set; 839b77ba244SStefano Zampini matmat = entry; 840b77ba244SStefano Zampini entry = entry->next; 841b77ba244SStefano Zampini } 8429566063dSJacob Faibussowitsch PetscCall(PetscNew(&matmat->next)); 843b77ba244SStefano Zampini matmat = matmat->next; 844b77ba244SStefano Zampini } 845b77ba244SStefano Zampini 846843d480fSStefano Zampini set: 847b77ba244SStefano Zampini matmat->symbolic = symbolic; 848b77ba244SStefano Zampini matmat->numeric = numeric; 849b77ba244SStefano Zampini matmat->destroy = destroy; 850b77ba244SStefano Zampini matmat->ptype = ptype; 8519566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->composedname)); 8529566063dSJacob Faibussowitsch PetscCall(PetscFree(matmat->resultname)); 8539566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(composedname,&matmat->composedname)); 8549566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(resultname,&matmat->resultname)); 8559566063dSJacob 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")); 8569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X)); 857b77ba244SStefano Zampini PetscFunctionReturn(0); 858b77ba244SStefano Zampini } 859b77ba244SStefano Zampini 860b77ba244SStefano Zampini /*@C 861b77ba244SStefano Zampini MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix. 862b77ba244SStefano Zampini 863b77ba244SStefano Zampini Logically Collective on Mat 864b77ba244SStefano Zampini 865b77ba244SStefano Zampini Input Parameters: 866b77ba244SStefano Zampini + A - the shell matrix 867b77ba244SStefano Zampini . ptype - the product type 868b77ba244SStefano Zampini . symbolic - the function for the symbolic phase (can be NULL) 869b77ba244SStefano Zampini . numeric - the function for the numerical phase 870b77ba244SStefano Zampini . destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL) 871b77ba244SStefano Zampini . Btype - the matrix type for the matrix to be multiplied against 872b77ba244SStefano Zampini - Ctype - the matrix type for the result (can be NULL) 873b77ba244SStefano Zampini 874b77ba244SStefano Zampini Level: advanced 875b77ba244SStefano Zampini 876b77ba244SStefano Zampini Usage: 877b77ba244SStefano Zampini $ extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**); 878b77ba244SStefano Zampini $ extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*); 879b77ba244SStefano Zampini $ extern PetscErrorCode userdestroy(void*); 880b77ba244SStefano Zampini $ MatCreateShell(comm,m,n,M,N,ctx,&A); 881b77ba244SStefano Zampini $ MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE); 882b77ba244SStefano Zampini $ [ create B of type SEQAIJ etc..] 883b77ba244SStefano Zampini $ MatProductCreate(A,B,NULL,&C); 884b77ba244SStefano Zampini $ MatProductSetType(C,MATPRODUCT_AB); 885b77ba244SStefano Zampini $ MatProductSetFromOptions(C); 886b77ba244SStefano Zampini $ MatProductSymbolic(C); -> actually runs the user defined symbolic operation 887b77ba244SStefano Zampini $ MatProductNumeric(C); -> actually runs the user defined numeric operation 888b77ba244SStefano Zampini $ [ use C = A*B ] 889b77ba244SStefano Zampini 890b77ba244SStefano Zampini Notes: 891b77ba244SStefano Zampini MATPRODUCT_ABC is not supported yet. Not supported in Fortran. 892b77ba244SStefano Zampini If the symbolic phase is not specified, MatSetUp() is called on the result matrix that must have its type set if Ctype is NULL. 893b77ba244SStefano Zampini Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback. 894b77ba244SStefano Zampini PETSc will take care of calling the user-defined callbacks. 895b77ba244SStefano Zampini It is allowed to specify the same callbacks for different Btype matrix types. 896b77ba244SStefano Zampini The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence. 897b77ba244SStefano Zampini 898b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatProductType, MatType, MatSetUp() 899b77ba244SStefano Zampini @*/ 900b77ba244SStefano Zampini 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) 901b77ba244SStefano Zampini { 902b77ba244SStefano Zampini PetscFunctionBegin; 903b77ba244SStefano Zampini PetscValidHeaderSpecific(A,MAT_CLASSID,1); 904b77ba244SStefano Zampini PetscValidLogicalCollectiveEnum(A,ptype,2); 9052c71b3e2SJacob Faibussowitsch PetscCheckFalse(ptype == MATPRODUCT_ABC,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]); 90628b400f6SJacob Faibussowitsch PetscCheck(numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4"); 907dadcf809SJacob Faibussowitsch PetscValidCharPointer(Btype,6); 908dadcf809SJacob Faibussowitsch if (Ctype) PetscValidCharPointer(Ctype,7); 909*cac4c232SBarry 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)); 910b77ba244SStefano Zampini PetscFunctionReturn(0); 911b77ba244SStefano Zampini } 912b77ba244SStefano Zampini 913b77ba244SStefano Zampini 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) 914b77ba244SStefano Zampini { 915b77ba244SStefano Zampini PetscBool flg; 916b77ba244SStefano Zampini char composedname[256]; 917b77ba244SStefano Zampini MatRootName Bnames = MatRootNameList, Cnames = MatRootNameList; 918b77ba244SStefano Zampini PetscMPIInt size; 919b77ba244SStefano Zampini 920b77ba244SStefano Zampini PetscFunctionBegin; 921b77ba244SStefano Zampini PetscValidType(A,1); 922b77ba244SStefano Zampini while (Bnames) { /* user passed in the root name */ 9239566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Btype,Bnames->rname,&flg)); 924b77ba244SStefano Zampini if (flg) break; 925b77ba244SStefano Zampini Bnames = Bnames->next; 926b77ba244SStefano Zampini } 927b77ba244SStefano Zampini while (Cnames) { /* user passed in the root name */ 9289566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(Ctype,Cnames->rname,&flg)); 929b77ba244SStefano Zampini if (flg) break; 930b77ba244SStefano Zampini Cnames = Cnames->next; 931b77ba244SStefano Zampini } 9329566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size)); 933b77ba244SStefano Zampini Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype; 934b77ba244SStefano Zampini Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype; 9359566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype)); 9369566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype)); 9373a40ed3dSBarry Smith PetscFunctionReturn(0); 938e51e0e81SBarry Smith } 939e51e0e81SBarry Smith 9407fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str) 9417fabda3fSAlex Fikl { 94228f357e3SAlex Fikl Mat_Shell *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data; 943cb8c8a77SBarry Smith PetscBool matflg; 944b77ba244SStefano Zampini MatShellMatFunctionList matmatA; 9457fabda3fSAlex Fikl 9467fabda3fSAlex Fikl PetscFunctionBegin; 9479566063dSJacob Faibussowitsch PetscCall(MatIsShell(B,&matflg)); 94828b400f6SJacob Faibussowitsch PetscCheck(matflg,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name); 9497fabda3fSAlex Fikl 9509566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps))); 9519566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps))); 9527fabda3fSAlex Fikl 953cb8c8a77SBarry Smith if (shellA->ops->copy) { 9549566063dSJacob Faibussowitsch PetscCall((*shellA->ops->copy)(A,B,str)); 955cb8c8a77SBarry Smith } 9567fabda3fSAlex Fikl shellB->vscale = shellA->vscale; 9577fabda3fSAlex Fikl shellB->vshift = shellA->vshift; 9580c0fd78eSBarry Smith if (shellA->dshift) { 9590c0fd78eSBarry Smith if (!shellB->dshift) { 9609566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->dshift,&shellB->dshift)); 9617fabda3fSAlex Fikl } 9629566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->dshift,shellB->dshift)); 9637fabda3fSAlex Fikl } else { 9649566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->dshift)); 9657fabda3fSAlex Fikl } 9660c0fd78eSBarry Smith if (shellA->left) { 9670c0fd78eSBarry Smith if (!shellB->left) { 9689566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->left,&shellB->left)); 9697fabda3fSAlex Fikl } 9709566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->left,shellB->left)); 9717fabda3fSAlex Fikl } else { 9729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->left)); 9737fabda3fSAlex Fikl } 9740c0fd78eSBarry Smith if (shellA->right) { 9750c0fd78eSBarry Smith if (!shellB->right) { 9769566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->right,&shellB->right)); 9777fabda3fSAlex Fikl } 9789566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->right,shellB->right)); 9797fabda3fSAlex Fikl } else { 9809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shellB->right)); 9817fabda3fSAlex Fikl } 9829566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shellB->axpy)); 983ef5c7bd2SStefano Zampini shellB->axpy_vscale = 0.0; 984ef5c7bd2SStefano Zampini shellB->axpy_state = 0; 98540e381c3SBarry Smith if (shellA->axpy) { 9869566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->axpy)); 98740e381c3SBarry Smith shellB->axpy = shellA->axpy; 98840e381c3SBarry Smith shellB->axpy_vscale = shellA->axpy_vscale; 989ef5c7bd2SStefano Zampini shellB->axpy_state = shellA->axpy_state; 99040e381c3SBarry Smith } 99145960306SStefano Zampini if (shellA->zrows) { 9929566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zrows,&shellB->zrows)); 99345960306SStefano Zampini if (shellA->zcols) { 9949566063dSJacob Faibussowitsch PetscCall(ISDuplicate(shellA->zcols,&shellB->zcols)); 99545960306SStefano Zampini } 9969566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals,&shellB->zvals)); 9979566063dSJacob Faibussowitsch PetscCall(VecCopy(shellA->zvals,shellB->zvals)); 9989566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shellA->zvals_w,&shellB->zvals_w)); 9999566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_r)); 10009566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)shellA->zvals_sct_c)); 100145960306SStefano Zampini shellB->zvals_sct_r = shellA->zvals_sct_r; 100245960306SStefano Zampini shellB->zvals_sct_c = shellA->zvals_sct_c; 100345960306SStefano Zampini } 1004b77ba244SStefano Zampini 1005b77ba244SStefano Zampini matmatA = shellA->matmat; 1006b77ba244SStefano Zampini if (matmatA) { 1007b77ba244SStefano Zampini while (matmatA->next) { 10089566063dSJacob Faibussowitsch PetscCall(MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname)); 1009b77ba244SStefano Zampini matmatA = matmatA->next; 1010b77ba244SStefano Zampini } 1011b77ba244SStefano Zampini } 10127fabda3fSAlex Fikl PetscFunctionReturn(0); 10137fabda3fSAlex Fikl } 10147fabda3fSAlex Fikl 1015cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M) 1016cb8c8a77SBarry Smith { 1017cb8c8a77SBarry Smith void *ctx; 1018cb8c8a77SBarry Smith 1019cb8c8a77SBarry Smith PetscFunctionBegin; 10209566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(mat,&ctx)); 10219566063dSJacob Faibussowitsch PetscCall(MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M)); 10229566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name)); 1023a4b1380bSStefano Zampini if (op != MAT_DO_NOT_COPY_VALUES) { 10249566063dSJacob Faibussowitsch PetscCall(MatCopy(mat,*M,SAME_NONZERO_PATTERN)); 1025a4b1380bSStefano Zampini } 1026cb8c8a77SBarry Smith PetscFunctionReturn(0); 1027cb8c8a77SBarry Smith } 1028cb8c8a77SBarry Smith 1029dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 1030ef66eb69SBarry Smith { 1031ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell*)A->data; 103225578ef6SJed Brown Vec xx; 1033e3f487b0SBarry Smith PetscObjectState instate,outstate; 1034ef66eb69SBarry Smith 1035ef66eb69SBarry Smith PetscFunctionBegin; 103628b400f6SJacob Faibussowitsch PetscCheck(shell->ops->mult,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL"); 10379566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroRight(A,x,&xx)); 10389566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleRight(A,xx,&xx)); 10399566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10409566063dSJacob Faibussowitsch PetscCall((*shell->ops->mult)(A,xx,y)); 10419566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1042e3f487b0SBarry Smith if (instate == outstate) { 1043e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10449566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1045e3f487b0SBarry Smith } 10469566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A,xx,y)); 10479566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleLeft(A,y)); 10489566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroLeft(A,y)); 10499f137db4SBarry Smith 10509f137db4SBarry Smith if (shell->axpy) { 1051ef5c7bd2SStefano Zampini Mat X; 1052ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1053ef5c7bd2SStefano Zampini 10549566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy,&X)); 10559566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state)); 10562c71b3e2SJacob Faibussowitsch PetscCheckFalse(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,...)"); 1057b77ba244SStefano Zampini 10589566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left)); 10599566063dSJacob Faibussowitsch PetscCall(VecCopy(x,shell->axpy_right)); 10609566063dSJacob Faibussowitsch PetscCall(MatMult(shell->axpy,shell->axpy_right,shell->axpy_left)); 10619566063dSJacob Faibussowitsch PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_left)); 10629f137db4SBarry Smith } 1063ef66eb69SBarry Smith PetscFunctionReturn(0); 1064ef66eb69SBarry Smith } 1065ef66eb69SBarry Smith 10665edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z) 10675edf6516SJed Brown { 10685edf6516SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 10695edf6516SJed Brown 10705edf6516SJed Brown PetscFunctionBegin; 10715edf6516SJed Brown if (y == z) { 10729566063dSJacob Faibussowitsch if (!shell->right_add_work) PetscCall(VecDuplicate(z,&shell->right_add_work)); 10739566063dSJacob Faibussowitsch PetscCall(MatMult(A,x,shell->right_add_work)); 10749566063dSJacob Faibussowitsch PetscCall(VecAXPY(z,1.0,shell->right_add_work)); 10755edf6516SJed Brown } else { 10769566063dSJacob Faibussowitsch PetscCall(MatMult(A,x,z)); 10779566063dSJacob Faibussowitsch PetscCall(VecAXPY(z,1.0,y)); 10785edf6516SJed Brown } 10795edf6516SJed Brown PetscFunctionReturn(0); 10805edf6516SJed Brown } 10815edf6516SJed Brown 108218be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y) 108318be62a5SSatish Balay { 108418be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell*)A->data; 108525578ef6SJed Brown Vec xx; 1086e3f487b0SBarry Smith PetscObjectState instate,outstate; 108718be62a5SSatish Balay 108818be62a5SSatish Balay PetscFunctionBegin; 108928b400f6SJacob Faibussowitsch PetscCheck(shell->ops->multtranspose,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL"); 10909566063dSJacob Faibussowitsch PetscCall(MatShellPreZeroLeft(A,x,&xx)); 10919566063dSJacob Faibussowitsch PetscCall(MatShellPreScaleLeft(A,xx,&xx)); 10929566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &instate)); 10939566063dSJacob Faibussowitsch PetscCall((*shell->ops->multtranspose)(A,xx,y)); 10949566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)y, &outstate)); 1095e3f487b0SBarry Smith if (instate == outstate) { 1096e3f487b0SBarry Smith /* increase the state of the output vector since the user did not update its state themself as should have been done */ 10979566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)y)); 1098e3f487b0SBarry Smith } 10999566063dSJacob Faibussowitsch PetscCall(MatShellShiftAndScale(A,xx,y)); 11009566063dSJacob Faibussowitsch PetscCall(MatShellPostScaleRight(A,y)); 11019566063dSJacob Faibussowitsch PetscCall(MatShellPostZeroRight(A,y)); 1102350ec83bSStefano Zampini 1103350ec83bSStefano Zampini if (shell->axpy) { 1104ef5c7bd2SStefano Zampini Mat X; 1105ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1106ef5c7bd2SStefano Zampini 11079566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy,&X)); 11089566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state)); 11092c71b3e2SJacob Faibussowitsch PetscCheckFalse(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,...)"); 11109566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left)); 11119566063dSJacob Faibussowitsch PetscCall(VecCopy(x,shell->axpy_left)); 11129566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right)); 11139566063dSJacob Faibussowitsch PetscCall(VecAXPY(y,shell->axpy_vscale,shell->axpy_right)); 1114350ec83bSStefano Zampini } 111518be62a5SSatish Balay PetscFunctionReturn(0); 111618be62a5SSatish Balay } 111718be62a5SSatish Balay 11185edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z) 11195edf6516SJed Brown { 11205edf6516SJed Brown Mat_Shell *shell = (Mat_Shell*)A->data; 11215edf6516SJed Brown 11225edf6516SJed Brown PetscFunctionBegin; 11235edf6516SJed Brown if (y == z) { 11249566063dSJacob Faibussowitsch if (!shell->left_add_work) PetscCall(VecDuplicate(z,&shell->left_add_work)); 11259566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A,x,shell->left_add_work)); 11269566063dSJacob Faibussowitsch PetscCall(VecAXPY(z,1.0,shell->left_add_work)); 11275edf6516SJed Brown } else { 11289566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A,x,z)); 11299566063dSJacob Faibussowitsch PetscCall(VecAXPY(z,1.0,y)); 11305edf6516SJed Brown } 11315edf6516SJed Brown PetscFunctionReturn(0); 11325edf6516SJed Brown } 11335edf6516SJed Brown 11340c0fd78eSBarry Smith /* 11350c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 11360c0fd78eSBarry Smith */ 113718be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v) 113818be62a5SSatish Balay { 113918be62a5SSatish Balay Mat_Shell *shell = (Mat_Shell*)A->data; 114018be62a5SSatish Balay 114118be62a5SSatish Balay PetscFunctionBegin; 11420c0fd78eSBarry Smith if (shell->ops->getdiagonal) { 11439566063dSJacob Faibussowitsch PetscCall((*shell->ops->getdiagonal)(A,v)); 1144305211d5SBarry 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,...)"); 11459566063dSJacob Faibussowitsch PetscCall(VecScale(v,shell->vscale)); 11468fe8eb27SJed Brown if (shell->dshift) { 11479566063dSJacob Faibussowitsch PetscCall(VecAXPY(v,1.0,shell->dshift)); 114818be62a5SSatish Balay } 11499566063dSJacob Faibussowitsch PetscCall(VecShift(v,shell->vshift)); 11509566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(v,v,shell->left)); 11519566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(v,v,shell->right)); 115245960306SStefano Zampini if (shell->zrows) { 11539566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE)); 11549566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE)); 115545960306SStefano Zampini } 115681c02519SBarry Smith if (shell->axpy) { 1157ef5c7bd2SStefano Zampini Mat X; 1158ef5c7bd2SStefano Zampini PetscObjectState axpy_state; 1159ef5c7bd2SStefano Zampini 11609566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(shell->axpy,&X)); 11619566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X,&axpy_state)); 11622c71b3e2SJacob Faibussowitsch PetscCheckFalse(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,...)"); 11639566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left)); 11649566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(shell->axpy,shell->axpy_left)); 11659566063dSJacob Faibussowitsch PetscCall(VecAXPY(v,shell->axpy_vscale,shell->axpy_left)); 116681c02519SBarry Smith } 116718be62a5SSatish Balay PetscFunctionReturn(0); 116818be62a5SSatish Balay } 116918be62a5SSatish Balay 1170f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a) 1171ef66eb69SBarry Smith { 1172ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell*)Y->data; 1173789d8953SBarry Smith PetscBool flg; 1174b24ad042SBarry Smith 1175ef66eb69SBarry Smith PetscFunctionBegin; 11769566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(Y,&flg)); 117728b400f6SJacob Faibussowitsch PetscCheck(flg,PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent"); 11780c0fd78eSBarry Smith if (shell->left || shell->right) { 11798fe8eb27SJed Brown if (!shell->dshift) { 11809566063dSJacob Faibussowitsch PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift)); 11819566063dSJacob Faibussowitsch PetscCall(VecSet(shell->dshift,a)); 11820c0fd78eSBarry Smith } else { 11839566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->left)); 11849566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseMult(shell->dshift,shell->dshift,shell->right)); 11859566063dSJacob Faibussowitsch PetscCall(VecShift(shell->dshift,a)); 11860c0fd78eSBarry Smith } 11879566063dSJacob Faibussowitsch if (shell->left) PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->left)); 11889566063dSJacob Faibussowitsch if (shell->right) PetscCall(VecPointwiseDivide(shell->dshift,shell->dshift,shell->right)); 11898fe8eb27SJed Brown } else shell->vshift += a; 119045960306SStefano Zampini if (shell->zrows) { 11919566063dSJacob Faibussowitsch PetscCall(VecShift(shell->zvals,a)); 119245960306SStefano Zampini } 1193ef66eb69SBarry Smith PetscFunctionReturn(0); 1194ef66eb69SBarry Smith } 1195ef66eb69SBarry Smith 1196b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s) 11976464bf51SAlex Fikl { 11986464bf51SAlex Fikl Mat_Shell *shell = (Mat_Shell*)A->data; 11996464bf51SAlex Fikl 12006464bf51SAlex Fikl PetscFunctionBegin; 12019566063dSJacob Faibussowitsch if (!shell->dshift) PetscCall(VecDuplicate(D,&shell->dshift)); 12020c0fd78eSBarry Smith if (shell->left || shell->right) { 12039566063dSJacob Faibussowitsch if (!shell->right_work) PetscCall(VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work)); 12049f137db4SBarry Smith if (shell->left && shell->right) { 12059566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left)); 12069566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work,shell->right_work,shell->right)); 12079f137db4SBarry Smith } else if (shell->left) { 12089566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work,D,shell->left)); 12099f137db4SBarry Smith } else { 12109566063dSJacob Faibussowitsch PetscCall(VecPointwiseDivide(shell->right_work,D,shell->right)); 12119f137db4SBarry Smith } 12129566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift,s,shell->right_work)); 12130c0fd78eSBarry Smith } else { 12149566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->dshift,s,D)); 1215b253ae0bS“Marek } 1216b253ae0bS“Marek PetscFunctionReturn(0); 1217b253ae0bS“Marek } 1218b253ae0bS“Marek 1219b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins) 1220b253ae0bS“Marek { 122145960306SStefano Zampini Mat_Shell *shell = (Mat_Shell*)A->data; 1222b253ae0bS“Marek Vec d; 1223789d8953SBarry Smith PetscBool flg; 1224b253ae0bS“Marek 1225b253ae0bS“Marek PetscFunctionBegin; 12269566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A,&flg)); 122728b400f6SJacob Faibussowitsch PetscCheck(flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent"); 1228b253ae0bS“Marek if (ins == INSERT_VALUES) { 122928b400f6SJacob Faibussowitsch PetscCheck(A->ops->getdiagonal,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first"); 12309566063dSJacob Faibussowitsch PetscCall(VecDuplicate(D,&d)); 12319566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(A,d)); 12329566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A,d,-1.)); 12339566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A,D,1.)); 12349566063dSJacob Faibussowitsch PetscCall(VecDestroy(&d)); 123545960306SStefano Zampini if (shell->zrows) { 12369566063dSJacob Faibussowitsch PetscCall(VecCopy(D,shell->zvals)); 123745960306SStefano Zampini } 1238b253ae0bS“Marek } else { 12399566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet_Shell_Private(A,D,1.)); 124045960306SStefano Zampini if (shell->zrows) { 12419566063dSJacob Faibussowitsch PetscCall(VecAXPY(shell->zvals,1.0,D)); 124245960306SStefano Zampini } 12436464bf51SAlex Fikl } 12446464bf51SAlex Fikl PetscFunctionReturn(0); 12456464bf51SAlex Fikl } 12466464bf51SAlex Fikl 1247f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a) 1248ef66eb69SBarry Smith { 1249ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell*)Y->data; 1250b24ad042SBarry Smith 1251ef66eb69SBarry Smith PetscFunctionBegin; 1252f4df32b1SMatthew Knepley shell->vscale *= a; 12530c0fd78eSBarry Smith shell->vshift *= a; 12542205254eSKarl Rupp if (shell->dshift) { 12559566063dSJacob Faibussowitsch PetscCall(VecScale(shell->dshift,a)); 12560c0fd78eSBarry Smith } 125781c02519SBarry Smith shell->axpy_vscale *= a; 125845960306SStefano Zampini if (shell->zrows) { 12599566063dSJacob Faibussowitsch PetscCall(VecScale(shell->zvals,a)); 126045960306SStefano Zampini } 12618fe8eb27SJed Brown PetscFunctionReturn(0); 126218be62a5SSatish Balay } 12638fe8eb27SJed Brown 12648fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right) 12658fe8eb27SJed Brown { 12668fe8eb27SJed Brown Mat_Shell *shell = (Mat_Shell*)Y->data; 12678fe8eb27SJed Brown 12688fe8eb27SJed Brown PetscFunctionBegin; 12698fe8eb27SJed Brown if (left) { 12700c0fd78eSBarry Smith if (!shell->left) { 12719566063dSJacob Faibussowitsch PetscCall(VecDuplicate(left,&shell->left)); 12729566063dSJacob Faibussowitsch PetscCall(VecCopy(left,shell->left)); 12730c0fd78eSBarry Smith } else { 12749566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->left,shell->left,left)); 127518be62a5SSatish Balay } 127645960306SStefano Zampini if (shell->zrows) { 12779566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,left)); 127845960306SStefano Zampini } 1279ef66eb69SBarry Smith } 12808fe8eb27SJed Brown if (right) { 12810c0fd78eSBarry Smith if (!shell->right) { 12829566063dSJacob Faibussowitsch PetscCall(VecDuplicate(right,&shell->right)); 12839566063dSJacob Faibussowitsch PetscCall(VecCopy(right,shell->right)); 12840c0fd78eSBarry Smith } else { 12859566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->right,shell->right,right)); 12868fe8eb27SJed Brown } 128745960306SStefano Zampini if (shell->zrows) { 128845960306SStefano Zampini if (!shell->left_work) { 12899566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(Y,NULL,&shell->left_work)); 129045960306SStefano Zampini } 12919566063dSJacob Faibussowitsch PetscCall(VecSet(shell->zvals_w,1.0)); 12929566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD)); 12939566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD)); 12949566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w)); 129545960306SStefano Zampini } 12968fe8eb27SJed Brown } 1297ef5c7bd2SStefano Zampini if (shell->axpy) { 12989566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(shell->axpy,left,right)); 1299ef5c7bd2SStefano Zampini } 1300ef66eb69SBarry Smith PetscFunctionReturn(0); 1301ef66eb69SBarry Smith } 1302ef66eb69SBarry Smith 1303dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 1304ef66eb69SBarry Smith { 1305ef66eb69SBarry Smith Mat_Shell *shell = (Mat_Shell*)Y->data; 1306ef66eb69SBarry Smith 1307ef66eb69SBarry Smith PetscFunctionBegin; 13088fe8eb27SJed Brown if (t == MAT_FINAL_ASSEMBLY) { 1309ef66eb69SBarry Smith shell->vshift = 0.0; 1310ef66eb69SBarry Smith shell->vscale = 1.0; 1311ef5c7bd2SStefano Zampini shell->axpy_vscale = 0.0; 1312ef5c7bd2SStefano Zampini shell->axpy_state = 0; 13139566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->dshift)); 13149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->left)); 13159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->right)); 13169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&shell->axpy)); 13179566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_left)); 13189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&shell->axpy_right)); 13199566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_c)); 13209566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&shell->zvals_sct_r)); 13219566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zrows)); 13229566063dSJacob Faibussowitsch PetscCall(ISDestroy(&shell->zcols)); 1323ef66eb69SBarry Smith } 1324ef66eb69SBarry Smith PetscFunctionReturn(0); 1325ef66eb69SBarry Smith } 1326ef66eb69SBarry Smith 13273b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d) 13283b49f96aSBarry Smith { 13293b49f96aSBarry Smith PetscFunctionBegin; 13303b49f96aSBarry Smith *missing = PETSC_FALSE; 13313b49f96aSBarry Smith PetscFunctionReturn(0); 13323b49f96aSBarry Smith } 13333b49f96aSBarry Smith 13349f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str) 13359f137db4SBarry Smith { 13369f137db4SBarry Smith Mat_Shell *shell = (Mat_Shell*)Y->data; 13379f137db4SBarry Smith 13389f137db4SBarry Smith PetscFunctionBegin; 1339ef5c7bd2SStefano Zampini if (X == Y) { 13409566063dSJacob Faibussowitsch PetscCall(MatScale(Y,1.0 + a)); 1341ef5c7bd2SStefano Zampini PetscFunctionReturn(0); 1342ef5c7bd2SStefano Zampini } 1343ef5c7bd2SStefano Zampini if (!shell->axpy) { 13449566063dSJacob Faibussowitsch PetscCall(MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy)); 13459f137db4SBarry Smith shell->axpy_vscale = a; 13469566063dSJacob Faibussowitsch PetscCall(PetscObjectStateGet((PetscObject)X,&shell->axpy_state)); 1347ef5c7bd2SStefano Zampini } else { 13489566063dSJacob Faibussowitsch PetscCall(MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str)); 1349ef5c7bd2SStefano Zampini } 13509f137db4SBarry Smith PetscFunctionReturn(0); 13519f137db4SBarry Smith } 13529f137db4SBarry Smith 1353f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL, 1354f4259b30SLisandro Dalcin NULL, 1355f4259b30SLisandro Dalcin NULL, 1356f4259b30SLisandro Dalcin NULL, 13570c0fd78eSBarry Smith /* 4*/ MatMultAdd_Shell, 1358f4259b30SLisandro Dalcin NULL, 13590c0fd78eSBarry Smith MatMultTransposeAdd_Shell, 1360f4259b30SLisandro Dalcin NULL, 1361f4259b30SLisandro Dalcin NULL, 1362f4259b30SLisandro Dalcin NULL, 1363f4259b30SLisandro Dalcin /*10*/ NULL, 1364f4259b30SLisandro Dalcin NULL, 1365f4259b30SLisandro Dalcin NULL, 1366f4259b30SLisandro Dalcin NULL, 1367f4259b30SLisandro Dalcin NULL, 1368f4259b30SLisandro Dalcin /*15*/ NULL, 1369f4259b30SLisandro Dalcin NULL, 1370f4259b30SLisandro Dalcin NULL, 13718fe8eb27SJed Brown MatDiagonalScale_Shell, 1372f4259b30SLisandro Dalcin NULL, 1373f4259b30SLisandro Dalcin /*20*/ NULL, 1374ef66eb69SBarry Smith MatAssemblyEnd_Shell, 1375f4259b30SLisandro Dalcin NULL, 1376f4259b30SLisandro Dalcin NULL, 137745960306SStefano Zampini /*24*/ MatZeroRows_Shell, 1378f4259b30SLisandro Dalcin NULL, 1379f4259b30SLisandro Dalcin NULL, 1380f4259b30SLisandro Dalcin NULL, 1381f4259b30SLisandro Dalcin NULL, 1382f4259b30SLisandro Dalcin /*29*/ NULL, 1383f4259b30SLisandro Dalcin NULL, 1384f4259b30SLisandro Dalcin NULL, 1385f4259b30SLisandro Dalcin NULL, 1386f4259b30SLisandro Dalcin NULL, 1387cb8c8a77SBarry Smith /*34*/ MatDuplicate_Shell, 1388f4259b30SLisandro Dalcin NULL, 1389f4259b30SLisandro Dalcin NULL, 1390f4259b30SLisandro Dalcin NULL, 1391f4259b30SLisandro Dalcin NULL, 13929f137db4SBarry Smith /*39*/ MatAXPY_Shell, 1393f4259b30SLisandro Dalcin NULL, 1394f4259b30SLisandro Dalcin NULL, 1395f4259b30SLisandro Dalcin NULL, 1396cb8c8a77SBarry Smith MatCopy_Shell, 1397f4259b30SLisandro Dalcin /*44*/ NULL, 1398ef66eb69SBarry Smith MatScale_Shell, 1399ef66eb69SBarry Smith MatShift_Shell, 14006464bf51SAlex Fikl MatDiagonalSet_Shell, 140145960306SStefano Zampini MatZeroRowsColumns_Shell, 1402f4259b30SLisandro Dalcin /*49*/ NULL, 1403f4259b30SLisandro Dalcin NULL, 1404f4259b30SLisandro Dalcin NULL, 1405f4259b30SLisandro Dalcin NULL, 1406f4259b30SLisandro Dalcin NULL, 1407f4259b30SLisandro Dalcin /*54*/ NULL, 1408f4259b30SLisandro Dalcin NULL, 1409f4259b30SLisandro Dalcin NULL, 1410f4259b30SLisandro Dalcin NULL, 1411f4259b30SLisandro Dalcin NULL, 1412f4259b30SLisandro Dalcin /*59*/ NULL, 1413b9b97703SBarry Smith MatDestroy_Shell, 1414f4259b30SLisandro Dalcin NULL, 1415251fad3fSStefano Zampini MatConvertFrom_Shell, 1416f4259b30SLisandro Dalcin NULL, 1417f4259b30SLisandro Dalcin /*64*/ NULL, 1418f4259b30SLisandro Dalcin NULL, 1419f4259b30SLisandro Dalcin NULL, 1420f4259b30SLisandro Dalcin NULL, 1421f4259b30SLisandro Dalcin NULL, 1422f4259b30SLisandro Dalcin /*69*/ NULL, 1423f4259b30SLisandro Dalcin NULL, 1424c87e5d42SMatthew Knepley MatConvert_Shell, 1425f4259b30SLisandro Dalcin NULL, 1426f4259b30SLisandro Dalcin NULL, 1427f4259b30SLisandro Dalcin /*74*/ NULL, 1428f4259b30SLisandro Dalcin NULL, 1429f4259b30SLisandro Dalcin NULL, 1430f4259b30SLisandro Dalcin NULL, 1431f4259b30SLisandro Dalcin NULL, 1432f4259b30SLisandro Dalcin /*79*/ NULL, 1433f4259b30SLisandro Dalcin NULL, 1434f4259b30SLisandro Dalcin NULL, 1435f4259b30SLisandro Dalcin NULL, 1436f4259b30SLisandro Dalcin NULL, 1437f4259b30SLisandro Dalcin /*84*/ NULL, 1438f4259b30SLisandro Dalcin NULL, 1439f4259b30SLisandro Dalcin NULL, 1440f4259b30SLisandro Dalcin NULL, 1441f4259b30SLisandro Dalcin NULL, 1442f4259b30SLisandro Dalcin /*89*/ NULL, 1443f4259b30SLisandro Dalcin NULL, 1444f4259b30SLisandro Dalcin NULL, 1445f4259b30SLisandro Dalcin NULL, 1446f4259b30SLisandro Dalcin NULL, 1447f4259b30SLisandro Dalcin /*94*/ NULL, 1448f4259b30SLisandro Dalcin NULL, 1449f4259b30SLisandro Dalcin NULL, 1450f4259b30SLisandro Dalcin NULL, 1451f4259b30SLisandro Dalcin NULL, 1452f4259b30SLisandro Dalcin /*99*/ NULL, 1453f4259b30SLisandro Dalcin NULL, 1454f4259b30SLisandro Dalcin NULL, 1455f4259b30SLisandro Dalcin NULL, 1456f4259b30SLisandro Dalcin NULL, 1457f4259b30SLisandro Dalcin /*104*/ NULL, 1458f4259b30SLisandro Dalcin NULL, 1459f4259b30SLisandro Dalcin NULL, 1460f4259b30SLisandro Dalcin NULL, 1461f4259b30SLisandro Dalcin NULL, 1462f4259b30SLisandro Dalcin /*109*/ NULL, 1463f4259b30SLisandro Dalcin NULL, 1464f4259b30SLisandro Dalcin NULL, 1465f4259b30SLisandro Dalcin NULL, 14663b49f96aSBarry Smith MatMissingDiagonal_Shell, 1467f4259b30SLisandro Dalcin /*114*/ NULL, 1468f4259b30SLisandro Dalcin NULL, 1469f4259b30SLisandro Dalcin NULL, 1470f4259b30SLisandro Dalcin NULL, 1471f4259b30SLisandro Dalcin NULL, 1472f4259b30SLisandro Dalcin /*119*/ NULL, 1473f4259b30SLisandro Dalcin NULL, 1474f4259b30SLisandro Dalcin NULL, 1475f4259b30SLisandro Dalcin NULL, 1476f4259b30SLisandro Dalcin NULL, 1477f4259b30SLisandro Dalcin /*124*/ NULL, 1478f4259b30SLisandro Dalcin NULL, 1479f4259b30SLisandro Dalcin NULL, 1480f4259b30SLisandro Dalcin NULL, 1481f4259b30SLisandro Dalcin NULL, 1482f4259b30SLisandro Dalcin /*129*/ NULL, 1483f4259b30SLisandro Dalcin NULL, 1484f4259b30SLisandro Dalcin NULL, 1485f4259b30SLisandro Dalcin NULL, 1486f4259b30SLisandro Dalcin NULL, 1487f4259b30SLisandro Dalcin /*134*/ NULL, 1488f4259b30SLisandro Dalcin NULL, 1489f4259b30SLisandro Dalcin NULL, 1490f4259b30SLisandro Dalcin NULL, 1491f4259b30SLisandro Dalcin NULL, 1492f4259b30SLisandro Dalcin /*139*/ NULL, 1493f4259b30SLisandro Dalcin NULL, 1494d70f29a3SPierre Jolivet NULL, 1495d70f29a3SPierre Jolivet NULL, 1496d70f29a3SPierre Jolivet NULL, 1497d70f29a3SPierre Jolivet /*144*/ NULL, 1498d70f29a3SPierre Jolivet NULL, 1499d70f29a3SPierre Jolivet NULL, 1500f4259b30SLisandro Dalcin NULL 15013964eb88SJed Brown }; 1502273d9f13SBarry Smith 1503789d8953SBarry Smith PetscErrorCode MatShellSetContext_Shell(Mat mat,void *ctx) 1504789d8953SBarry Smith { 1505789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell*)mat->data; 1506789d8953SBarry Smith 1507789d8953SBarry Smith PetscFunctionBegin; 1508789d8953SBarry Smith shell->ctx = ctx; 1509789d8953SBarry Smith PetscFunctionReturn(0); 1510789d8953SBarry Smith } 1511789d8953SBarry Smith 1512db77db73SJeremy L Thompson static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype) 1513db77db73SJeremy L Thompson { 1514db77db73SJeremy L Thompson PetscFunctionBegin; 15159566063dSJacob Faibussowitsch PetscCall(PetscFree(mat->defaultvectype)); 15169566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(vtype,(char**)&mat->defaultvectype)); 1517db77db73SJeremy L Thompson PetscFunctionReturn(0); 1518db77db73SJeremy L Thompson } 1519db77db73SJeremy L Thompson 1520789d8953SBarry Smith PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A) 1521789d8953SBarry Smith { 1522789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell*)A->data; 1523789d8953SBarry Smith 1524789d8953SBarry Smith PetscFunctionBegin; 1525789d8953SBarry Smith shell->managescalingshifts = PETSC_FALSE; 1526789d8953SBarry Smith A->ops->diagonalset = NULL; 1527789d8953SBarry Smith A->ops->diagonalscale = NULL; 1528789d8953SBarry Smith A->ops->scale = NULL; 1529789d8953SBarry Smith A->ops->shift = NULL; 1530789d8953SBarry Smith A->ops->axpy = NULL; 1531789d8953SBarry Smith PetscFunctionReturn(0); 1532789d8953SBarry Smith } 1533789d8953SBarry Smith 1534789d8953SBarry Smith PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void)) 1535789d8953SBarry Smith { 1536feb237baSPierre Jolivet Mat_Shell *shell = (Mat_Shell*)mat->data; 1537789d8953SBarry Smith 1538789d8953SBarry Smith PetscFunctionBegin; 1539789d8953SBarry Smith switch (op) { 1540789d8953SBarry Smith case MATOP_DESTROY: 1541789d8953SBarry Smith shell->ops->destroy = (PetscErrorCode (*)(Mat))f; 1542789d8953SBarry Smith break; 1543789d8953SBarry Smith case MATOP_VIEW: 1544789d8953SBarry Smith if (!mat->ops->viewnative) { 1545789d8953SBarry Smith mat->ops->viewnative = mat->ops->view; 1546789d8953SBarry Smith } 1547789d8953SBarry Smith mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f; 1548789d8953SBarry Smith break; 1549789d8953SBarry Smith case MATOP_COPY: 1550789d8953SBarry Smith shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f; 1551789d8953SBarry Smith break; 1552789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1553789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1554789d8953SBarry Smith case MATOP_SHIFT: 1555789d8953SBarry Smith case MATOP_SCALE: 1556789d8953SBarry Smith case MATOP_AXPY: 1557789d8953SBarry Smith case MATOP_ZERO_ROWS: 1558789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 155928b400f6SJacob Faibussowitsch PetscCheck(!shell->managescalingshifts,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1560789d8953SBarry Smith (((void(**)(void))mat->ops)[op]) = f; 1561789d8953SBarry Smith break; 1562789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1563789d8953SBarry Smith if (shell->managescalingshifts) { 1564789d8953SBarry Smith shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1565789d8953SBarry Smith mat->ops->getdiagonal = MatGetDiagonal_Shell; 1566789d8953SBarry Smith } else { 1567789d8953SBarry Smith shell->ops->getdiagonal = NULL; 1568789d8953SBarry Smith mat->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1569789d8953SBarry Smith } 1570789d8953SBarry Smith break; 1571789d8953SBarry Smith case MATOP_MULT: 1572789d8953SBarry Smith if (shell->managescalingshifts) { 1573789d8953SBarry Smith shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1574789d8953SBarry Smith mat->ops->mult = MatMult_Shell; 1575789d8953SBarry Smith } else { 1576789d8953SBarry Smith shell->ops->mult = NULL; 1577789d8953SBarry Smith mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1578789d8953SBarry Smith } 1579789d8953SBarry Smith break; 1580789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1581789d8953SBarry Smith if (shell->managescalingshifts) { 1582789d8953SBarry Smith shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1583789d8953SBarry Smith mat->ops->multtranspose = MatMultTranspose_Shell; 1584789d8953SBarry Smith } else { 1585789d8953SBarry Smith shell->ops->multtranspose = NULL; 1586789d8953SBarry Smith mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1587789d8953SBarry Smith } 1588789d8953SBarry Smith break; 1589789d8953SBarry Smith default: 1590789d8953SBarry Smith (((void(**)(void))mat->ops)[op]) = f; 1591789d8953SBarry Smith break; 1592789d8953SBarry Smith } 1593789d8953SBarry Smith PetscFunctionReturn(0); 1594789d8953SBarry Smith } 1595789d8953SBarry Smith 1596789d8953SBarry Smith PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void)) 1597789d8953SBarry Smith { 1598789d8953SBarry Smith Mat_Shell *shell = (Mat_Shell*)mat->data; 1599789d8953SBarry Smith 1600789d8953SBarry Smith PetscFunctionBegin; 1601789d8953SBarry Smith switch (op) { 1602789d8953SBarry Smith case MATOP_DESTROY: 1603789d8953SBarry Smith *f = (void (*)(void))shell->ops->destroy; 1604789d8953SBarry Smith break; 1605789d8953SBarry Smith case MATOP_VIEW: 1606789d8953SBarry Smith *f = (void (*)(void))mat->ops->view; 1607789d8953SBarry Smith break; 1608789d8953SBarry Smith case MATOP_COPY: 1609789d8953SBarry Smith *f = (void (*)(void))shell->ops->copy; 1610789d8953SBarry Smith break; 1611789d8953SBarry Smith case MATOP_DIAGONAL_SET: 1612789d8953SBarry Smith case MATOP_DIAGONAL_SCALE: 1613789d8953SBarry Smith case MATOP_SHIFT: 1614789d8953SBarry Smith case MATOP_SCALE: 1615789d8953SBarry Smith case MATOP_AXPY: 1616789d8953SBarry Smith case MATOP_ZERO_ROWS: 1617789d8953SBarry Smith case MATOP_ZERO_ROWS_COLUMNS: 1618789d8953SBarry Smith *f = (((void (**)(void))mat->ops)[op]); 1619789d8953SBarry Smith break; 1620789d8953SBarry Smith case MATOP_GET_DIAGONAL: 1621789d8953SBarry Smith if (shell->ops->getdiagonal) 1622789d8953SBarry Smith *f = (void (*)(void))shell->ops->getdiagonal; 1623789d8953SBarry Smith else 1624789d8953SBarry Smith *f = (((void (**)(void))mat->ops)[op]); 1625789d8953SBarry Smith break; 1626789d8953SBarry Smith case MATOP_MULT: 1627789d8953SBarry Smith if (shell->ops->mult) 1628789d8953SBarry Smith *f = (void (*)(void))shell->ops->mult; 1629789d8953SBarry Smith else 1630789d8953SBarry Smith *f = (((void (**)(void))mat->ops)[op]); 1631789d8953SBarry Smith break; 1632789d8953SBarry Smith case MATOP_MULT_TRANSPOSE: 1633789d8953SBarry Smith if (shell->ops->multtranspose) 1634789d8953SBarry Smith *f = (void (*)(void))shell->ops->multtranspose; 1635789d8953SBarry Smith else 1636789d8953SBarry Smith *f = (((void (**)(void))mat->ops)[op]); 1637789d8953SBarry Smith break; 1638789d8953SBarry Smith default: 1639789d8953SBarry Smith *f = (((void (**)(void))mat->ops)[op]); 1640789d8953SBarry Smith } 1641789d8953SBarry Smith PetscFunctionReturn(0); 1642789d8953SBarry Smith } 1643789d8953SBarry Smith 16440bad9183SKris Buschelman /*MC 1645fafad747SKris Buschelman MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 16460bad9183SKris Buschelman 16470bad9183SKris Buschelman Level: advanced 16480bad9183SKris Buschelman 16490c0fd78eSBarry Smith .seealso: MatCreateShell() 16500bad9183SKris Buschelman M*/ 16510bad9183SKris Buschelman 16528cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 1653273d9f13SBarry Smith { 1654273d9f13SBarry Smith Mat_Shell *b; 1655273d9f13SBarry Smith 1656273d9f13SBarry Smith PetscFunctionBegin; 16579566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps))); 1658273d9f13SBarry Smith 16599566063dSJacob Faibussowitsch PetscCall(PetscNewLog(A,&b)); 1660273d9f13SBarry Smith A->data = (void*)b; 1661273d9f13SBarry Smith 1662f4259b30SLisandro Dalcin b->ctx = NULL; 1663ef66eb69SBarry Smith b->vshift = 0.0; 1664ef66eb69SBarry Smith b->vscale = 1.0; 16650c0fd78eSBarry Smith b->managescalingshifts = PETSC_TRUE; 1666273d9f13SBarry Smith A->assembled = PETSC_TRUE; 1667210f0121SBarry Smith A->preallocated = PETSC_FALSE; 16682205254eSKarl Rupp 16699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell)); 16709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell)); 16719566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell)); 16729566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell)); 16739566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell)); 16749566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell)); 16759566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell)); 16769566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATSHELL)); 1677273d9f13SBarry Smith PetscFunctionReturn(0); 1678273d9f13SBarry Smith } 1679e51e0e81SBarry Smith 16804b828684SBarry Smith /*@C 1681052efed2SBarry Smith MatCreateShell - Creates a new matrix class for use with a user-defined 1682ff756334SLois Curfman McInnes private data storage format. 1683e51e0e81SBarry Smith 1684d083f849SBarry Smith Collective 1685c7fcc2eaSBarry Smith 1686e51e0e81SBarry Smith Input Parameters: 1687c7fcc2eaSBarry Smith + comm - MPI communicator 1688c7fcc2eaSBarry Smith . m - number of local rows (must be given) 1689c7fcc2eaSBarry Smith . n - number of local columns (must be given) 1690c7fcc2eaSBarry Smith . M - number of global rows (may be PETSC_DETERMINE) 1691c7fcc2eaSBarry Smith . N - number of global columns (may be PETSC_DETERMINE) 1692c7fcc2eaSBarry Smith - ctx - pointer to data needed by the shell matrix routines 1693e51e0e81SBarry Smith 1694ff756334SLois Curfman McInnes Output Parameter: 169544cd7ae7SLois Curfman McInnes . A - the matrix 1696e51e0e81SBarry Smith 1697ff2fd236SBarry Smith Level: advanced 1698ff2fd236SBarry Smith 1699f39d1f56SLois Curfman McInnes Usage: 17005bd1e576SStefano Zampini $ extern PetscErrorCode mult(Mat,Vec,Vec); 1701f39d1f56SLois Curfman McInnes $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 1702c134de8dSSatish Balay $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1703f39d1f56SLois Curfman McInnes $ [ Use matrix for operations that have been set ] 1704f39d1f56SLois Curfman McInnes $ MatDestroy(mat); 1705f39d1f56SLois Curfman McInnes 1706ff756334SLois Curfman McInnes Notes: 1707ff756334SLois Curfman McInnes The shell matrix type is intended to provide a simple class to use 1708ff756334SLois Curfman McInnes with KSP (such as, for use with matrix-free methods). You should not 1709ff756334SLois Curfman McInnes use the shell type if you plan to define a complete matrix class. 1710e51e0e81SBarry Smith 171195452b02SPatrick Sanan Fortran Notes: 171295452b02SPatrick Sanan To use this from Fortran with a ctx you must write an interface definition for this 1713daf670e6SBarry Smith function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing 1714daf670e6SBarry Smith in as the ctx argument. 1715f38a8d56SBarry Smith 1716f39d1f56SLois Curfman McInnes PETSc requires that matrices and vectors being used for certain 1717f39d1f56SLois Curfman McInnes operations are partitioned accordingly. For example, when 1718645985a0SLois Curfman McInnes creating a shell matrix, A, that supports parallel matrix-vector 1719645985a0SLois Curfman McInnes products using MatMult(A,x,y) the user should set the number 1720645985a0SLois Curfman McInnes of local matrix rows to be the number of local elements of the 1721645985a0SLois Curfman McInnes corresponding result vector, y. Note that this is information is 1722645985a0SLois Curfman McInnes required for use of the matrix interface routines, even though 1723645985a0SLois Curfman McInnes the shell matrix may not actually be physically partitioned. 1724645985a0SLois Curfman McInnes For example, 1725f39d1f56SLois Curfman McInnes 1726f39d1f56SLois Curfman McInnes $ 1727f39d1f56SLois Curfman McInnes $ Vec x, y 17285bd1e576SStefano Zampini $ extern PetscErrorCode mult(Mat,Vec,Vec); 1729645985a0SLois Curfman McInnes $ Mat A 1730f39d1f56SLois Curfman McInnes $ 1731c94f878dSBarry Smith $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 1732c94f878dSBarry Smith $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 1733f39d1f56SLois Curfman McInnes $ VecGetLocalSize(y,&m); 1734c7fcc2eaSBarry Smith $ VecGetLocalSize(x,&n); 1735c7fcc2eaSBarry Smith $ MatCreateShell(comm,m,n,M,N,ctx,&A); 1736c134de8dSSatish Balay $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 1737645985a0SLois Curfman McInnes $ MatMult(A,x,y); 173845960306SStefano Zampini $ MatDestroy(&A); 173945960306SStefano Zampini $ VecDestroy(&y); 174045960306SStefano Zampini $ VecDestroy(&x); 1741645985a0SLois Curfman McInnes $ 1742e51e0e81SBarry Smith 174345960306SStefano Zampini MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these 17449b53d762SBarry Smith operations cannot be overwritten unless MatShellSetManageScalingShifts() is called. 17459b53d762SBarry Smith 17460c0fd78eSBarry Smith For rectangular matrices do all the scalings and shifts make sense? 17470c0fd78eSBarry Smith 174895452b02SPatrick Sanan Developers Notes: 174995452b02SPatrick Sanan Regarding shifting and scaling. The general form is 17500c0fd78eSBarry Smith 17510c0fd78eSBarry Smith diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 17520c0fd78eSBarry Smith 17530c0fd78eSBarry Smith The order you apply the operations is important. For example if you have a dshift then 17540c0fd78eSBarry Smith apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 17550c0fd78eSBarry Smith you get s*vscale*A + diag(shift) 17560c0fd78eSBarry Smith 17570c0fd78eSBarry Smith A is the user provided function. 17580c0fd78eSBarry Smith 1759ad2f5c3fSBarry Smith KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for 1760ad2f5c3fSBarry Smith for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger 1761ad2f5c3fSBarry Smith an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat); 1762ad2f5c3fSBarry Smith each time the MATSHELL matrix has changed. 1763ad2f5c3fSBarry Smith 17647301b172SPierre Jolivet Matrix product operations (i.e. MatMat, MatTransposeMat etc) can be specified using MatShellSetMatProductOperation() 1765b77ba244SStefano Zampini 1766ad2f5c3fSBarry Smith Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided 1767ad2f5c3fSBarry Smith with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale(). 1768ad2f5c3fSBarry Smith 1769b77ba244SStefano Zampini .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts(), MatShellSetMatProductOperation() 1770e51e0e81SBarry Smith @*/ 17717087cfbeSBarry Smith PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 1772e51e0e81SBarry Smith { 17733a40ed3dSBarry Smith PetscFunctionBegin; 17749566063dSJacob Faibussowitsch PetscCall(MatCreate(comm,A)); 17759566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*A,m,n,M,N)); 17769566063dSJacob Faibussowitsch PetscCall(MatSetType(*A,MATSHELL)); 17779566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*A,ctx)); 17789566063dSJacob Faibussowitsch PetscCall(MatSetUp(*A)); 1779273d9f13SBarry Smith PetscFunctionReturn(0); 1780c7fcc2eaSBarry Smith } 1781c7fcc2eaSBarry Smith 1782c6866cfdSSatish Balay /*@ 1783273d9f13SBarry Smith MatShellSetContext - sets the context for a shell matrix 1784c7fcc2eaSBarry Smith 17853f9fe445SBarry Smith Logically Collective on Mat 1786c7fcc2eaSBarry Smith 1787273d9f13SBarry Smith Input Parameters: 1788273d9f13SBarry Smith + mat - the shell matrix 1789273d9f13SBarry Smith - ctx - the context 1790273d9f13SBarry Smith 1791273d9f13SBarry Smith Level: advanced 1792273d9f13SBarry Smith 179395452b02SPatrick Sanan Fortran Notes: 179495452b02SPatrick Sanan To use this from Fortran you must write a Fortran interface definition for this 1795daf670e6SBarry Smith function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 1796273d9f13SBarry Smith 1797273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 17980bc0a719SBarry Smith @*/ 17997087cfbeSBarry Smith PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 1800273d9f13SBarry Smith { 1801273d9f13SBarry Smith PetscFunctionBegin; 18020700a824SBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1803*cac4c232SBarry Smith PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx)); 18043a40ed3dSBarry Smith PetscFunctionReturn(0); 1805e51e0e81SBarry Smith } 1806e51e0e81SBarry Smith 1807db77db73SJeremy L Thompson /*@C 1808db77db73SJeremy L Thompson MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs() 1809db77db73SJeremy L Thompson 1810db77db73SJeremy L Thompson Logically collective 1811db77db73SJeremy L Thompson 1812db77db73SJeremy L Thompson Input Parameters: 1813db77db73SJeremy L Thompson + mat - the shell matrix 1814db77db73SJeremy L Thompson - vtype - type to use for creating vectors 1815db77db73SJeremy L Thompson 1816db77db73SJeremy L Thompson Notes: 1817db77db73SJeremy L Thompson 1818db77db73SJeremy L Thompson Level: advanced 1819db77db73SJeremy L Thompson 1820db77db73SJeremy L Thompson .seealso: MatCreateVecs() 1821db77db73SJeremy L Thompson @*/ 1822db77db73SJeremy L Thompson PetscErrorCode MatShellSetVecType(Mat mat,VecType vtype) 1823db77db73SJeremy L Thompson { 1824db77db73SJeremy L Thompson PetscFunctionBegin; 1825*cac4c232SBarry Smith PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype)); 1826db77db73SJeremy L Thompson PetscFunctionReturn(0); 1827db77db73SJeremy L Thompson } 1828db77db73SJeremy L Thompson 18290c0fd78eSBarry Smith /*@ 18300c0fd78eSBarry Smith MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately 18310c0fd78eSBarry Smith after MatCreateShell() 18320c0fd78eSBarry Smith 18330c0fd78eSBarry Smith Logically Collective on Mat 18340c0fd78eSBarry Smith 18350c0fd78eSBarry Smith Input Parameter: 18360c0fd78eSBarry Smith . mat - the shell matrix 18370c0fd78eSBarry Smith 18380c0fd78eSBarry Smith Level: advanced 18390c0fd78eSBarry Smith 18400c0fd78eSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation() 18410c0fd78eSBarry Smith @*/ 18420c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A) 18430c0fd78eSBarry Smith { 18440c0fd78eSBarry Smith PetscFunctionBegin; 18450c0fd78eSBarry Smith PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1846*cac4c232SBarry Smith PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A)); 18470c0fd78eSBarry Smith PetscFunctionReturn(0); 18480c0fd78eSBarry Smith } 18490c0fd78eSBarry Smith 1850c16cb8f2SBarry Smith /*@C 1851f3b1f45cSBarry Smith MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function. 1852f3b1f45cSBarry Smith 1853f3b1f45cSBarry Smith Logically Collective on Mat 1854f3b1f45cSBarry Smith 1855f3b1f45cSBarry Smith Input Parameters: 1856f3b1f45cSBarry Smith + mat - the shell matrix 1857f3b1f45cSBarry Smith . f - the function 1858f3b1f45cSBarry Smith . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1859f3b1f45cSBarry Smith - ctx - an optional context for the function 1860f3b1f45cSBarry Smith 1861f3b1f45cSBarry Smith Output Parameter: 1862f3b1f45cSBarry Smith . flg - PETSC_TRUE if the multiply is likely correct 1863f3b1f45cSBarry Smith 1864f3b1f45cSBarry Smith Options Database: 1865f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1866f3b1f45cSBarry Smith 1867f3b1f45cSBarry Smith Level: advanced 1868f3b1f45cSBarry Smith 186995452b02SPatrick Sanan Fortran Notes: 187095452b02SPatrick Sanan Not supported from Fortran 1871f3b1f45cSBarry Smith 1872f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose() 1873f3b1f45cSBarry Smith @*/ 1874f3b1f45cSBarry Smith PetscErrorCode MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1875f3b1f45cSBarry Smith { 1876f3b1f45cSBarry Smith PetscInt m,n; 1877f3b1f45cSBarry Smith Mat mf,Dmf,Dmat,Ddiff; 1878f3b1f45cSBarry Smith PetscReal Diffnorm,Dmfnorm; 187974e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1880f3b1f45cSBarry Smith 1881f3b1f45cSBarry Smith PetscFunctionBegin; 1882f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 18839566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v)); 18849566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat,&m,&n)); 18859566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf)); 18869566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf,f,ctx)); 18879566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf,base,NULL)); 1888f3b1f45cSBarry Smith 18899566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf)); 18909566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mat,MATAIJ,&Dmat)); 1891f3b1f45cSBarry Smith 18929566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff)); 18939566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN)); 18949566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm)); 18959566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm)); 1896f3b1f45cSBarry Smith if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 1897f3b1f45cSBarry Smith flag = PETSC_FALSE; 1898f3b1f45cSBarry Smith if (v) { 18999566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm))); 19009566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view")); 19019566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view")); 19029566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view")); 1903f3b1f45cSBarry Smith } 1904f3b1f45cSBarry Smith } else if (v) { 19059566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n")); 1906f3b1f45cSBarry Smith } 1907f3b1f45cSBarry Smith if (flg) *flg = flag; 19089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19099566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19119566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 1912f3b1f45cSBarry Smith PetscFunctionReturn(0); 1913f3b1f45cSBarry Smith } 1914f3b1f45cSBarry Smith 1915f3b1f45cSBarry Smith /*@C 19167301b172SPierre Jolivet MatShellTestMultTranspose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function. 1917f3b1f45cSBarry Smith 1918f3b1f45cSBarry Smith Logically Collective on Mat 1919f3b1f45cSBarry Smith 1920f3b1f45cSBarry Smith Input Parameters: 1921f3b1f45cSBarry Smith + mat - the shell matrix 1922f3b1f45cSBarry Smith . f - the function 1923f3b1f45cSBarry Smith . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 1924f3b1f45cSBarry Smith - ctx - an optional context for the function 1925f3b1f45cSBarry Smith 1926f3b1f45cSBarry Smith Output Parameter: 1927f3b1f45cSBarry Smith . flg - PETSC_TRUE if the multiply is likely correct 1928f3b1f45cSBarry Smith 1929f3b1f45cSBarry Smith Options Database: 1930f3b1f45cSBarry Smith . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 1931f3b1f45cSBarry Smith 1932f3b1f45cSBarry Smith Level: advanced 1933f3b1f45cSBarry Smith 193495452b02SPatrick Sanan Fortran Notes: 193595452b02SPatrick Sanan Not supported from Fortran 1936f3b1f45cSBarry Smith 1937f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult() 1938f3b1f45cSBarry Smith @*/ 1939f3b1f45cSBarry Smith PetscErrorCode MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 1940f3b1f45cSBarry Smith { 1941f3b1f45cSBarry Smith Vec x,y,z; 1942f3b1f45cSBarry Smith PetscInt m,n,M,N; 1943f3b1f45cSBarry Smith Mat mf,Dmf,Dmat,Ddiff; 1944f3b1f45cSBarry Smith PetscReal Diffnorm,Dmfnorm; 194574e5cdcaSBarry Smith PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 1946f3b1f45cSBarry Smith 1947f3b1f45cSBarry Smith PetscFunctionBegin; 1948f3b1f45cSBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 19499566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v)); 19509566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(mat,&x,&y)); 19519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(y,&z)); 19529566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat,&m,&n)); 19539566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat,&M,&N)); 19549566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf)); 19559566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(mf,f,ctx)); 19569566063dSJacob Faibussowitsch PetscCall(MatMFFDSetBase(mf,base,NULL)); 19579566063dSJacob Faibussowitsch PetscCall(MatComputeOperator(mf,MATAIJ,&Dmf)); 19589566063dSJacob Faibussowitsch PetscCall(MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf)); 19599566063dSJacob Faibussowitsch PetscCall(MatComputeOperatorTranspose(mat,MATAIJ,&Dmat)); 1960f3b1f45cSBarry Smith 19619566063dSJacob Faibussowitsch PetscCall(MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff)); 19629566063dSJacob Faibussowitsch PetscCall(MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN)); 19639566063dSJacob Faibussowitsch PetscCall(MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm)); 19649566063dSJacob Faibussowitsch PetscCall(MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm)); 1965f3b1f45cSBarry Smith if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 1966f3b1f45cSBarry Smith flag = PETSC_FALSE; 1967f3b1f45cSBarry Smith if (v) { 19689566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm))); 19699566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view")); 19709566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view")); 19719566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view")); 1972f3b1f45cSBarry Smith } 1973f3b1f45cSBarry Smith } else if (v) { 19749566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n")); 1975f3b1f45cSBarry Smith } 1976f3b1f45cSBarry Smith if (flg) *flg = flag; 19779566063dSJacob Faibussowitsch PetscCall(MatDestroy(&mf)); 19789566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmat)); 19799566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ddiff)); 19809566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Dmf)); 19819566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 19829566063dSJacob Faibussowitsch PetscCall(VecDestroy(&y)); 19839566063dSJacob Faibussowitsch PetscCall(VecDestroy(&z)); 1984f3b1f45cSBarry Smith PetscFunctionReturn(0); 1985f3b1f45cSBarry Smith } 1986f3b1f45cSBarry Smith 1987f3b1f45cSBarry Smith /*@C 19880c0fd78eSBarry Smith MatShellSetOperation - Allows user to set a matrix operation for a shell matrix. 1989e51e0e81SBarry Smith 19903f9fe445SBarry Smith Logically Collective on Mat 1991fee21e36SBarry Smith 1992c7fcc2eaSBarry Smith Input Parameters: 1993c7fcc2eaSBarry Smith + mat - the shell matrix 1994c7fcc2eaSBarry Smith . op - the name of the operation 1995789d8953SBarry Smith - g - the function that provides the operation. 1996c7fcc2eaSBarry Smith 199715091d37SBarry Smith Level: advanced 199815091d37SBarry Smith 1999fae171e0SBarry Smith Usage: 2000e93bc3c1Svictor $ extern PetscErrorCode usermult(Mat,Vec,Vec); 2001b77ba244SStefano Zampini $ MatCreateShell(comm,m,n,M,N,ctx,&A); 2002b77ba244SStefano Zampini $ MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 20030b627109SLois Curfman McInnes 2004a62d957aSLois Curfman McInnes Notes: 2005e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 20061c1c02c0SLois Curfman McInnes operations, which all have the form MATOP_<OPERATION>, where 2007a62d957aSLois Curfman McInnes <OPERATION> is the name (in all capital letters) of the 20081c1c02c0SLois Curfman McInnes user interface routine (e.g., MatMult() -> MATOP_MULT). 2009a62d957aSLois Curfman McInnes 2010a4d85fd7SBarry Smith All user-provided functions (except for MATOP_DESTROY) should have the same calling 2011deebb3c3SLois Curfman McInnes sequence as the usual matrix interface routines, since they 2012deebb3c3SLois Curfman McInnes are intended to be accessed via the usual matrix interface 2013deebb3c3SLois Curfman McInnes routines, e.g., 2014a62d957aSLois Curfman McInnes $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2015a62d957aSLois Curfman McInnes 20164aa34b0aSBarry Smith In particular each function MUST return an error code of 0 on success and 20174aa34b0aSBarry Smith nonzero on failure. 20184aa34b0aSBarry Smith 2019a62d957aSLois Curfman McInnes Within each user-defined routine, the user should call 2020a62d957aSLois Curfman McInnes MatShellGetContext() to obtain the user-defined context that was 2021a62d957aSLois Curfman McInnes set by MatCreateShell(). 2022a62d957aSLois Curfman McInnes 2023b77ba244SStefano Zampini Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation() 2024b77ba244SStefano Zampini 202595452b02SPatrick Sanan Fortran Notes: 202695452b02SPatrick Sanan For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not 2027c4762a1bSJed Brown generate a matrix. See src/mat/tests/ex120f.F 2028501d9185SBarry Smith 2029b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts(), MatShellSetMatProductOperation() 2030e51e0e81SBarry Smith @*/ 2031789d8953SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void)) 2032e51e0e81SBarry Smith { 20333a40ed3dSBarry Smith PetscFunctionBegin; 20340700a824SBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2035*cac4c232SBarry Smith PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g)); 20363a40ed3dSBarry Smith PetscFunctionReturn(0); 2037e51e0e81SBarry Smith } 2038f0479e8cSBarry Smith 2039d4bb536fSBarry Smith /*@C 2040d4bb536fSBarry Smith MatShellGetOperation - Gets a matrix function for a shell matrix. 2041d4bb536fSBarry Smith 2042c7fcc2eaSBarry Smith Not Collective 2043c7fcc2eaSBarry Smith 2044d4bb536fSBarry Smith Input Parameters: 2045c7fcc2eaSBarry Smith + mat - the shell matrix 2046c7fcc2eaSBarry Smith - op - the name of the operation 2047d4bb536fSBarry Smith 2048d4bb536fSBarry Smith Output Parameter: 2049789d8953SBarry Smith . g - the function that provides the operation. 2050d4bb536fSBarry Smith 205115091d37SBarry Smith Level: advanced 205215091d37SBarry Smith 2053d4bb536fSBarry Smith Notes: 2054e090d566SSatish Balay See the file include/petscmat.h for a complete list of matrix 2055d4bb536fSBarry Smith operations, which all have the form MATOP_<OPERATION>, where 2056d4bb536fSBarry Smith <OPERATION> is the name (in all capital letters) of the 2057d4bb536fSBarry Smith user interface routine (e.g., MatMult() -> MATOP_MULT). 2058d4bb536fSBarry Smith 2059d4bb536fSBarry Smith All user-provided functions have the same calling 2060d4bb536fSBarry Smith sequence as the usual matrix interface routines, since they 2061d4bb536fSBarry Smith are intended to be accessed via the usual matrix interface 2062d4bb536fSBarry Smith routines, e.g., 2063d4bb536fSBarry Smith $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 2064d4bb536fSBarry Smith 2065d4bb536fSBarry Smith Within each user-defined routine, the user should call 2066d4bb536fSBarry Smith MatShellGetContext() to obtain the user-defined context that was 2067d4bb536fSBarry Smith set by MatCreateShell(). 2068d4bb536fSBarry Smith 2069ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 2070d4bb536fSBarry Smith @*/ 2071789d8953SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void)) 2072d4bb536fSBarry Smith { 20733a40ed3dSBarry Smith PetscFunctionBegin; 20740700a824SBarry Smith PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2075*cac4c232SBarry Smith PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g)); 20763a40ed3dSBarry Smith PetscFunctionReturn(0); 2077d4bb536fSBarry Smith } 2078b77ba244SStefano Zampini 2079b77ba244SStefano Zampini /*@ 2080b77ba244SStefano Zampini MatIsShell - Inquires if a matrix is derived from MATSHELL 2081b77ba244SStefano Zampini 2082b77ba244SStefano Zampini Input Parameter: 2083b77ba244SStefano Zampini . mat - the matrix 2084b77ba244SStefano Zampini 2085b77ba244SStefano Zampini Output Parameter: 2086b77ba244SStefano Zampini . flg - the boolean value 2087b77ba244SStefano Zampini 2088b77ba244SStefano Zampini Level: developer 2089b77ba244SStefano Zampini 2090b77ba244SStefano Zampini Notes: in the future, we should allow the object type name to be changed still using the MatShell data structure for other matrices (i.e. MATTRANSPOSEMAT, MATSCHURCOMPLEMENT etc) 2091b77ba244SStefano Zampini 2092b77ba244SStefano Zampini .seealso: MatCreateShell() 2093b77ba244SStefano Zampini @*/ 2094b77ba244SStefano Zampini PetscErrorCode MatIsShell(Mat mat, PetscBool *flg) 2095b77ba244SStefano Zampini { 2096b77ba244SStefano Zampini PetscFunctionBegin; 2097b77ba244SStefano Zampini PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2098dadcf809SJacob Faibussowitsch PetscValidBoolPointer(flg,2); 2099b77ba244SStefano Zampini *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell); 2100b77ba244SStefano Zampini PetscFunctionReturn(0); 2101b77ba244SStefano Zampini } 2102