xref: /petsc/src/mat/impls/shell/shell.c (revision d70f29a362ae60d541be4e9a72e9494be00f9e3d)
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   PetscErrorCode ierr;
7345960306SStefano Zampini 
7445960306SStefano Zampini   PetscFunctionBegin;
7545960306SStefano Zampini   *xx = x;
7645960306SStefano Zampini   if (shell->zrows) {
7745960306SStefano Zampini     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
7845960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
7945960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8045960306SStefano Zampini     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
8145960306SStefano Zampini   }
8245960306SStefano Zampini   if (shell->zcols) {
8345960306SStefano Zampini     if (!shell->right_work) {
8445960306SStefano Zampini       ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);
8545960306SStefano Zampini     }
8645960306SStefano Zampini     ierr = VecCopy(x,shell->right_work);CHKERRQ(ierr);
8745960306SStefano Zampini     ierr = VecISSet(shell->right_work,shell->zcols,0.0);CHKERRQ(ierr);
8845960306SStefano Zampini     *xx  = shell->right_work;
8945960306SStefano Zampini   }
9045960306SStefano Zampini   PetscFunctionReturn(0);
9145960306SStefano Zampini }
9245960306SStefano Zampini 
9345960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
9445960306SStefano Zampini static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x)
9545960306SStefano Zampini {
9645960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
9745960306SStefano Zampini   PetscErrorCode ierr;
9845960306SStefano Zampini 
9945960306SStefano Zampini   PetscFunctionBegin;
10045960306SStefano Zampini   if (shell->zrows) {
10145960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
10245960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
10345960306SStefano Zampini   }
10445960306SStefano Zampini   PetscFunctionReturn(0);
10545960306SStefano Zampini }
10645960306SStefano Zampini 
10745960306SStefano Zampini /*
10845960306SStefano Zampini      Store and scale values on zeroed rows
10945960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
11045960306SStefano Zampini */
11145960306SStefano Zampini static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx)
11245960306SStefano Zampini {
11345960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
11445960306SStefano Zampini   PetscErrorCode ierr;
11545960306SStefano Zampini 
11645960306SStefano Zampini   PetscFunctionBegin;
11745960306SStefano Zampini   *xx = NULL;
11845960306SStefano Zampini   if (!shell->zrows) {
11945960306SStefano Zampini     *xx = x;
12045960306SStefano Zampini   } else {
12145960306SStefano Zampini     if (!shell->left_work) {
12245960306SStefano Zampini       ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);
12345960306SStefano Zampini     }
12445960306SStefano Zampini     ierr = VecCopy(x,shell->left_work);CHKERRQ(ierr);
12545960306SStefano Zampini     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
12645960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
12745960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
12845960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
12945960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
13045960306SStefano Zampini     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
13145960306SStefano Zampini     *xx  = shell->left_work;
13245960306SStefano Zampini   }
13345960306SStefano Zampini   PetscFunctionReturn(0);
13445960306SStefano Zampini }
13545960306SStefano Zampini 
13645960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
13745960306SStefano Zampini static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x)
13845960306SStefano Zampini {
13945960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
14045960306SStefano Zampini   PetscErrorCode ierr;
14145960306SStefano Zampini 
14245960306SStefano Zampini   PetscFunctionBegin;
14345960306SStefano Zampini   if (shell->zcols) {
14445960306SStefano Zampini     ierr = VecISSet(x,shell->zcols,0.0);CHKERRQ(ierr);
14545960306SStefano Zampini   }
14645960306SStefano Zampini   if (shell->zrows) {
14745960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
14845960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
14945960306SStefano Zampini   }
15045960306SStefano Zampini   PetscFunctionReturn(0);
15145960306SStefano Zampini }
15245960306SStefano Zampini 
1538fe8eb27SJed Brown /*
1540c0fd78eSBarry Smith       xx = diag(left)*x
1558fe8eb27SJed Brown */
1568fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
1578fe8eb27SJed Brown {
1588fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1598fe8eb27SJed Brown   PetscErrorCode ierr;
1608fe8eb27SJed Brown 
1618fe8eb27SJed Brown   PetscFunctionBegin;
1620298fd71SBarry Smith   *xx = NULL;
1638fe8eb27SJed Brown   if (!shell->left) {
1648fe8eb27SJed Brown     *xx = x;
1658fe8eb27SJed Brown   } else {
1668fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
1678fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
1688fe8eb27SJed Brown     *xx  = shell->left_work;
1698fe8eb27SJed Brown   }
1708fe8eb27SJed Brown   PetscFunctionReturn(0);
1718fe8eb27SJed Brown }
1728fe8eb27SJed Brown 
1730c0fd78eSBarry Smith /*
1740c0fd78eSBarry Smith      xx = diag(right)*x
1750c0fd78eSBarry Smith */
1768fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1778fe8eb27SJed Brown {
1788fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1798fe8eb27SJed Brown   PetscErrorCode ierr;
1808fe8eb27SJed Brown 
1818fe8eb27SJed Brown   PetscFunctionBegin;
1820298fd71SBarry Smith   *xx = NULL;
1838fe8eb27SJed Brown   if (!shell->right) {
1848fe8eb27SJed Brown     *xx = x;
1858fe8eb27SJed Brown   } else {
1868fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
1878fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
1888fe8eb27SJed Brown     *xx  = shell->right_work;
1898fe8eb27SJed Brown   }
1908fe8eb27SJed Brown   PetscFunctionReturn(0);
1918fe8eb27SJed Brown }
1928fe8eb27SJed Brown 
1930c0fd78eSBarry Smith /*
1940c0fd78eSBarry Smith     x = diag(left)*x
1950c0fd78eSBarry Smith */
1968fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1978fe8eb27SJed Brown {
1988fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1998fe8eb27SJed Brown   PetscErrorCode ierr;
2008fe8eb27SJed Brown 
2018fe8eb27SJed Brown   PetscFunctionBegin;
2028fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
2038fe8eb27SJed Brown   PetscFunctionReturn(0);
2048fe8eb27SJed Brown }
2058fe8eb27SJed Brown 
2060c0fd78eSBarry Smith /*
2070c0fd78eSBarry Smith     x = diag(right)*x
2080c0fd78eSBarry Smith */
2098fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
2108fe8eb27SJed Brown {
2118fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2128fe8eb27SJed Brown   PetscErrorCode ierr;
2138fe8eb27SJed Brown 
2148fe8eb27SJed Brown   PetscFunctionBegin;
2158fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
2168fe8eb27SJed Brown   PetscFunctionReturn(0);
2178fe8eb27SJed Brown }
2188fe8eb27SJed Brown 
2190c0fd78eSBarry Smith /*
2200c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2210c0fd78eSBarry Smith 
2220c0fd78eSBarry Smith          On input Y already contains A*x
2230c0fd78eSBarry Smith */
2248fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
2258fe8eb27SJed Brown {
2268fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2278fe8eb27SJed Brown   PetscErrorCode ierr;
2288fe8eb27SJed Brown 
2298fe8eb27SJed Brown   PetscFunctionBegin;
2308fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
2318fe8eb27SJed Brown     PetscInt          i,m;
2328fe8eb27SJed Brown     const PetscScalar *x,*d;
2338fe8eb27SJed Brown     PetscScalar       *y;
2348fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
2358fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
2368fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
2378fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
2388fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
2398fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
2408fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
2418fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
2420c0fd78eSBarry Smith   } else {
243027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
2448fe8eb27SJed Brown   }
245d4c7de66SBarry Smith   if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */
2468fe8eb27SJed Brown   PetscFunctionReturn(0);
2478fe8eb27SJed Brown }
248e51e0e81SBarry Smith 
249789d8953SBarry Smith PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx)
250789d8953SBarry Smith {
251789d8953SBarry Smith   PetscFunctionBegin;
252789d8953SBarry Smith   *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
253789d8953SBarry Smith   PetscFunctionReturn(0);
254789d8953SBarry Smith }
255789d8953SBarry Smith 
2569d225801SJed Brown /*@
257a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
258b4fd4287SBarry Smith 
259c7fcc2eaSBarry Smith     Not Collective
260c7fcc2eaSBarry Smith 
261b4fd4287SBarry Smith     Input Parameter:
262b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
263b4fd4287SBarry Smith 
264b4fd4287SBarry Smith     Output Parameter:
265b4fd4287SBarry Smith .   ctx - the user provided context
266b4fd4287SBarry Smith 
26715091d37SBarry Smith     Level: advanced
26815091d37SBarry Smith 
26995452b02SPatrick Sanan    Fortran Notes:
27095452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
271daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
272a62d957aSLois Curfman McInnes 
273ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
2740bc0a719SBarry Smith @*/
2758fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
276b4fd4287SBarry Smith {
277dfbe8321SBarry Smith   PetscErrorCode ierr;
278273d9f13SBarry Smith 
2793a40ed3dSBarry Smith   PetscFunctionBegin;
2800700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2814482741eSBarry Smith   PetscValidPointer(ctx,2);
282789d8953SBarry Smith   ierr = PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr);
2833a40ed3dSBarry Smith   PetscFunctionReturn(0);
284b4fd4287SBarry Smith }
285b4fd4287SBarry Smith 
28645960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)
28745960306SStefano Zampini {
28845960306SStefano Zampini   PetscErrorCode ierr;
28945960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
29045960306SStefano Zampini   Vec            x = NULL,b = NULL;
29145960306SStefano Zampini   IS             is1, is2;
29245960306SStefano Zampini   const PetscInt *ridxs;
29345960306SStefano Zampini   PetscInt       *idxs,*gidxs;
29445960306SStefano Zampini   PetscInt       cum,rst,cst,i;
29545960306SStefano Zampini 
29645960306SStefano Zampini   PetscFunctionBegin;
29745960306SStefano Zampini   if (!shell->zvals) {
29845960306SStefano Zampini     ierr = MatCreateVecs(mat,NULL,&shell->zvals);CHKERRQ(ierr);
29945960306SStefano Zampini   }
30045960306SStefano Zampini   if (!shell->zvals_w) {
30145960306SStefano Zampini     ierr = VecDuplicate(shell->zvals,&shell->zvals_w);CHKERRQ(ierr);
30245960306SStefano Zampini   }
30345960306SStefano Zampini   ierr = MatGetOwnershipRange(mat,&rst,NULL);CHKERRQ(ierr);
30445960306SStefano Zampini   ierr = MatGetOwnershipRangeColumn(mat,&cst,NULL);CHKERRQ(ierr);
30545960306SStefano Zampini 
30645960306SStefano Zampini   /* Expand/create index set of zeroed rows */
30745960306SStefano Zampini   ierr = PetscMalloc1(nr,&idxs);CHKERRQ(ierr);
30845960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
30945960306SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
31045960306SStefano Zampini   ierr = ISSort(is1);CHKERRQ(ierr);
31145960306SStefano Zampini   ierr = VecISSet(shell->zvals,is1,diag);CHKERRQ(ierr);
31245960306SStefano Zampini   if (shell->zrows) {
31345960306SStefano Zampini     ierr = ISSum(shell->zrows,is1,&is2);CHKERRQ(ierr);
31445960306SStefano Zampini     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
31545960306SStefano Zampini     ierr = ISDestroy(&is1);CHKERRQ(ierr);
31645960306SStefano Zampini     shell->zrows = is2;
31745960306SStefano Zampini   } else shell->zrows = is1;
31845960306SStefano Zampini 
31945960306SStefano Zampini   /* Create scatters for diagonal values communications */
32045960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
32145960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
32245960306SStefano Zampini 
32345960306SStefano Zampini   /* row scatter: from/to left vector */
32445960306SStefano Zampini   ierr = MatCreateVecs(mat,&x,&b);CHKERRQ(ierr);
32545960306SStefano Zampini   ierr = VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r);CHKERRQ(ierr);
32645960306SStefano Zampini 
32745960306SStefano Zampini   /* col scatter: from right vector to left vector */
32845960306SStefano Zampini   ierr = ISGetIndices(shell->zrows,&ridxs);CHKERRQ(ierr);
32945960306SStefano Zampini   ierr = ISGetLocalSize(shell->zrows,&nr);CHKERRQ(ierr);
33045960306SStefano Zampini   ierr = PetscMalloc1(nr,&gidxs);CHKERRQ(ierr);
33145960306SStefano Zampini   for (i = 0, cum  = 0; i < nr; i++) {
33245960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
33345960306SStefano Zampini     gidxs[cum] = ridxs[i];
33445960306SStefano Zampini     cum++;
33545960306SStefano Zampini   }
33645960306SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
33745960306SStefano Zampini   ierr = VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c);CHKERRQ(ierr);
33845960306SStefano Zampini   ierr = ISDestroy(&is1);CHKERRQ(ierr);
33945960306SStefano Zampini   ierr = VecDestroy(&x);CHKERRQ(ierr);
34045960306SStefano Zampini   ierr = VecDestroy(&b);CHKERRQ(ierr);
34145960306SStefano Zampini 
34245960306SStefano Zampini   /* Expand/create index set of zeroed columns */
34345960306SStefano Zampini   if (rc) {
34445960306SStefano Zampini     ierr = PetscMalloc1(nc,&idxs);CHKERRQ(ierr);
34545960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
34645960306SStefano Zampini     ierr = ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
34745960306SStefano Zampini     ierr = ISSort(is1);CHKERRQ(ierr);
34845960306SStefano Zampini     if (shell->zcols) {
34945960306SStefano Zampini       ierr = ISSum(shell->zcols,is1,&is2);CHKERRQ(ierr);
35045960306SStefano Zampini       ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
35145960306SStefano Zampini       ierr = ISDestroy(&is1);CHKERRQ(ierr);
35245960306SStefano Zampini       shell->zcols = is2;
35345960306SStefano Zampini     } else shell->zcols = is1;
35445960306SStefano Zampini   }
35545960306SStefano Zampini   PetscFunctionReturn(0);
35645960306SStefano Zampini }
35745960306SStefano Zampini 
35845960306SStefano Zampini static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
35945960306SStefano Zampini {
360ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
36145960306SStefano Zampini   PetscInt       nr, *lrows;
36245960306SStefano Zampini   PetscErrorCode ierr;
36345960306SStefano Zampini 
36445960306SStefano Zampini   PetscFunctionBegin;
36545960306SStefano Zampini   if (x && b) {
36645960306SStefano Zampini     Vec          xt;
36745960306SStefano Zampini     PetscScalar *vals;
36845960306SStefano Zampini     PetscInt    *gcols,i,st,nl,nc;
36945960306SStefano Zampini 
37045960306SStefano Zampini     ierr = PetscMalloc1(n,&gcols);CHKERRQ(ierr);
37145960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
37245960306SStefano Zampini 
37345960306SStefano Zampini     ierr = MatCreateVecs(mat,&xt,NULL);CHKERRQ(ierr);
37445960306SStefano Zampini     ierr = VecCopy(x,xt);CHKERRQ(ierr);
37545960306SStefano Zampini     ierr = PetscCalloc1(nc,&vals);CHKERRQ(ierr);
37645960306SStefano Zampini     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
37745960306SStefano Zampini     ierr = PetscFree(vals);CHKERRQ(ierr);
37845960306SStefano Zampini     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
37945960306SStefano Zampini     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
38045960306SStefano Zampini     ierr = VecAYPX(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, x2] */
38145960306SStefano Zampini 
38245960306SStefano Zampini     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
38345960306SStefano Zampini     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
38445960306SStefano Zampini     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
38545960306SStefano Zampini     for (i = 0; i < nl; i++) {
38645960306SStefano Zampini       PetscInt g = i + st;
38745960306SStefano Zampini       if (g > mat->rmap->N) continue;
38845960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
38945960306SStefano Zampini       ierr = VecSetValue(b,g,diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
39045960306SStefano Zampini     }
39145960306SStefano Zampini     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
39245960306SStefano Zampini     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
39345960306SStefano Zampini     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1, x2 * diag] */
39445960306SStefano Zampini     ierr = VecDestroy(&xt);CHKERRQ(ierr);
39545960306SStefano Zampini     ierr = PetscFree(gcols);CHKERRQ(ierr);
39645960306SStefano Zampini   }
39745960306SStefano Zampini   ierr = PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL);CHKERRQ(ierr);
39845960306SStefano Zampini   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE);CHKERRQ(ierr);
399ef5c7bd2SStefano Zampini   if (shell->axpy) {
400ef5c7bd2SStefano Zampini     ierr = MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL);CHKERRQ(ierr);
401ef5c7bd2SStefano Zampini   }
40245960306SStefano Zampini   ierr = PetscFree(lrows);CHKERRQ(ierr);
40345960306SStefano Zampini   PetscFunctionReturn(0);
40445960306SStefano Zampini }
40545960306SStefano Zampini 
40645960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)
40745960306SStefano Zampini {
408ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
40945960306SStefano Zampini   PetscInt       *lrows, *lcols;
41045960306SStefano Zampini   PetscInt       nr, nc;
41145960306SStefano Zampini   PetscBool      congruent;
41245960306SStefano Zampini   PetscErrorCode ierr;
41345960306SStefano Zampini 
41445960306SStefano Zampini   PetscFunctionBegin;
41545960306SStefano Zampini   if (x && b) {
41645960306SStefano Zampini     Vec          xt, bt;
41745960306SStefano Zampini     PetscScalar *vals;
41845960306SStefano Zampini     PetscInt    *grows,*gcols,i,st,nl;
41945960306SStefano Zampini 
42045960306SStefano Zampini     ierr = PetscMalloc2(n,&grows,n,&gcols);CHKERRQ(ierr);
42145960306SStefano Zampini     for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
42245960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
42345960306SStefano Zampini     ierr = PetscCalloc1(n,&vals);CHKERRQ(ierr);
42445960306SStefano Zampini 
42545960306SStefano Zampini     ierr = MatCreateVecs(mat,&xt,&bt);CHKERRQ(ierr);
42645960306SStefano Zampini     ierr = VecCopy(x,xt);CHKERRQ(ierr);
42745960306SStefano Zampini     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
42845960306SStefano Zampini     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
42945960306SStefano Zampini     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
43045960306SStefano Zampini     ierr = VecAXPY(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, -x2] */
43145960306SStefano Zampini     ierr = MatMult(mat,xt,bt);CHKERRQ(ierr);                           /* bt = [-A12*x2,-A22*x2] */
43245960306SStefano Zampini     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* bt = [-A12*x2,0] */
43345960306SStefano Zampini     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
43445960306SStefano Zampini     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
43545960306SStefano Zampini     ierr = VecAXPY(b,1.0,bt);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, b2] */
43645960306SStefano Zampini     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* b  = [b1 - A12*x2, 0] */
43745960306SStefano Zampini     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
43845960306SStefano Zampini     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
43945960306SStefano Zampini     ierr = PetscFree(vals);CHKERRQ(ierr);
44045960306SStefano Zampini 
44145960306SStefano Zampini     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
44245960306SStefano Zampini     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
44345960306SStefano Zampini     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
44445960306SStefano Zampini     for (i = 0; i < nl; i++) {
44545960306SStefano Zampini       PetscInt g = i + st;
44645960306SStefano Zampini       if (g > mat->rmap->N) continue;
44745960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
44845960306SStefano Zampini       ierr = VecSetValue(b,g,-diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
44945960306SStefano Zampini     }
45045960306SStefano Zampini     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
45145960306SStefano Zampini     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
45245960306SStefano Zampini     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, x2 * diag] */
45345960306SStefano Zampini     ierr = VecDestroy(&xt);CHKERRQ(ierr);
45445960306SStefano Zampini     ierr = VecDestroy(&bt);CHKERRQ(ierr);
45545960306SStefano Zampini     ierr = PetscFree2(grows,gcols);CHKERRQ(ierr);
45645960306SStefano Zampini   }
45745960306SStefano Zampini   ierr = PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL);CHKERRQ(ierr);
45845960306SStefano Zampini   ierr = MatHasCongruentLayouts(mat,&congruent);CHKERRQ(ierr);
45945960306SStefano Zampini   if (congruent) {
46045960306SStefano Zampini     nc    = nr;
46145960306SStefano Zampini     lcols = lrows;
46245960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
46345960306SStefano Zampini     PetscInt i,nt,*t;
46445960306SStefano Zampini 
46545960306SStefano Zampini     ierr = PetscMalloc1(n,&t);CHKERRQ(ierr);
46645960306SStefano Zampini     for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
46745960306SStefano Zampini     ierr = PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL);CHKERRQ(ierr);
46845960306SStefano Zampini     ierr = PetscFree(t);CHKERRQ(ierr);
46945960306SStefano Zampini   }
47045960306SStefano Zampini   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE);CHKERRQ(ierr);
47145960306SStefano Zampini   if (!congruent) {
47245960306SStefano Zampini     ierr = PetscFree(lcols);CHKERRQ(ierr);
47345960306SStefano Zampini   }
47445960306SStefano Zampini   ierr = PetscFree(lrows);CHKERRQ(ierr);
475ef5c7bd2SStefano Zampini   if (shell->axpy) {
476ef5c7bd2SStefano Zampini     ierr = MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL);CHKERRQ(ierr);
477ef5c7bd2SStefano Zampini   }
47845960306SStefano Zampini   PetscFunctionReturn(0);
47945960306SStefano Zampini }
48045960306SStefano Zampini 
481dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
482e51e0e81SBarry Smith {
483dfbe8321SBarry Smith   PetscErrorCode          ierr;
484bf0cc555SLisandro Dalcin   Mat_Shell               *shell = (Mat_Shell*)mat->data;
485b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
486ed3cc1f0SBarry Smith 
4873a40ed3dSBarry Smith   PetscFunctionBegin;
48828f357e3SAlex Fikl   if (shell->ops->destroy) {
48928f357e3SAlex Fikl     ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr);
490bf0cc555SLisandro Dalcin   }
491ef5c7bd2SStefano Zampini   ierr = PetscMemzero(shell->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
4920c0fd78eSBarry Smith   ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
4930c0fd78eSBarry Smith   ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
4940c0fd78eSBarry Smith   ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
4958fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
4968fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
4975edf6516SJed Brown   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
4985edf6516SJed Brown   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
499b77ba244SStefano Zampini   ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr);
500b77ba244SStefano Zampini   ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr);
5019f137db4SBarry Smith   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
50245960306SStefano Zampini   ierr = VecDestroy(&shell->zvals_w);CHKERRQ(ierr);
50345960306SStefano Zampini   ierr = VecDestroy(&shell->zvals);CHKERRQ(ierr);
50445960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
50545960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
50645960306SStefano Zampini   ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
50745960306SStefano Zampini   ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
508b77ba244SStefano Zampini 
509b77ba244SStefano Zampini   matmat = shell->matmat;
510b77ba244SStefano Zampini   while (matmat) {
511b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
512b77ba244SStefano Zampini 
513b77ba244SStefano Zampini     ierr = PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL);CHKERRQ(ierr);
514b77ba244SStefano Zampini     ierr = PetscFree(matmat->composedname);CHKERRQ(ierr);
515b77ba244SStefano Zampini     ierr = PetscFree(matmat->resultname);CHKERRQ(ierr);
516b77ba244SStefano Zampini     ierr = PetscFree(matmat);CHKERRQ(ierr);
517b77ba244SStefano Zampini     matmat = next;
518b77ba244SStefano Zampini   }
519789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL);CHKERRQ(ierr);
520789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL);CHKERRQ(ierr);
521db77db73SJeremy L Thompson   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL);CHKERRQ(ierr);
522789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL);CHKERRQ(ierr);
523789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL);CHKERRQ(ierr);
524789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL);CHKERRQ(ierr);
525b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL);CHKERRQ(ierr);
526b77ba244SStefano Zampini   ierr = PetscFree(mat->data);CHKERRQ(ierr);
527b77ba244SStefano Zampini   PetscFunctionReturn(0);
528b77ba244SStefano Zampini }
529b77ba244SStefano Zampini 
530b77ba244SStefano Zampini typedef struct {
531b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat,Mat,Mat,void*);
532b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void*);
533b77ba244SStefano Zampini   void           *userdata;
534b77ba244SStefano Zampini   Mat            B;
535b77ba244SStefano Zampini   Mat            Bt;
536b77ba244SStefano Zampini   Mat            axpy;
537b77ba244SStefano Zampini } MatMatDataShell;
538b77ba244SStefano Zampini 
539b77ba244SStefano Zampini static PetscErrorCode DestroyMatMatDataShell(void *data)
540b77ba244SStefano Zampini {
541b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
542b77ba244SStefano Zampini   PetscErrorCode ierr;
543b77ba244SStefano Zampini 
544b77ba244SStefano Zampini   PetscFunctionBegin;
545b77ba244SStefano Zampini   if (mmdata->destroy) {
546b77ba244SStefano Zampini     ierr = (*mmdata->destroy)(mmdata->userdata);CHKERRQ(ierr);
547b77ba244SStefano Zampini   }
548b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->B);CHKERRQ(ierr);
549b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->Bt);CHKERRQ(ierr);
550b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->axpy);CHKERRQ(ierr);
551b77ba244SStefano Zampini   ierr = PetscFree(mmdata);CHKERRQ(ierr);
552b77ba244SStefano Zampini   PetscFunctionReturn(0);
553b77ba244SStefano Zampini }
554b77ba244SStefano Zampini 
555b77ba244SStefano Zampini static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
556b77ba244SStefano Zampini {
557b77ba244SStefano Zampini   PetscErrorCode  ierr;
558b77ba244SStefano Zampini   Mat_Product     *product;
559b77ba244SStefano Zampini   Mat             A, B;
560b77ba244SStefano Zampini   MatMatDataShell *mdata;
561b77ba244SStefano Zampini   PetscScalar     zero = 0.0;
562b77ba244SStefano Zampini 
563b77ba244SStefano Zampini   PetscFunctionBegin;
564b77ba244SStefano Zampini   MatCheckProduct(D,1);
565b77ba244SStefano Zampini   product = D->product;
5662c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty");
567b77ba244SStefano Zampini   A = product->A;
568b77ba244SStefano Zampini   B = product->B;
569b77ba244SStefano Zampini   mdata = (MatMatDataShell*)product->data;
570b77ba244SStefano Zampini   if (mdata->numeric) {
571b77ba244SStefano Zampini     Mat_Shell      *shell = (Mat_Shell*)A->data;
572b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
573b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
574b77ba244SStefano Zampini     PetscBool      useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
575b77ba244SStefano Zampini 
576b77ba244SStefano Zampini     if (shell->managescalingshifts) {
5772c71b3e2SJacob Faibussowitsch       PetscCheckFalse(shell->zcols || shell->zrows,PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns");
578b77ba244SStefano Zampini       if (shell->right || shell->left) {
579b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
580b77ba244SStefano Zampini         if (!mdata->B) {
581b77ba244SStefano Zampini           ierr = MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B);CHKERRQ(ierr);
582b77ba244SStefano Zampini         } else {
583b77ba244SStefano Zampini           newB = PETSC_FALSE;
584b77ba244SStefano Zampini         }
585b77ba244SStefano Zampini         ierr = MatCopy(B,mdata->B,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
586b77ba244SStefano Zampini       }
587b77ba244SStefano Zampini       switch (product->type) {
588b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
589b77ba244SStefano Zampini         if (shell->right) {
590b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr);
591b77ba244SStefano Zampini         }
592b77ba244SStefano Zampini         break;
593b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
594b77ba244SStefano Zampini         if (shell->left) {
595b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->left,NULL);CHKERRQ(ierr);
596b77ba244SStefano Zampini         }
597b77ba244SStefano Zampini         break;
598b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
599b77ba244SStefano Zampini         if (shell->right) {
600b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr);
601b77ba244SStefano Zampini         }
602b77ba244SStefano Zampini         break;
603b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
604b77ba244SStefano Zampini         if (shell->right && shell->left) {
605b77ba244SStefano Zampini           PetscBool flg;
606b77ba244SStefano Zampini 
607b77ba244SStefano Zampini           ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr);
6082c71b3e2SJacob Faibussowitsch           PetscCheckFalse(!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);
609b77ba244SStefano Zampini         }
610b77ba244SStefano Zampini         if (shell->right) {
611b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr);
612b77ba244SStefano Zampini         }
613b77ba244SStefano Zampini         break;
614b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
615b77ba244SStefano Zampini         if (shell->right && shell->left) {
616b77ba244SStefano Zampini           PetscBool flg;
617b77ba244SStefano Zampini 
618b77ba244SStefano Zampini           ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr);
6192c71b3e2SJacob Faibussowitsch           PetscCheckFalse(!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);
620b77ba244SStefano Zampini         }
621b77ba244SStefano Zampini         if (shell->right) {
622b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr);
623b77ba244SStefano Zampini         }
624b77ba244SStefano Zampini         break;
62598921bdaSJacob 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);
626b77ba244SStefano Zampini       }
627b77ba244SStefano Zampini     }
628b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
629b77ba244SStefano Zampini     D->product = NULL;
630b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
631b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
632b77ba244SStefano Zampini 
633b77ba244SStefano Zampini     ierr = (*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata);CHKERRQ(ierr);
634b77ba244SStefano Zampini 
635b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
636b77ba244SStefano Zampini     ierr = MatProductClear(D);CHKERRQ(ierr);
637b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
638b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
639b77ba244SStefano Zampini     D->product = product;
640b77ba244SStefano Zampini 
641b77ba244SStefano Zampini     if (shell->managescalingshifts) {
642b77ba244SStefano Zampini       ierr = MatScale(D,shell->vscale);CHKERRQ(ierr);
643b77ba244SStefano Zampini       switch (product->type) {
644b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
645b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
646b77ba244SStefano Zampini         if (shell->left) {
647b77ba244SStefano Zampini           ierr = MatDiagonalScale(D,shell->left,NULL);CHKERRQ(ierr);
648b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
649b77ba244SStefano Zampini             if (!shell->left_work) {ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);}
650b77ba244SStefano Zampini             if (shell->dshift) {
651b77ba244SStefano Zampini               ierr = VecCopy(shell->dshift,shell->left_work);CHKERRQ(ierr);
652b77ba244SStefano Zampini               ierr = VecShift(shell->left_work,shell->vshift);CHKERRQ(ierr);
653b77ba244SStefano Zampini               ierr = VecPointwiseMult(shell->left_work,shell->left_work,shell->left);CHKERRQ(ierr);
654b77ba244SStefano Zampini             } else {
655b77ba244SStefano Zampini               ierr = VecSet(shell->left_work,shell->vshift);CHKERRQ(ierr);
656b77ba244SStefano Zampini             }
657b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
658b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
659b77ba244SStefano Zampini               MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
660b77ba244SStefano Zampini 
661b77ba244SStefano Zampini               ierr = MatTranspose(mdata->B,reuse,&mdata->Bt);CHKERRQ(ierr);
662b77ba244SStefano Zampini               ierr = MatDiagonalScale(mdata->Bt,shell->left_work,NULL);CHKERRQ(ierr);
663b77ba244SStefano Zampini               ierr = MatAXPY(D,1.0,mdata->Bt,str);CHKERRQ(ierr);
664b77ba244SStefano Zampini             } else {
665b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
666b77ba244SStefano Zampini 
667b77ba244SStefano Zampini               ierr = MatDiagonalScale(mdata->B,shell->left_work,NULL);CHKERRQ(ierr);
668b77ba244SStefano Zampini               ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr);
669b77ba244SStefano Zampini             }
670b77ba244SStefano Zampini           }
671b77ba244SStefano Zampini         }
672b77ba244SStefano Zampini         break;
673b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
674b77ba244SStefano Zampini         if (shell->right) {
675b77ba244SStefano Zampini           ierr = MatDiagonalScale(D,shell->right,NULL);CHKERRQ(ierr);
676b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
677b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
678b77ba244SStefano Zampini 
679b77ba244SStefano Zampini             if (!shell->right_work) {ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);}
680b77ba244SStefano Zampini             if (shell->dshift) {
681b77ba244SStefano Zampini               ierr = VecCopy(shell->dshift,shell->right_work);CHKERRQ(ierr);
682b77ba244SStefano Zampini               ierr = VecShift(shell->right_work,shell->vshift);CHKERRQ(ierr);
683b77ba244SStefano Zampini               ierr = VecPointwiseMult(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
684b77ba244SStefano Zampini             } else {
685b77ba244SStefano Zampini               ierr = VecSet(shell->right_work,shell->vshift);CHKERRQ(ierr);
686b77ba244SStefano Zampini             }
687b77ba244SStefano Zampini             ierr = MatDiagonalScale(mdata->B,shell->right_work,NULL);CHKERRQ(ierr);
688b77ba244SStefano Zampini             ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr);
689b77ba244SStefano Zampini           }
690b77ba244SStefano Zampini         }
691b77ba244SStefano Zampini         break;
692b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
693b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
6942c71b3e2SJacob 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);
695b77ba244SStefano Zampini         break;
69698921bdaSJacob 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);
697b77ba244SStefano Zampini       }
698b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
699b77ba244SStefano Zampini         Mat              X;
700b77ba244SStefano Zampini         PetscObjectState axpy_state;
701b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
702b77ba244SStefano Zampini 
7033ec1f749SStefano Zampini         ierr = MatShellGetContext(shell->axpy,&X);CHKERRQ(ierr);
704b77ba244SStefano Zampini         ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
7052c71b3e2SJacob 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,...)");
706b77ba244SStefano Zampini         if (!mdata->axpy) {
707b77ba244SStefano Zampini           str  = DIFFERENT_NONZERO_PATTERN;
708b77ba244SStefano Zampini           ierr = MatProductCreate(shell->axpy,B,NULL,&mdata->axpy);CHKERRQ(ierr);
709b77ba244SStefano Zampini           ierr = MatProductSetType(mdata->axpy,product->type);CHKERRQ(ierr);
710b77ba244SStefano Zampini           ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr);
711b77ba244SStefano Zampini           ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr);
712b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
713b77ba244SStefano Zampini           PetscBool flg;
714b77ba244SStefano Zampini 
715b77ba244SStefano Zampini           ierr = MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy);CHKERRQ(ierr);
716b77ba244SStefano Zampini           ierr = MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg);CHKERRQ(ierr);
717b77ba244SStefano Zampini           if (!flg) {
718b77ba244SStefano Zampini             str  = DIFFERENT_NONZERO_PATTERN;
719b77ba244SStefano Zampini             ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr);
720b77ba244SStefano Zampini             ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr);
721b77ba244SStefano Zampini           }
722b77ba244SStefano Zampini         }
723b77ba244SStefano Zampini         ierr = MatProductNumeric(mdata->axpy);CHKERRQ(ierr);
724b77ba244SStefano Zampini         ierr = MatAXPY(D,shell->axpy_vscale,mdata->axpy,str);CHKERRQ(ierr);
725b77ba244SStefano Zampini       }
726b77ba244SStefano Zampini     }
727b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation");
728b77ba244SStefano Zampini   PetscFunctionReturn(0);
729b77ba244SStefano Zampini }
730b77ba244SStefano Zampini 
731b77ba244SStefano Zampini static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
732b77ba244SStefano Zampini {
733b77ba244SStefano Zampini   PetscErrorCode          ierr;
734b77ba244SStefano Zampini   Mat_Product             *product;
735b77ba244SStefano Zampini   Mat                     A,B;
736b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
737b77ba244SStefano Zampini   Mat_Shell               *shell;
738b77ba244SStefano Zampini   PetscBool               flg;
739b77ba244SStefano Zampini   char                    composedname[256];
740b77ba244SStefano Zampini   MatMatDataShell         *mdata;
741b77ba244SStefano Zampini 
742b77ba244SStefano Zampini   PetscFunctionBegin;
743b77ba244SStefano Zampini   MatCheckProduct(D,1);
744b77ba244SStefano Zampini   product = D->product;
7452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty");
746b77ba244SStefano Zampini   A = product->A;
747b77ba244SStefano Zampini   B = product->B;
748b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
749b77ba244SStefano Zampini   matmat = shell->matmat;
750b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
751b77ba244SStefano Zampini   while (matmat) {
752b77ba244SStefano Zampini     ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr);
753b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
754b77ba244SStefano Zampini     if (flg) break;
755b77ba244SStefano Zampini     matmat = matmat->next;
756b77ba244SStefano Zampini   }
7572c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!flg,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]);
758b77ba244SStefano Zampini   switch (product->type) {
759b77ba244SStefano Zampini   case MATPRODUCT_AB:
760b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);CHKERRQ(ierr);
761b77ba244SStefano Zampini     break;
762b77ba244SStefano Zampini   case MATPRODUCT_AtB:
763b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);CHKERRQ(ierr);
764b77ba244SStefano Zampini     break;
765b77ba244SStefano Zampini   case MATPRODUCT_ABt:
766b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N);CHKERRQ(ierr);
767b77ba244SStefano Zampini     break;
768b77ba244SStefano Zampini   case MATPRODUCT_RARt:
769b77ba244SStefano Zampini     ierr = MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N);CHKERRQ(ierr);
770b77ba244SStefano Zampini     break;
771b77ba244SStefano Zampini   case MATPRODUCT_PtAP:
772b77ba244SStefano Zampini     ierr = MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N);CHKERRQ(ierr);
773b77ba244SStefano Zampini     break;
77498921bdaSJacob 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);
775b77ba244SStefano Zampini   }
776b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
777b77ba244SStefano Zampini   if (matmat->resultname) {
778b77ba244SStefano Zampini     ierr = PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg);CHKERRQ(ierr);
779b77ba244SStefano Zampini     if (!flg) {
780b77ba244SStefano Zampini       ierr = MatSetType(D,matmat->resultname);CHKERRQ(ierr);
781b77ba244SStefano Zampini     }
782b77ba244SStefano Zampini   }
783b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
784b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
785b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
786b77ba244SStefano Zampini   /* attach product data */
787b77ba244SStefano Zampini   ierr = PetscNew(&mdata);CHKERRQ(ierr);
788b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
789b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
790b77ba244SStefano Zampini   if (matmat->symbolic) {
791b77ba244SStefano Zampini     ierr = (*matmat->symbolic)(A,B,D,&mdata->userdata);CHKERRQ(ierr);
792b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
793b77ba244SStefano Zampini     ierr = MatSetUp(D);CHKERRQ(ierr);
794b77ba244SStefano Zampini   }
7952c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase");
7962c71b3e2SJacob Faibussowitsch   PetscCheckFalse(D->product->data,PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase");
797b77ba244SStefano Zampini   D->product->data = mdata;
798b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
799b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
800b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
801b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
802b77ba244SStefano Zampini   PetscFunctionReturn(0);
803b77ba244SStefano Zampini }
804b77ba244SStefano Zampini 
805b77ba244SStefano Zampini static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
806b77ba244SStefano Zampini {
807b77ba244SStefano Zampini   PetscErrorCode          ierr;
808b77ba244SStefano Zampini   Mat_Product             *product;
809b77ba244SStefano Zampini   Mat                     A,B;
810b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
811b77ba244SStefano Zampini   Mat_Shell               *shell;
812b77ba244SStefano Zampini   PetscBool               flg;
813b77ba244SStefano Zampini   char                    composedname[256];
814b77ba244SStefano Zampini 
815b77ba244SStefano Zampini   PetscFunctionBegin;
816b77ba244SStefano Zampini   MatCheckProduct(D,1);
817b77ba244SStefano Zampini   product = D->product;
818b77ba244SStefano Zampini   A = product->A;
819b77ba244SStefano Zampini   B = product->B;
820b77ba244SStefano Zampini   ierr = MatIsShell(A,&flg);CHKERRQ(ierr);
821b77ba244SStefano Zampini   if (!flg) PetscFunctionReturn(0);
822b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
823b77ba244SStefano Zampini   matmat = shell->matmat;
824b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
825b77ba244SStefano Zampini   while (matmat) {
826b77ba244SStefano Zampini     ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr);
827b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
828b77ba244SStefano Zampini     if (flg) break;
829b77ba244SStefano Zampini     matmat = matmat->next;
830b77ba244SStefano Zampini   }
831b77ba244SStefano Zampini   if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; }
8327d3de750SJacob Faibussowitsch   else { ierr = PetscInfo(D,"  symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type]);CHKERRQ(ierr); }
833b77ba244SStefano Zampini   PetscFunctionReturn(0);
834b77ba244SStefano Zampini }
835b77ba244SStefano Zampini 
836b77ba244SStefano 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)
837b77ba244SStefano Zampini {
838b77ba244SStefano Zampini   PetscBool               flg;
839b77ba244SStefano Zampini   PetscErrorCode          ierr;
840b77ba244SStefano Zampini   Mat_Shell               *shell;
841b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
842b77ba244SStefano Zampini 
843b77ba244SStefano Zampini   PetscFunctionBegin;
8442c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine");
8452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!composedname,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name");
846b77ba244SStefano Zampini 
847b77ba244SStefano Zampini   /* add product callback */
848b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
849b77ba244SStefano Zampini   matmat = shell->matmat;
850b77ba244SStefano Zampini   if (!matmat) {
851b77ba244SStefano Zampini     ierr = PetscNew(&shell->matmat);CHKERRQ(ierr);
852b77ba244SStefano Zampini     matmat = shell->matmat;
853b77ba244SStefano Zampini   } else {
854b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
855b77ba244SStefano Zampini     while (entry) {
856b77ba244SStefano Zampini       ierr = PetscStrcmp(composedname,entry->composedname,&flg);CHKERRQ(ierr);
857b77ba244SStefano Zampini       flg  = (PetscBool)(flg && (entry->ptype == ptype));
858843d480fSStefano Zampini       if (flg) goto set;
859b77ba244SStefano Zampini       matmat = entry;
860b77ba244SStefano Zampini       entry = entry->next;
861b77ba244SStefano Zampini     }
862b77ba244SStefano Zampini     ierr = PetscNew(&matmat->next);CHKERRQ(ierr);
863b77ba244SStefano Zampini     matmat = matmat->next;
864b77ba244SStefano Zampini   }
865b77ba244SStefano Zampini 
866843d480fSStefano Zampini set:
867b77ba244SStefano Zampini   matmat->symbolic = symbolic;
868b77ba244SStefano Zampini   matmat->numeric  = numeric;
869b77ba244SStefano Zampini   matmat->destroy  = destroy;
870b77ba244SStefano Zampini   matmat->ptype    = ptype;
871b77ba244SStefano Zampini   ierr = PetscFree(matmat->composedname);CHKERRQ(ierr);
872b77ba244SStefano Zampini   ierr = PetscFree(matmat->resultname);CHKERRQ(ierr);
873b77ba244SStefano Zampini   ierr = PetscStrallocpy(composedname,&matmat->composedname);CHKERRQ(ierr);
874b77ba244SStefano Zampini   ierr = PetscStrallocpy(resultname,&matmat->resultname);CHKERRQ(ierr);
8757d3de750SJacob Faibussowitsch   ierr = PetscInfo(A,"Composing %s for product type %s with result %s\n",matmat->composedname,MatProductTypes[matmat->ptype],matmat->resultname ? matmat->resultname : "not specified");CHKERRQ(ierr);
876b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X);CHKERRQ(ierr);
877b77ba244SStefano Zampini   PetscFunctionReturn(0);
878b77ba244SStefano Zampini }
879b77ba244SStefano Zampini 
880b77ba244SStefano Zampini /*@C
881b77ba244SStefano Zampini     MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix.
882b77ba244SStefano Zampini 
883b77ba244SStefano Zampini    Logically Collective on Mat
884b77ba244SStefano Zampini 
885b77ba244SStefano Zampini     Input Parameters:
886b77ba244SStefano Zampini +   A - the shell matrix
887b77ba244SStefano Zampini .   ptype - the product type
888b77ba244SStefano Zampini .   symbolic - the function for the symbolic phase (can be NULL)
889b77ba244SStefano Zampini .   numeric - the function for the numerical phase
890b77ba244SStefano Zampini .   destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL)
891b77ba244SStefano Zampini .   Btype - the matrix type for the matrix to be multiplied against
892b77ba244SStefano Zampini -   Ctype - the matrix type for the result (can be NULL)
893b77ba244SStefano Zampini 
894b77ba244SStefano Zampini    Level: advanced
895b77ba244SStefano Zampini 
896b77ba244SStefano Zampini     Usage:
897b77ba244SStefano Zampini $      extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**);
898b77ba244SStefano Zampini $      extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*);
899b77ba244SStefano Zampini $      extern PetscErrorCode userdestroy(void*);
900b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
901b77ba244SStefano Zampini $      MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE);
902b77ba244SStefano Zampini $      [ create B of type SEQAIJ etc..]
903b77ba244SStefano Zampini $      MatProductCreate(A,B,NULL,&C);
904b77ba244SStefano Zampini $      MatProductSetType(C,MATPRODUCT_AB);
905b77ba244SStefano Zampini $      MatProductSetFromOptions(C);
906b77ba244SStefano Zampini $      MatProductSymbolic(C); -> actually runs the user defined symbolic operation
907b77ba244SStefano Zampini $      MatProductNumeric(C); -> actually runs the user defined numeric operation
908b77ba244SStefano Zampini $      [ use C = A*B ]
909b77ba244SStefano Zampini 
910b77ba244SStefano Zampini     Notes:
911b77ba244SStefano Zampini     MATPRODUCT_ABC is not supported yet. Not supported in Fortran.
912b77ba244SStefano 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.
913b77ba244SStefano Zampini     Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
914b77ba244SStefano Zampini     PETSc will take care of calling the user-defined callbacks.
915b77ba244SStefano Zampini     It is allowed to specify the same callbacks for different Btype matrix types.
916b77ba244SStefano Zampini     The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence.
917b77ba244SStefano Zampini 
918b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatProductType, MatType, MatSetUp()
919b77ba244SStefano Zampini @*/
920b77ba244SStefano 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)
921b77ba244SStefano Zampini {
922b77ba244SStefano Zampini   PetscErrorCode ierr;
923b77ba244SStefano Zampini 
924b77ba244SStefano Zampini   PetscFunctionBegin;
925b77ba244SStefano Zampini   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
926b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A,ptype,2);
9272c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ptype == MATPRODUCT_ABC,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]);
9282c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!numeric,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4");
929b77ba244SStefano Zampini   PetscValidPointer(Btype,6);
930b77ba244SStefano Zampini   if (Ctype) PetscValidPointer(Ctype,7);
931b77ba244SStefano Zampini   ierr = 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));CHKERRQ(ierr);
932b77ba244SStefano Zampini   PetscFunctionReturn(0);
933b77ba244SStefano Zampini }
934b77ba244SStefano Zampini 
935b77ba244SStefano 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)
936b77ba244SStefano Zampini {
937b77ba244SStefano Zampini   PetscBool      flg;
938b77ba244SStefano Zampini   PetscErrorCode ierr;
939b77ba244SStefano Zampini   char           composedname[256];
940b77ba244SStefano Zampini   MatRootName    Bnames = MatRootNameList, Cnames = MatRootNameList;
941b77ba244SStefano Zampini   PetscMPIInt    size;
942b77ba244SStefano Zampini 
943b77ba244SStefano Zampini   PetscFunctionBegin;
944b77ba244SStefano Zampini   PetscValidType(A,1);
945b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
946b77ba244SStefano Zampini     ierr = PetscStrcmp(Btype,Bnames->rname,&flg);CHKERRQ(ierr);
947b77ba244SStefano Zampini     if (flg) break;
948b77ba244SStefano Zampini     Bnames = Bnames->next;
949b77ba244SStefano Zampini   }
950b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
951b77ba244SStefano Zampini     ierr = PetscStrcmp(Ctype,Cnames->rname,&flg);CHKERRQ(ierr);
952b77ba244SStefano Zampini     if (flg) break;
953b77ba244SStefano Zampini     Cnames = Cnames->next;
954b77ba244SStefano Zampini   }
955ffc4695bSBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRMPI(ierr);
956b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
957b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
958b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype);CHKERRQ(ierr);
959b77ba244SStefano Zampini   ierr = MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype);CHKERRQ(ierr);
9603a40ed3dSBarry Smith   PetscFunctionReturn(0);
961e51e0e81SBarry Smith }
962e51e0e81SBarry Smith 
9637fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
9647fabda3fSAlex Fikl {
96528f357e3SAlex Fikl   Mat_Shell               *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
9667fabda3fSAlex Fikl   PetscErrorCode          ierr;
967cb8c8a77SBarry Smith   PetscBool               matflg;
968b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9697fabda3fSAlex Fikl 
9707fabda3fSAlex Fikl   PetscFunctionBegin;
971b77ba244SStefano Zampini   ierr = MatIsShell(B,&matflg);CHKERRQ(ierr);
9722c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!matflg,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name);
9737fabda3fSAlex Fikl 
974cb8c8a77SBarry Smith   ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
975cb8c8a77SBarry Smith   ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
9767fabda3fSAlex Fikl 
977cb8c8a77SBarry Smith   if (shellA->ops->copy) {
97828f357e3SAlex Fikl     ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr);
979cb8c8a77SBarry Smith   }
9807fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9817fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9820c0fd78eSBarry Smith   if (shellA->dshift) {
9830c0fd78eSBarry Smith     if (!shellB->dshift) {
9840c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr);
9857fabda3fSAlex Fikl     }
9860c0fd78eSBarry Smith     ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr);
9877fabda3fSAlex Fikl   } else {
9889f137db4SBarry Smith     ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr);
9897fabda3fSAlex Fikl   }
9900c0fd78eSBarry Smith   if (shellA->left) {
9910c0fd78eSBarry Smith     if (!shellB->left) {
9920c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr);
9937fabda3fSAlex Fikl     }
9940c0fd78eSBarry Smith     ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr);
9957fabda3fSAlex Fikl   } else {
9969f137db4SBarry Smith     ierr = VecDestroy(&shellB->left);CHKERRQ(ierr);
9977fabda3fSAlex Fikl   }
9980c0fd78eSBarry Smith   if (shellA->right) {
9990c0fd78eSBarry Smith     if (!shellB->right) {
10000c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr);
10017fabda3fSAlex Fikl     }
10020c0fd78eSBarry Smith     ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr);
10037fabda3fSAlex Fikl   } else {
10049f137db4SBarry Smith     ierr = VecDestroy(&shellB->right);CHKERRQ(ierr);
10057fabda3fSAlex Fikl   }
100640e381c3SBarry Smith   ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr);
1007ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
1008ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
100940e381c3SBarry Smith   if (shellA->axpy) {
101040e381c3SBarry Smith     ierr                = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr);
101140e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
101240e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
1013ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
101440e381c3SBarry Smith   }
101545960306SStefano Zampini   if (shellA->zrows) {
101645960306SStefano Zampini     ierr = ISDuplicate(shellA->zrows,&shellB->zrows);CHKERRQ(ierr);
101745960306SStefano Zampini     if (shellA->zcols) {
101845960306SStefano Zampini       ierr = ISDuplicate(shellA->zcols,&shellB->zcols);CHKERRQ(ierr);
101945960306SStefano Zampini     }
102045960306SStefano Zampini     ierr = VecDuplicate(shellA->zvals,&shellB->zvals);CHKERRQ(ierr);
102145960306SStefano Zampini     ierr = VecCopy(shellA->zvals,shellB->zvals);CHKERRQ(ierr);
102245960306SStefano Zampini     ierr = VecDuplicate(shellA->zvals_w,&shellB->zvals_w);CHKERRQ(ierr);
102345960306SStefano Zampini     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_r);CHKERRQ(ierr);
102445960306SStefano Zampini     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_c);CHKERRQ(ierr);
102545960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
102645960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
102745960306SStefano Zampini   }
1028b77ba244SStefano Zampini 
1029b77ba244SStefano Zampini   matmatA = shellA->matmat;
1030b77ba244SStefano Zampini   if (matmatA) {
1031b77ba244SStefano Zampini     while (matmatA->next) {
1032b77ba244SStefano Zampini       ierr = MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname);CHKERRQ(ierr);
1033b77ba244SStefano Zampini       matmatA = matmatA->next;
1034b77ba244SStefano Zampini     }
1035b77ba244SStefano Zampini   }
10367fabda3fSAlex Fikl   PetscFunctionReturn(0);
10377fabda3fSAlex Fikl }
10387fabda3fSAlex Fikl 
1039cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
1040cb8c8a77SBarry Smith {
1041cb8c8a77SBarry Smith   PetscErrorCode ierr;
1042cb8c8a77SBarry Smith   void           *ctx;
1043cb8c8a77SBarry Smith 
1044cb8c8a77SBarry Smith   PetscFunctionBegin;
1045cb8c8a77SBarry Smith   ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr);
1046cb8c8a77SBarry Smith   ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr);
1047b77ba244SStefano Zampini   ierr = PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name);CHKERRQ(ierr);
1048a4b1380bSStefano Zampini   if (op != MAT_DO_NOT_COPY_VALUES) {
1049cb8c8a77SBarry Smith     ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
1050a4b1380bSStefano Zampini   }
1051cb8c8a77SBarry Smith   PetscFunctionReturn(0);
1052cb8c8a77SBarry Smith }
1053cb8c8a77SBarry Smith 
1054dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
1055ef66eb69SBarry Smith {
1056ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
1057dfbe8321SBarry Smith   PetscErrorCode   ierr;
105825578ef6SJed Brown   Vec              xx;
1059e3f487b0SBarry Smith   PetscObjectState instate,outstate;
1060ef66eb69SBarry Smith 
1061ef66eb69SBarry Smith   PetscFunctionBegin;
10622c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!shell->ops->mult,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
106345960306SStefano Zampini   ierr = MatShellPreZeroRight(A,x,&xx);CHKERRQ(ierr);
106445960306SStefano Zampini   ierr = MatShellPreScaleRight(A,xx,&xx);CHKERRQ(ierr);
106545960306SStefano Zampini   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
106628f357e3SAlex Fikl   ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr);
1067e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
1068e3f487b0SBarry Smith   if (instate == outstate) {
1069e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1070e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
1071e3f487b0SBarry Smith   }
10728fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
10738fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
107445960306SStefano Zampini   ierr = MatShellPostZeroLeft(A,y);CHKERRQ(ierr);
10759f137db4SBarry Smith 
10769f137db4SBarry Smith   if (shell->axpy) {
1077ef5c7bd2SStefano Zampini     Mat              X;
1078ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1079ef5c7bd2SStefano Zampini 
10803ec1f749SStefano Zampini     ierr = MatShellGetContext(shell->axpy,&X);CHKERRQ(ierr);
1081ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
10822c71b3e2SJacob 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,...)");
1083b77ba244SStefano Zampini 
1084b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1085b77ba244SStefano Zampini     ierr = VecCopy(x,shell->axpy_right);CHKERRQ(ierr);
1086b77ba244SStefano Zampini     ierr = MatMult(shell->axpy,shell->axpy_right,shell->axpy_left);CHKERRQ(ierr);
1087b77ba244SStefano Zampini     ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr);
10889f137db4SBarry Smith   }
1089ef66eb69SBarry Smith   PetscFunctionReturn(0);
1090ef66eb69SBarry Smith }
1091ef66eb69SBarry Smith 
10925edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
10935edf6516SJed Brown {
10945edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
10955edf6516SJed Brown   PetscErrorCode ierr;
10965edf6516SJed Brown 
10975edf6516SJed Brown   PetscFunctionBegin;
10985edf6516SJed Brown   if (y == z) {
10995edf6516SJed Brown     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
11005edf6516SJed Brown     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
1101b8430d49SBarry Smith     ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr);
11025edf6516SJed Brown   } else {
11035edf6516SJed Brown     ierr = MatMult(A,x,z);CHKERRQ(ierr);
11045edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
11055edf6516SJed Brown   }
11065edf6516SJed Brown   PetscFunctionReturn(0);
11075edf6516SJed Brown }
11085edf6516SJed Brown 
110918be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
111018be62a5SSatish Balay {
111118be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
111218be62a5SSatish Balay   PetscErrorCode   ierr;
111325578ef6SJed Brown   Vec              xx;
1114e3f487b0SBarry Smith   PetscObjectState instate,outstate;
111518be62a5SSatish Balay 
111618be62a5SSatish Balay   PetscFunctionBegin;
11172c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!shell->ops->multtranspose,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
111845960306SStefano Zampini   ierr = MatShellPreZeroLeft(A,x,&xx);CHKERRQ(ierr);
111945960306SStefano Zampini   ierr = MatShellPreScaleLeft(A,xx,&xx);CHKERRQ(ierr);
1120e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
112128f357e3SAlex Fikl   ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr);
1122e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
1123e3f487b0SBarry Smith   if (instate == outstate) {
1124e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1125e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
1126e3f487b0SBarry Smith   }
11278fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
11288fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
112945960306SStefano Zampini   ierr = MatShellPostZeroRight(A,y);CHKERRQ(ierr);
1130350ec83bSStefano Zampini 
1131350ec83bSStefano Zampini   if (shell->axpy) {
1132ef5c7bd2SStefano Zampini     Mat              X;
1133ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1134ef5c7bd2SStefano Zampini 
11353ec1f749SStefano Zampini     ierr = MatShellGetContext(shell->axpy,&X);CHKERRQ(ierr);
1136ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
11372c71b3e2SJacob 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,...)");
1138b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1139b77ba244SStefano Zampini     ierr = VecCopy(x,shell->axpy_left);CHKERRQ(ierr);
1140b77ba244SStefano Zampini     ierr = MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right);CHKERRQ(ierr);
1141b77ba244SStefano Zampini     ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_right);CHKERRQ(ierr);
1142350ec83bSStefano Zampini   }
114318be62a5SSatish Balay   PetscFunctionReturn(0);
114418be62a5SSatish Balay }
114518be62a5SSatish Balay 
11465edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
11475edf6516SJed Brown {
11485edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
11495edf6516SJed Brown   PetscErrorCode ierr;
11505edf6516SJed Brown 
11515edf6516SJed Brown   PetscFunctionBegin;
11525edf6516SJed Brown   if (y == z) {
11535edf6516SJed Brown     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
11545edf6516SJed Brown     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
1155dac989eaS“Marek     ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr);
11565edf6516SJed Brown   } else {
11575edf6516SJed Brown     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
11585edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
11595edf6516SJed Brown   }
11605edf6516SJed Brown   PetscFunctionReturn(0);
11615edf6516SJed Brown }
11625edf6516SJed Brown 
11630c0fd78eSBarry Smith /*
11640c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11650c0fd78eSBarry Smith */
116618be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
116718be62a5SSatish Balay {
116818be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
116918be62a5SSatish Balay   PetscErrorCode ierr;
117018be62a5SSatish Balay 
117118be62a5SSatish Balay   PetscFunctionBegin;
11720c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
117328f357e3SAlex Fikl     ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr);
1174305211d5SBarry 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,...)");
117518be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
11768fe8eb27SJed Brown   if (shell->dshift) {
11770c0fd78eSBarry Smith     ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr);
117818be62a5SSatish Balay   }
11790c0fd78eSBarry Smith   ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
11808fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
11818fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
118245960306SStefano Zampini   if (shell->zrows) {
118345960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
118445960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
118545960306SStefano Zampini   }
118681c02519SBarry Smith   if (shell->axpy) {
1187ef5c7bd2SStefano Zampini     Mat              X;
1188ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1189ef5c7bd2SStefano Zampini 
11903ec1f749SStefano Zampini     ierr = MatShellGetContext(shell->axpy,&X);CHKERRQ(ierr);
1191ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
11922c71b3e2SJacob 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,...)");
1193b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1194b77ba244SStefano Zampini     ierr = MatGetDiagonal(shell->axpy,shell->axpy_left);CHKERRQ(ierr);
1195b77ba244SStefano Zampini     ierr = VecAXPY(v,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr);
119681c02519SBarry Smith   }
119718be62a5SSatish Balay   PetscFunctionReturn(0);
119818be62a5SSatish Balay }
119918be62a5SSatish Balay 
1200f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
1201ef66eb69SBarry Smith {
1202ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12038fe8eb27SJed Brown   PetscErrorCode ierr;
1204789d8953SBarry Smith   PetscBool      flg;
1205b24ad042SBarry Smith 
1206ef66eb69SBarry Smith   PetscFunctionBegin;
1207789d8953SBarry Smith   ierr = MatHasCongruentLayouts(Y,&flg);CHKERRQ(ierr);
12082c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!flg,PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent");
12090c0fd78eSBarry Smith   if (shell->left || shell->right) {
12108fe8eb27SJed Brown     if (!shell->dshift) {
12110c0fd78eSBarry Smith       ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr);
12120c0fd78eSBarry Smith       ierr = VecSet(shell->dshift,a);CHKERRQ(ierr);
12130c0fd78eSBarry Smith     } else {
12140c0fd78eSBarry Smith       if (shell->left)  {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
12150c0fd78eSBarry Smith       if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
12169f137db4SBarry Smith       ierr = VecShift(shell->dshift,a);CHKERRQ(ierr);
12170c0fd78eSBarry Smith     }
12188fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
12198fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
12208fe8eb27SJed Brown   } else shell->vshift += a;
122145960306SStefano Zampini   if (shell->zrows) {
122245960306SStefano Zampini     ierr = VecShift(shell->zvals,a);CHKERRQ(ierr);
122345960306SStefano Zampini   }
1224ef66eb69SBarry Smith   PetscFunctionReturn(0);
1225ef66eb69SBarry Smith }
1226ef66eb69SBarry Smith 
1227b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
12286464bf51SAlex Fikl {
12296464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
12306464bf51SAlex Fikl   PetscErrorCode ierr;
12316464bf51SAlex Fikl 
12326464bf51SAlex Fikl   PetscFunctionBegin;
12330c0fd78eSBarry Smith   if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);}
12340c0fd78eSBarry Smith   if (shell->left || shell->right) {
123592fabd1fSBarry Smith     if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);}
12369f137db4SBarry Smith     if (shell->left && shell->right)  {
12379f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
12389f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
12399f137db4SBarry Smith     } else if (shell->left) {
12409f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
12419f137db4SBarry Smith     } else {
12429f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr);
12439f137db4SBarry Smith     }
1244b253ae0bS“Marek     ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr);
12450c0fd78eSBarry Smith   } else {
1246b253ae0bS“Marek     ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr);
1247b253ae0bS“Marek   }
1248b253ae0bS“Marek   PetscFunctionReturn(0);
1249b253ae0bS“Marek }
1250b253ae0bS“Marek 
1251b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
1252b253ae0bS“Marek {
125345960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
1254b253ae0bS“Marek   Vec            d;
1255b253ae0bS“Marek   PetscErrorCode ierr;
1256789d8953SBarry Smith   PetscBool      flg;
1257b253ae0bS“Marek 
1258b253ae0bS“Marek   PetscFunctionBegin;
1259789d8953SBarry Smith   ierr = MatHasCongruentLayouts(A,&flg);CHKERRQ(ierr);
12602c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!flg,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent");
1261b253ae0bS“Marek   if (ins == INSERT_VALUES) {
12622c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!A->ops->getdiagonal,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
1263b253ae0bS“Marek     ierr = VecDuplicate(D,&d);CHKERRQ(ierr);
1264b253ae0bS“Marek     ierr = MatGetDiagonal(A,d);CHKERRQ(ierr);
1265b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr);
1266b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
1267b253ae0bS“Marek     ierr = VecDestroy(&d);CHKERRQ(ierr);
126845960306SStefano Zampini     if (shell->zrows) {
126945960306SStefano Zampini       ierr = VecCopy(D,shell->zvals);CHKERRQ(ierr);
127045960306SStefano Zampini     }
1271b253ae0bS“Marek   } else {
1272b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
127345960306SStefano Zampini     if (shell->zrows) {
127445960306SStefano Zampini       ierr = VecAXPY(shell->zvals,1.0,D);CHKERRQ(ierr);
127545960306SStefano Zampini     }
12766464bf51SAlex Fikl   }
12776464bf51SAlex Fikl   PetscFunctionReturn(0);
12786464bf51SAlex Fikl }
12796464bf51SAlex Fikl 
1280f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
1281ef66eb69SBarry Smith {
1282ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12838fe8eb27SJed Brown   PetscErrorCode ierr;
1284b24ad042SBarry Smith 
1285ef66eb69SBarry Smith   PetscFunctionBegin;
1286f4df32b1SMatthew Knepley   shell->vscale *= a;
12870c0fd78eSBarry Smith   shell->vshift *= a;
12882205254eSKarl Rupp   if (shell->dshift) {
12892205254eSKarl Rupp     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
12900c0fd78eSBarry Smith   }
129181c02519SBarry Smith   shell->axpy_vscale *= a;
129245960306SStefano Zampini   if (shell->zrows) {
129345960306SStefano Zampini     ierr = VecScale(shell->zvals,a);CHKERRQ(ierr);
129445960306SStefano Zampini   }
12958fe8eb27SJed Brown   PetscFunctionReturn(0);
129618be62a5SSatish Balay }
12978fe8eb27SJed Brown 
12988fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
12998fe8eb27SJed Brown {
13008fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13018fe8eb27SJed Brown   PetscErrorCode ierr;
13028fe8eb27SJed Brown 
13038fe8eb27SJed Brown   PetscFunctionBegin;
13048fe8eb27SJed Brown   if (left) {
13050c0fd78eSBarry Smith     if (!shell->left) {
13060c0fd78eSBarry Smith       ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr);
13078fe8eb27SJed Brown       ierr = VecCopy(left,shell->left);CHKERRQ(ierr);
13080c0fd78eSBarry Smith     } else {
13090c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
131018be62a5SSatish Balay     }
131145960306SStefano Zampini     if (shell->zrows) {
131245960306SStefano Zampini       ierr = VecPointwiseMult(shell->zvals,shell->zvals,left);CHKERRQ(ierr);
131345960306SStefano Zampini     }
1314ef66eb69SBarry Smith   }
13158fe8eb27SJed Brown   if (right) {
13160c0fd78eSBarry Smith     if (!shell->right) {
13170c0fd78eSBarry Smith       ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr);
13188fe8eb27SJed Brown       ierr = VecCopy(right,shell->right);CHKERRQ(ierr);
13190c0fd78eSBarry Smith     } else {
13200c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
13218fe8eb27SJed Brown     }
132245960306SStefano Zampini     if (shell->zrows) {
132345960306SStefano Zampini       if (!shell->left_work) {
132445960306SStefano Zampini         ierr = MatCreateVecs(Y,NULL,&shell->left_work);CHKERRQ(ierr);
132545960306SStefano Zampini       }
132645960306SStefano Zampini       ierr = VecSet(shell->zvals_w,1.0);CHKERRQ(ierr);
132745960306SStefano Zampini       ierr = VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
132845960306SStefano Zampini       ierr = VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
132945960306SStefano Zampini       ierr = VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w);CHKERRQ(ierr);
133045960306SStefano Zampini     }
13318fe8eb27SJed Brown   }
1332ef5c7bd2SStefano Zampini   if (shell->axpy) {
1333ef5c7bd2SStefano Zampini     ierr = MatDiagonalScale(shell->axpy,left,right);CHKERRQ(ierr);
1334ef5c7bd2SStefano Zampini   }
1335ef66eb69SBarry Smith   PetscFunctionReturn(0);
1336ef66eb69SBarry Smith }
1337ef66eb69SBarry Smith 
1338dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
1339ef66eb69SBarry Smith {
1340ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13410c0fd78eSBarry Smith   PetscErrorCode ierr;
1342ef66eb69SBarry Smith 
1343ef66eb69SBarry Smith   PetscFunctionBegin;
13448fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1345ef66eb69SBarry Smith     shell->vshift = 0.0;
1346ef66eb69SBarry Smith     shell->vscale = 1.0;
1347ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1348ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13490c0fd78eSBarry Smith     ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
13500c0fd78eSBarry Smith     ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
13510c0fd78eSBarry Smith     ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
135281c02519SBarry Smith     ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
1353b77ba244SStefano Zampini     ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr);
1354b77ba244SStefano Zampini     ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr);
135545960306SStefano Zampini     ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
135645960306SStefano Zampini     ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
135745960306SStefano Zampini     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
135845960306SStefano Zampini     ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
1359ef66eb69SBarry Smith   }
1360ef66eb69SBarry Smith   PetscFunctionReturn(0);
1361ef66eb69SBarry Smith }
1362ef66eb69SBarry Smith 
13633b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d)
13643b49f96aSBarry Smith {
13653b49f96aSBarry Smith   PetscFunctionBegin;
13663b49f96aSBarry Smith   *missing = PETSC_FALSE;
13673b49f96aSBarry Smith   PetscFunctionReturn(0);
13683b49f96aSBarry Smith }
13693b49f96aSBarry Smith 
13709f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
13719f137db4SBarry Smith {
13729f137db4SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13739f137db4SBarry Smith   PetscErrorCode ierr;
13749f137db4SBarry Smith 
13759f137db4SBarry Smith   PetscFunctionBegin;
1376ef5c7bd2SStefano Zampini   if (X == Y) {
1377ef5c7bd2SStefano Zampini     ierr = MatScale(Y,1.0 + a);CHKERRQ(ierr);
1378ef5c7bd2SStefano Zampini     PetscFunctionReturn(0);
1379ef5c7bd2SStefano Zampini   }
1380ef5c7bd2SStefano Zampini   if (!shell->axpy) {
1381ef5c7bd2SStefano Zampini     ierr = MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy);CHKERRQ(ierr);
13829f137db4SBarry Smith     shell->axpy_vscale = a;
1383ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&shell->axpy_state);CHKERRQ(ierr);
1384ef5c7bd2SStefano Zampini   } else {
1385ef5c7bd2SStefano Zampini     ierr = MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str);CHKERRQ(ierr);
1386ef5c7bd2SStefano Zampini   }
13879f137db4SBarry Smith   PetscFunctionReturn(0);
13889f137db4SBarry Smith }
13899f137db4SBarry Smith 
1390f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
1391f4259b30SLisandro Dalcin                                        NULL,
1392f4259b30SLisandro Dalcin                                        NULL,
1393f4259b30SLisandro Dalcin                                        NULL,
13940c0fd78eSBarry Smith                                 /* 4*/ MatMultAdd_Shell,
1395f4259b30SLisandro Dalcin                                        NULL,
13960c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1397f4259b30SLisandro Dalcin                                        NULL,
1398f4259b30SLisandro Dalcin                                        NULL,
1399f4259b30SLisandro Dalcin                                        NULL,
1400f4259b30SLisandro Dalcin                                 /*10*/ NULL,
1401f4259b30SLisandro Dalcin                                        NULL,
1402f4259b30SLisandro Dalcin                                        NULL,
1403f4259b30SLisandro Dalcin                                        NULL,
1404f4259b30SLisandro Dalcin                                        NULL,
1405f4259b30SLisandro Dalcin                                 /*15*/ NULL,
1406f4259b30SLisandro Dalcin                                        NULL,
1407f4259b30SLisandro Dalcin                                        NULL,
14088fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1409f4259b30SLisandro Dalcin                                        NULL,
1410f4259b30SLisandro Dalcin                                 /*20*/ NULL,
1411ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1412f4259b30SLisandro Dalcin                                        NULL,
1413f4259b30SLisandro Dalcin                                        NULL,
141445960306SStefano Zampini                                 /*24*/ MatZeroRows_Shell,
1415f4259b30SLisandro Dalcin                                        NULL,
1416f4259b30SLisandro Dalcin                                        NULL,
1417f4259b30SLisandro Dalcin                                        NULL,
1418f4259b30SLisandro Dalcin                                        NULL,
1419f4259b30SLisandro Dalcin                                 /*29*/ NULL,
1420f4259b30SLisandro Dalcin                                        NULL,
1421f4259b30SLisandro Dalcin                                        NULL,
1422f4259b30SLisandro Dalcin                                        NULL,
1423f4259b30SLisandro Dalcin                                        NULL,
1424cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
1425f4259b30SLisandro Dalcin                                        NULL,
1426f4259b30SLisandro Dalcin                                        NULL,
1427f4259b30SLisandro Dalcin                                        NULL,
1428f4259b30SLisandro Dalcin                                        NULL,
14299f137db4SBarry Smith                                 /*39*/ MatAXPY_Shell,
1430f4259b30SLisandro Dalcin                                        NULL,
1431f4259b30SLisandro Dalcin                                        NULL,
1432f4259b30SLisandro Dalcin                                        NULL,
1433cb8c8a77SBarry Smith                                        MatCopy_Shell,
1434f4259b30SLisandro Dalcin                                 /*44*/ NULL,
1435ef66eb69SBarry Smith                                        MatScale_Shell,
1436ef66eb69SBarry Smith                                        MatShift_Shell,
14376464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
143845960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1439f4259b30SLisandro Dalcin                                 /*49*/ NULL,
1440f4259b30SLisandro Dalcin                                        NULL,
1441f4259b30SLisandro Dalcin                                        NULL,
1442f4259b30SLisandro Dalcin                                        NULL,
1443f4259b30SLisandro Dalcin                                        NULL,
1444f4259b30SLisandro Dalcin                                 /*54*/ NULL,
1445f4259b30SLisandro Dalcin                                        NULL,
1446f4259b30SLisandro Dalcin                                        NULL,
1447f4259b30SLisandro Dalcin                                        NULL,
1448f4259b30SLisandro Dalcin                                        NULL,
1449f4259b30SLisandro Dalcin                                 /*59*/ NULL,
1450b9b97703SBarry Smith                                        MatDestroy_Shell,
1451f4259b30SLisandro Dalcin                                        NULL,
1452251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1453f4259b30SLisandro Dalcin                                        NULL,
1454f4259b30SLisandro Dalcin                                 /*64*/ NULL,
1455f4259b30SLisandro Dalcin                                        NULL,
1456f4259b30SLisandro Dalcin                                        NULL,
1457f4259b30SLisandro Dalcin                                        NULL,
1458f4259b30SLisandro Dalcin                                        NULL,
1459f4259b30SLisandro Dalcin                                 /*69*/ NULL,
1460f4259b30SLisandro Dalcin                                        NULL,
1461c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1462f4259b30SLisandro Dalcin                                        NULL,
1463f4259b30SLisandro Dalcin                                        NULL,
1464f4259b30SLisandro Dalcin                                 /*74*/ NULL,
1465f4259b30SLisandro Dalcin                                        NULL,
1466f4259b30SLisandro Dalcin                                        NULL,
1467f4259b30SLisandro Dalcin                                        NULL,
1468f4259b30SLisandro Dalcin                                        NULL,
1469f4259b30SLisandro Dalcin                                 /*79*/ NULL,
1470f4259b30SLisandro Dalcin                                        NULL,
1471f4259b30SLisandro Dalcin                                        NULL,
1472f4259b30SLisandro Dalcin                                        NULL,
1473f4259b30SLisandro Dalcin                                        NULL,
1474f4259b30SLisandro Dalcin                                 /*84*/ NULL,
1475f4259b30SLisandro Dalcin                                        NULL,
1476f4259b30SLisandro Dalcin                                        NULL,
1477f4259b30SLisandro Dalcin                                        NULL,
1478f4259b30SLisandro Dalcin                                        NULL,
1479f4259b30SLisandro Dalcin                                 /*89*/ NULL,
1480f4259b30SLisandro Dalcin                                        NULL,
1481f4259b30SLisandro Dalcin                                        NULL,
1482f4259b30SLisandro Dalcin                                        NULL,
1483f4259b30SLisandro Dalcin                                        NULL,
1484f4259b30SLisandro Dalcin                                 /*94*/ NULL,
1485f4259b30SLisandro Dalcin                                        NULL,
1486f4259b30SLisandro Dalcin                                        NULL,
1487f4259b30SLisandro Dalcin                                        NULL,
1488f4259b30SLisandro Dalcin                                        NULL,
1489f4259b30SLisandro Dalcin                                 /*99*/ NULL,
1490f4259b30SLisandro Dalcin                                        NULL,
1491f4259b30SLisandro Dalcin                                        NULL,
1492f4259b30SLisandro Dalcin                                        NULL,
1493f4259b30SLisandro Dalcin                                        NULL,
1494f4259b30SLisandro Dalcin                                /*104*/ NULL,
1495f4259b30SLisandro Dalcin                                        NULL,
1496f4259b30SLisandro Dalcin                                        NULL,
1497f4259b30SLisandro Dalcin                                        NULL,
1498f4259b30SLisandro Dalcin                                        NULL,
1499f4259b30SLisandro Dalcin                                /*109*/ NULL,
1500f4259b30SLisandro Dalcin                                        NULL,
1501f4259b30SLisandro Dalcin                                        NULL,
1502f4259b30SLisandro Dalcin                                        NULL,
15033b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
1504f4259b30SLisandro Dalcin                                /*114*/ NULL,
1505f4259b30SLisandro Dalcin                                        NULL,
1506f4259b30SLisandro Dalcin                                        NULL,
1507f4259b30SLisandro Dalcin                                        NULL,
1508f4259b30SLisandro Dalcin                                        NULL,
1509f4259b30SLisandro Dalcin                                /*119*/ NULL,
1510f4259b30SLisandro Dalcin                                        NULL,
1511f4259b30SLisandro Dalcin                                        NULL,
1512f4259b30SLisandro Dalcin                                        NULL,
1513f4259b30SLisandro Dalcin                                        NULL,
1514f4259b30SLisandro Dalcin                                /*124*/ NULL,
1515f4259b30SLisandro Dalcin                                        NULL,
1516f4259b30SLisandro Dalcin                                        NULL,
1517f4259b30SLisandro Dalcin                                        NULL,
1518f4259b30SLisandro Dalcin                                        NULL,
1519f4259b30SLisandro Dalcin                                /*129*/ NULL,
1520f4259b30SLisandro Dalcin                                        NULL,
1521f4259b30SLisandro Dalcin                                        NULL,
1522f4259b30SLisandro Dalcin                                        NULL,
1523f4259b30SLisandro Dalcin                                        NULL,
1524f4259b30SLisandro Dalcin                                /*134*/ NULL,
1525f4259b30SLisandro Dalcin                                        NULL,
1526f4259b30SLisandro Dalcin                                        NULL,
1527f4259b30SLisandro Dalcin                                        NULL,
1528f4259b30SLisandro Dalcin                                        NULL,
1529f4259b30SLisandro Dalcin                                /*139*/ NULL,
1530f4259b30SLisandro Dalcin                                        NULL,
1531*d70f29a3SPierre Jolivet                                        NULL,
1532*d70f29a3SPierre Jolivet                                        NULL,
1533*d70f29a3SPierre Jolivet                                        NULL,
1534*d70f29a3SPierre Jolivet                                /*144*/ NULL,
1535*d70f29a3SPierre Jolivet                                        NULL,
1536*d70f29a3SPierre Jolivet                                        NULL,
1537f4259b30SLisandro Dalcin                                        NULL
15383964eb88SJed Brown };
1539273d9f13SBarry Smith 
1540789d8953SBarry Smith PetscErrorCode  MatShellSetContext_Shell(Mat mat,void *ctx)
1541789d8953SBarry Smith {
1542789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell*)mat->data;
1543789d8953SBarry Smith 
1544789d8953SBarry Smith   PetscFunctionBegin;
1545789d8953SBarry Smith   shell->ctx = ctx;
1546789d8953SBarry Smith   PetscFunctionReturn(0);
1547789d8953SBarry Smith }
1548789d8953SBarry Smith 
1549db77db73SJeremy L Thompson static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype)
1550db77db73SJeremy L Thompson {
1551db77db73SJeremy L Thompson   PetscErrorCode ierr;
1552db77db73SJeremy L Thompson 
1553db77db73SJeremy L Thompson   PetscFunctionBegin;
1554db77db73SJeremy L Thompson   ierr = PetscFree(mat->defaultvectype);CHKERRQ(ierr);
1555db77db73SJeremy L Thompson   ierr = PetscStrallocpy(vtype,(char**)&mat->defaultvectype);CHKERRQ(ierr);
1556db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1557db77db73SJeremy L Thompson }
1558db77db73SJeremy L Thompson 
1559789d8953SBarry Smith PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1560789d8953SBarry Smith {
1561789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
1562789d8953SBarry Smith 
1563789d8953SBarry Smith   PetscFunctionBegin;
1564789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1565789d8953SBarry Smith   A->ops->diagonalset   = NULL;
1566789d8953SBarry Smith   A->ops->diagonalscale = NULL;
1567789d8953SBarry Smith   A->ops->scale         = NULL;
1568789d8953SBarry Smith   A->ops->shift         = NULL;
1569789d8953SBarry Smith   A->ops->axpy          = NULL;
1570789d8953SBarry Smith   PetscFunctionReturn(0);
1571789d8953SBarry Smith }
1572789d8953SBarry Smith 
1573789d8953SBarry Smith PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void))
1574789d8953SBarry Smith {
1575feb237baSPierre Jolivet   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1576789d8953SBarry Smith 
1577789d8953SBarry Smith   PetscFunctionBegin;
1578789d8953SBarry Smith   switch (op) {
1579789d8953SBarry Smith   case MATOP_DESTROY:
1580789d8953SBarry Smith     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1581789d8953SBarry Smith     break;
1582789d8953SBarry Smith   case MATOP_VIEW:
1583789d8953SBarry Smith     if (!mat->ops->viewnative) {
1584789d8953SBarry Smith       mat->ops->viewnative = mat->ops->view;
1585789d8953SBarry Smith     }
1586789d8953SBarry Smith     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1587789d8953SBarry Smith     break;
1588789d8953SBarry Smith   case MATOP_COPY:
1589789d8953SBarry Smith     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1590789d8953SBarry Smith     break;
1591789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1592789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1593789d8953SBarry Smith   case MATOP_SHIFT:
1594789d8953SBarry Smith   case MATOP_SCALE:
1595789d8953SBarry Smith   case MATOP_AXPY:
1596789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1597789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
15982c71b3e2SJacob Faibussowitsch     PetscCheckFalse(shell->managescalingshifts,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1599789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1600789d8953SBarry Smith     break;
1601789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1602789d8953SBarry Smith     if (shell->managescalingshifts) {
1603789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1604789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1605789d8953SBarry Smith     } else {
1606789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1607789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
1608789d8953SBarry Smith     }
1609789d8953SBarry Smith     break;
1610789d8953SBarry Smith   case MATOP_MULT:
1611789d8953SBarry Smith     if (shell->managescalingshifts) {
1612789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1613789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1614789d8953SBarry Smith     } else {
1615789d8953SBarry Smith       shell->ops->mult = NULL;
1616789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1617789d8953SBarry Smith     }
1618789d8953SBarry Smith     break;
1619789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1620789d8953SBarry Smith     if (shell->managescalingshifts) {
1621789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1622789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1623789d8953SBarry Smith     } else {
1624789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1625789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1626789d8953SBarry Smith     }
1627789d8953SBarry Smith     break;
1628789d8953SBarry Smith   default:
1629789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1630789d8953SBarry Smith     break;
1631789d8953SBarry Smith   }
1632789d8953SBarry Smith   PetscFunctionReturn(0);
1633789d8953SBarry Smith }
1634789d8953SBarry Smith 
1635789d8953SBarry Smith PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void))
1636789d8953SBarry Smith {
1637789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1638789d8953SBarry Smith 
1639789d8953SBarry Smith   PetscFunctionBegin;
1640789d8953SBarry Smith   switch (op) {
1641789d8953SBarry Smith   case MATOP_DESTROY:
1642789d8953SBarry Smith     *f = (void (*)(void))shell->ops->destroy;
1643789d8953SBarry Smith     break;
1644789d8953SBarry Smith   case MATOP_VIEW:
1645789d8953SBarry Smith     *f = (void (*)(void))mat->ops->view;
1646789d8953SBarry Smith     break;
1647789d8953SBarry Smith   case MATOP_COPY:
1648789d8953SBarry Smith     *f = (void (*)(void))shell->ops->copy;
1649789d8953SBarry Smith     break;
1650789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1651789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1652789d8953SBarry Smith   case MATOP_SHIFT:
1653789d8953SBarry Smith   case MATOP_SCALE:
1654789d8953SBarry Smith   case MATOP_AXPY:
1655789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1656789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1657789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1658789d8953SBarry Smith     break;
1659789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1660789d8953SBarry Smith     if (shell->ops->getdiagonal)
1661789d8953SBarry Smith       *f = (void (*)(void))shell->ops->getdiagonal;
1662789d8953SBarry Smith     else
1663789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1664789d8953SBarry Smith     break;
1665789d8953SBarry Smith   case MATOP_MULT:
1666789d8953SBarry Smith     if (shell->ops->mult)
1667789d8953SBarry Smith       *f = (void (*)(void))shell->ops->mult;
1668789d8953SBarry Smith     else
1669789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1670789d8953SBarry Smith     break;
1671789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1672789d8953SBarry Smith     if (shell->ops->multtranspose)
1673789d8953SBarry Smith       *f = (void (*)(void))shell->ops->multtranspose;
1674789d8953SBarry Smith     else
1675789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1676789d8953SBarry Smith     break;
1677789d8953SBarry Smith   default:
1678789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1679789d8953SBarry Smith   }
1680789d8953SBarry Smith   PetscFunctionReturn(0);
1681789d8953SBarry Smith }
1682789d8953SBarry Smith 
16830bad9183SKris Buschelman /*MC
1684fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16850bad9183SKris Buschelman 
16860bad9183SKris Buschelman   Level: advanced
16870bad9183SKris Buschelman 
16880c0fd78eSBarry Smith .seealso: MatCreateShell()
16890bad9183SKris Buschelman M*/
16900bad9183SKris Buschelman 
16918cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1692273d9f13SBarry Smith {
1693273d9f13SBarry Smith   Mat_Shell      *b;
1694dfbe8321SBarry Smith   PetscErrorCode ierr;
1695273d9f13SBarry Smith 
1696273d9f13SBarry Smith   PetscFunctionBegin;
1697273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
1698273d9f13SBarry Smith 
1699b00a9115SJed Brown   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
1700273d9f13SBarry Smith   A->data = (void*)b;
1701273d9f13SBarry Smith 
1702f4259b30SLisandro Dalcin   b->ctx                 = NULL;
1703ef66eb69SBarry Smith   b->vshift              = 0.0;
1704ef66eb69SBarry Smith   b->vscale              = 1.0;
17050c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1706273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1707210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17082205254eSKarl Rupp 
1709789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell);CHKERRQ(ierr);
1710789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell);CHKERRQ(ierr);
1711db77db73SJeremy L Thompson   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell);CHKERRQ(ierr);
1712789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell);CHKERRQ(ierr);
1713789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell);CHKERRQ(ierr);
1714789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell);CHKERRQ(ierr);
1715b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell);CHKERRQ(ierr);
171617667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
1717273d9f13SBarry Smith   PetscFunctionReturn(0);
1718273d9f13SBarry Smith }
1719e51e0e81SBarry Smith 
17204b828684SBarry Smith /*@C
1721052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
1722ff756334SLois Curfman McInnes    private data storage format.
1723e51e0e81SBarry Smith 
1724d083f849SBarry Smith   Collective
1725c7fcc2eaSBarry Smith 
1726e51e0e81SBarry Smith    Input Parameters:
1727c7fcc2eaSBarry Smith +  comm - MPI communicator
1728c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
1729c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
1730c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
1731c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
1732c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
1733e51e0e81SBarry Smith 
1734ff756334SLois Curfman McInnes    Output Parameter:
173544cd7ae7SLois Curfman McInnes .  A - the matrix
1736e51e0e81SBarry Smith 
1737ff2fd236SBarry Smith    Level: advanced
1738ff2fd236SBarry Smith 
1739f39d1f56SLois Curfman McInnes   Usage:
17405bd1e576SStefano Zampini $    extern PetscErrorCode mult(Mat,Vec,Vec);
1741f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
1742c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1743f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
1744f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
1745f39d1f56SLois Curfman McInnes 
1746ff756334SLois Curfman McInnes    Notes:
1747ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
1748ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
1749ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
1750e51e0e81SBarry Smith 
175195452b02SPatrick Sanan    Fortran Notes:
175295452b02SPatrick Sanan     To use this from Fortran with a ctx you must write an interface definition for this
1753daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
1754daf670e6SBarry Smith     in as the ctx argument.
1755f38a8d56SBarry Smith 
1756f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
1757f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
1758645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
1759645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
1760645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
1761645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
1762645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
1763645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
1764645985a0SLois Curfman McInnes    For example,
1765f39d1f56SLois Curfman McInnes 
1766f39d1f56SLois Curfman McInnes $
1767f39d1f56SLois Curfman McInnes $     Vec x, y
17685bd1e576SStefano Zampini $     extern PetscErrorCode mult(Mat,Vec,Vec);
1769645985a0SLois Curfman McInnes $     Mat A
1770f39d1f56SLois Curfman McInnes $
1771c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1772c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1773f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
1774c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
1775c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
1776c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1777645985a0SLois Curfman McInnes $     MatMult(A,x,y);
177845960306SStefano Zampini $     MatDestroy(&A);
177945960306SStefano Zampini $     VecDestroy(&y);
178045960306SStefano Zampini $     VecDestroy(&x);
1781645985a0SLois Curfman McInnes $
1782e51e0e81SBarry Smith 
178345960306SStefano Zampini    MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these
17849b53d762SBarry Smith    operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
17859b53d762SBarry Smith 
17860c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
17870c0fd78eSBarry Smith 
178895452b02SPatrick Sanan     Developers Notes:
178995452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
17900c0fd78eSBarry Smith 
17910c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17920c0fd78eSBarry Smith 
17930c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
17940c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17950c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
17960c0fd78eSBarry Smith 
17970c0fd78eSBarry Smith           A is the user provided function.
17980c0fd78eSBarry Smith 
1799ad2f5c3fSBarry Smith    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
1800ad2f5c3fSBarry Smith    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
1801ad2f5c3fSBarry Smith    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
1802ad2f5c3fSBarry Smith    each time the MATSHELL matrix has changed.
1803ad2f5c3fSBarry Smith 
18047301b172SPierre Jolivet    Matrix product operations (i.e. MatMat, MatTransposeMat etc) can be specified using MatShellSetMatProductOperation()
1805b77ba244SStefano Zampini 
1806ad2f5c3fSBarry Smith    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
1807ad2f5c3fSBarry Smith    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
1808ad2f5c3fSBarry Smith 
1809b77ba244SStefano Zampini .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts(), MatShellSetMatProductOperation()
1810e51e0e81SBarry Smith @*/
18117087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
1812e51e0e81SBarry Smith {
1813dfbe8321SBarry Smith   PetscErrorCode ierr;
1814ed3cc1f0SBarry Smith 
18153a40ed3dSBarry Smith   PetscFunctionBegin;
1816f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
1817f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
1818273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
1819273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
18200fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
1821273d9f13SBarry Smith   PetscFunctionReturn(0);
1822c7fcc2eaSBarry Smith }
1823c7fcc2eaSBarry Smith 
1824c6866cfdSSatish Balay /*@
1825273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
1826c7fcc2eaSBarry Smith 
18273f9fe445SBarry Smith    Logically Collective on Mat
1828c7fcc2eaSBarry Smith 
1829273d9f13SBarry Smith     Input Parameters:
1830273d9f13SBarry Smith +   mat - the shell matrix
1831273d9f13SBarry Smith -   ctx - the context
1832273d9f13SBarry Smith 
1833273d9f13SBarry Smith    Level: advanced
1834273d9f13SBarry Smith 
183595452b02SPatrick Sanan    Fortran Notes:
183695452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
1837daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1838273d9f13SBarry Smith 
1839273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
18400bc0a719SBarry Smith @*/
18417087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
1842273d9f13SBarry Smith {
1843dfbe8321SBarry Smith   PetscErrorCode ierr;
1844273d9f13SBarry Smith 
1845273d9f13SBarry Smith   PetscFunctionBegin;
18460700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1847ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr);
18483a40ed3dSBarry Smith   PetscFunctionReturn(0);
1849e51e0e81SBarry Smith }
1850e51e0e81SBarry Smith 
1851db77db73SJeremy L Thompson /*@C
1852db77db73SJeremy L Thompson  MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs()
1853db77db73SJeremy L Thompson 
1854db77db73SJeremy L Thompson  Logically collective
1855db77db73SJeremy L Thompson 
1856db77db73SJeremy L Thompson     Input Parameters:
1857db77db73SJeremy L Thompson +   mat   - the shell matrix
1858db77db73SJeremy L Thompson -   vtype - type to use for creating vectors
1859db77db73SJeremy L Thompson 
1860db77db73SJeremy L Thompson  Notes:
1861db77db73SJeremy L Thompson 
1862db77db73SJeremy L Thompson  Level: advanced
1863db77db73SJeremy L Thompson 
1864db77db73SJeremy L Thompson .seealso: MatCreateVecs()
1865db77db73SJeremy L Thompson @*/
1866db77db73SJeremy L Thompson PetscErrorCode  MatShellSetVecType(Mat mat,VecType vtype)
1867db77db73SJeremy L Thompson {
1868db77db73SJeremy L Thompson   PetscErrorCode ierr;
1869db77db73SJeremy L Thompson 
1870db77db73SJeremy L Thompson   PetscFunctionBegin;
1871db77db73SJeremy L Thompson   ierr = PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype));CHKERRQ(ierr);
1872db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1873db77db73SJeremy L Thompson }
1874db77db73SJeremy L Thompson 
18750c0fd78eSBarry Smith /*@
18760c0fd78eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
18770c0fd78eSBarry Smith           after MatCreateShell()
18780c0fd78eSBarry Smith 
18790c0fd78eSBarry Smith    Logically Collective on Mat
18800c0fd78eSBarry Smith 
18810c0fd78eSBarry Smith     Input Parameter:
18820c0fd78eSBarry Smith .   mat - the shell matrix
18830c0fd78eSBarry Smith 
18840c0fd78eSBarry Smith   Level: advanced
18850c0fd78eSBarry Smith 
18860c0fd78eSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation()
18870c0fd78eSBarry Smith @*/
18880c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A)
18890c0fd78eSBarry Smith {
18900c0fd78eSBarry Smith   PetscErrorCode ierr;
18910c0fd78eSBarry Smith 
18920c0fd78eSBarry Smith   PetscFunctionBegin;
18930c0fd78eSBarry Smith   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1894ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A));CHKERRQ(ierr);
18950c0fd78eSBarry Smith   PetscFunctionReturn(0);
18960c0fd78eSBarry Smith }
18970c0fd78eSBarry Smith 
1898c16cb8f2SBarry Smith /*@C
1899f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
1900f3b1f45cSBarry Smith 
1901f3b1f45cSBarry Smith    Logically Collective on Mat
1902f3b1f45cSBarry Smith 
1903f3b1f45cSBarry Smith     Input Parameters:
1904f3b1f45cSBarry Smith +   mat - the shell matrix
1905f3b1f45cSBarry Smith .   f - the function
1906f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1907f3b1f45cSBarry Smith -   ctx - an optional context for the function
1908f3b1f45cSBarry Smith 
1909f3b1f45cSBarry Smith    Output Parameter:
1910f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1911f3b1f45cSBarry Smith 
1912f3b1f45cSBarry Smith    Options Database:
1913f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1914f3b1f45cSBarry Smith 
1915f3b1f45cSBarry Smith    Level: advanced
1916f3b1f45cSBarry Smith 
191795452b02SPatrick Sanan    Fortran Notes:
191895452b02SPatrick Sanan     Not supported from Fortran
1919f3b1f45cSBarry Smith 
1920f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose()
1921f3b1f45cSBarry Smith @*/
1922f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1923f3b1f45cSBarry Smith {
1924f3b1f45cSBarry Smith   PetscErrorCode ierr;
1925f3b1f45cSBarry Smith   PetscInt       m,n;
1926f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1927f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
192874e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1929f3b1f45cSBarry Smith 
1930f3b1f45cSBarry Smith   PetscFunctionBegin;
1931f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1932f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr);
1933f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
1934f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr);
1935f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
1936f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
1937f3b1f45cSBarry Smith 
19380bacdadaSStefano Zampini   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
19390bacdadaSStefano Zampini   ierr = MatComputeOperator(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
1940f3b1f45cSBarry Smith 
1941f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
1942f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1943f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
1944f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
1945f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1946f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1947f3b1f45cSBarry Smith     if (v) {
1948fc7aafd1SBarry Smith       ierr = 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));CHKERRQ(ierr);
1949f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1950f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1951f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1952f3b1f45cSBarry Smith     }
1953f3b1f45cSBarry Smith   } else if (v) {
1954fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
1955f3b1f45cSBarry Smith   }
1956f3b1f45cSBarry Smith   if (flg) *flg = flag;
1957f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
1958f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
1959f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
1960f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
1961f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1962f3b1f45cSBarry Smith }
1963f3b1f45cSBarry Smith 
1964f3b1f45cSBarry Smith /*@C
19657301b172SPierre Jolivet     MatShellTestMultTranspose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
1966f3b1f45cSBarry Smith 
1967f3b1f45cSBarry Smith    Logically Collective on Mat
1968f3b1f45cSBarry Smith 
1969f3b1f45cSBarry Smith     Input Parameters:
1970f3b1f45cSBarry Smith +   mat - the shell matrix
1971f3b1f45cSBarry Smith .   f - the function
1972f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1973f3b1f45cSBarry Smith -   ctx - an optional context for the function
1974f3b1f45cSBarry Smith 
1975f3b1f45cSBarry Smith    Output Parameter:
1976f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1977f3b1f45cSBarry Smith 
1978f3b1f45cSBarry Smith    Options Database:
1979f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1980f3b1f45cSBarry Smith 
1981f3b1f45cSBarry Smith    Level: advanced
1982f3b1f45cSBarry Smith 
198395452b02SPatrick Sanan    Fortran Notes:
198495452b02SPatrick Sanan     Not supported from Fortran
1985f3b1f45cSBarry Smith 
1986f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult()
1987f3b1f45cSBarry Smith @*/
1988f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1989f3b1f45cSBarry Smith {
1990f3b1f45cSBarry Smith   PetscErrorCode ierr;
1991f3b1f45cSBarry Smith   Vec            x,y,z;
1992f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
1993f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1994f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
199574e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1996f3b1f45cSBarry Smith 
1997f3b1f45cSBarry Smith   PetscFunctionBegin;
1998f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1999f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr);
2000f3b1f45cSBarry Smith   ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr);
2001f3b1f45cSBarry Smith   ierr = VecDuplicate(y,&z);CHKERRQ(ierr);
2002f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
2003f3b1f45cSBarry Smith   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
2004f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr);
2005f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
2006f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
20070bacdadaSStefano Zampini   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
2008f3b1f45cSBarry Smith   ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr);
20090bacdadaSStefano Zampini   ierr = MatComputeOperatorTranspose(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
2010f3b1f45cSBarry Smith 
2011f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
2012f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
2013f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
2014f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
2015f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
2016f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2017f3b1f45cSBarry Smith     if (v) {
2018fc7aafd1SBarry Smith       ierr = 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));CHKERRQ(ierr);
2019f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2020f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2021f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2022f3b1f45cSBarry Smith     }
2023f3b1f45cSBarry Smith   } else if (v) {
2024fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
2025f3b1f45cSBarry Smith   }
2026f3b1f45cSBarry Smith   if (flg) *flg = flag;
2027f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
2028f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
2029f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
2030f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
2031f3b1f45cSBarry Smith   ierr = VecDestroy(&x);CHKERRQ(ierr);
2032f3b1f45cSBarry Smith   ierr = VecDestroy(&y);CHKERRQ(ierr);
2033f3b1f45cSBarry Smith   ierr = VecDestroy(&z);CHKERRQ(ierr);
2034f3b1f45cSBarry Smith   PetscFunctionReturn(0);
2035f3b1f45cSBarry Smith }
2036f3b1f45cSBarry Smith 
2037f3b1f45cSBarry Smith /*@C
20380c0fd78eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
2039e51e0e81SBarry Smith 
20403f9fe445SBarry Smith    Logically Collective on Mat
2041fee21e36SBarry Smith 
2042c7fcc2eaSBarry Smith     Input Parameters:
2043c7fcc2eaSBarry Smith +   mat - the shell matrix
2044c7fcc2eaSBarry Smith .   op - the name of the operation
2045789d8953SBarry Smith -   g - the function that provides the operation.
2046c7fcc2eaSBarry Smith 
204715091d37SBarry Smith    Level: advanced
204815091d37SBarry Smith 
2049fae171e0SBarry Smith     Usage:
2050e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
2051b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
2052b77ba244SStefano Zampini $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
20530b627109SLois Curfman McInnes 
2054a62d957aSLois Curfman McInnes     Notes:
2055e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
20561c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
2057a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
20581c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
2059a62d957aSLois Curfman McInnes 
2060a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
2061deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
2062deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
2063deebb3c3SLois Curfman McInnes     routines, e.g.,
2064a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2065a62d957aSLois Curfman McInnes 
20664aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
20674aa34b0aSBarry Smith     nonzero on failure.
20684aa34b0aSBarry Smith 
2069a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
2070a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
2071a62d957aSLois Curfman McInnes     set by MatCreateShell().
2072a62d957aSLois Curfman McInnes 
2073b77ba244SStefano Zampini     Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation()
2074b77ba244SStefano Zampini 
207595452b02SPatrick Sanan     Fortran Notes:
207695452b02SPatrick Sanan     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
2077c4762a1bSJed Brown        generate a matrix. See src/mat/tests/ex120f.F
2078501d9185SBarry Smith 
2079b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts(), MatShellSetMatProductOperation()
2080e51e0e81SBarry Smith @*/
2081789d8953SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void))
2082e51e0e81SBarry Smith {
2083976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
2084273d9f13SBarry Smith 
20853a40ed3dSBarry Smith   PetscFunctionBegin;
20860700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2087ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g));CHKERRQ(ierr);
20883a40ed3dSBarry Smith   PetscFunctionReturn(0);
2089e51e0e81SBarry Smith }
2090f0479e8cSBarry Smith 
2091d4bb536fSBarry Smith /*@C
2092d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
2093d4bb536fSBarry Smith 
2094c7fcc2eaSBarry Smith     Not Collective
2095c7fcc2eaSBarry Smith 
2096d4bb536fSBarry Smith     Input Parameters:
2097c7fcc2eaSBarry Smith +   mat - the shell matrix
2098c7fcc2eaSBarry Smith -   op - the name of the operation
2099d4bb536fSBarry Smith 
2100d4bb536fSBarry Smith     Output Parameter:
2101789d8953SBarry Smith .   g - the function that provides the operation.
2102d4bb536fSBarry Smith 
210315091d37SBarry Smith     Level: advanced
210415091d37SBarry Smith 
2105d4bb536fSBarry Smith     Notes:
2106e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
2107d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
2108d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
2109d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
2110d4bb536fSBarry Smith 
2111d4bb536fSBarry Smith     All user-provided functions have the same calling
2112d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
2113d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
2114d4bb536fSBarry Smith     routines, e.g.,
2115d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2116d4bb536fSBarry Smith 
2117d4bb536fSBarry Smith     Within each user-defined routine, the user should call
2118d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
2119d4bb536fSBarry Smith     set by MatCreateShell().
2120d4bb536fSBarry Smith 
2121ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
2122d4bb536fSBarry Smith @*/
2123789d8953SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void))
2124d4bb536fSBarry Smith {
2125976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
2126273d9f13SBarry Smith 
21273a40ed3dSBarry Smith   PetscFunctionBegin;
21280700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2129789d8953SBarry Smith   ierr = PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g));CHKERRQ(ierr);
21303a40ed3dSBarry Smith   PetscFunctionReturn(0);
2131d4bb536fSBarry Smith }
2132b77ba244SStefano Zampini 
2133b77ba244SStefano Zampini /*@
2134b77ba244SStefano Zampini     MatIsShell - Inquires if a matrix is derived from MATSHELL
2135b77ba244SStefano Zampini 
2136b77ba244SStefano Zampini     Input Parameter:
2137b77ba244SStefano Zampini .   mat - the matrix
2138b77ba244SStefano Zampini 
2139b77ba244SStefano Zampini     Output Parameter:
2140b77ba244SStefano Zampini .   flg - the boolean value
2141b77ba244SStefano Zampini 
2142b77ba244SStefano Zampini     Level: developer
2143b77ba244SStefano Zampini 
2144b77ba244SStefano 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)
2145b77ba244SStefano Zampini 
2146b77ba244SStefano Zampini .seealso: MatCreateShell()
2147b77ba244SStefano Zampini @*/
2148b77ba244SStefano Zampini PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2149b77ba244SStefano Zampini {
2150b77ba244SStefano Zampini   PetscFunctionBegin;
2151b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2152b77ba244SStefano Zampini   PetscValidPointer(flg,2);
2153b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
2154b77ba244SStefano Zampini   PetscFunctionReturn(0);
2155b77ba244SStefano Zampini }
2156