xref: /petsc/src/mat/impls/shell/shell.c (revision b77ba24407a1761eadc612ac3e023eac3ec36611)
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 
19*b77ba244SStefano Zampini struct _n_MatShellMatFunctionList {
20*b77ba244SStefano Zampini   PetscErrorCode  (*symbolic)(Mat,Mat,Mat,void**);
21*b77ba244SStefano Zampini   PetscErrorCode  (*numeric)(Mat,Mat,Mat,void*);
22*b77ba244SStefano Zampini   PetscErrorCode  (*destroy)(void*);
23*b77ba244SStefano Zampini   MatProductType  ptype;
24*b77ba244SStefano Zampini   char            *composedname;  /* string to identify routine with double dispatch */
25*b77ba244SStefano Zampini   char            *resultname; /* result matrix type */
26*b77ba244SStefano Zampini 
27*b77ba244SStefano Zampini   struct _n_MatShellMatFunctionList *next;
28*b77ba244SStefano Zampini };
29*b77ba244SStefano Zampini typedef struct _n_MatShellMatFunctionList *MatShellMatFunctionList;
30*b77ba244SStefano Zampini 
3128f357e3SAlex Fikl typedef struct {
3228f357e3SAlex Fikl   struct _MatShellOps ops[1];
332205254eSKarl Rupp 
34*b77ba244SStefano Zampini   /* The user will manage the scaling and shifts for the MATSHELL, not the default */
35*b77ba244SStefano Zampini   PetscBool managescalingshifts;
36*b77ba244SStefano Zampini 
37*b77ba244SStefano 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;
43*b77ba244SStefano Zampini 
44ef5c7bd2SStefano Zampini   /* support for MatAXPY */
459f137db4SBarry Smith   Mat              axpy;
469f137db4SBarry Smith   PetscScalar      axpy_vscale;
47*b77ba244SStefano Zampini   Vec              axpy_left,axpy_right;
48ef5c7bd2SStefano Zampini   PetscObjectState axpy_state;
49*b77ba244SStefano 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;
57*b77ba244SStefano Zampini 
58*b77ba244SStefano Zampini   /* MatMat operations */
59*b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
60*b77ba244SStefano Zampini 
61*b77ba244SStefano Zampini   /* user defined context */
6220563c6bSBarry Smith   void *ctx;
6388cf3e7dSBarry Smith } Mat_Shell;
640c0fd78eSBarry Smith 
6545960306SStefano Zampini 
6645960306SStefano Zampini /*
6745960306SStefano Zampini      Store and scale values on zeroed rows
6845960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed columns
6945960306SStefano Zampini */
7045960306SStefano Zampini static PetscErrorCode MatShellPreZeroRight(Mat A,Vec x,Vec *xx)
7145960306SStefano Zampini {
7245960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
7345960306SStefano Zampini   PetscErrorCode ierr;
7445960306SStefano Zampini 
7545960306SStefano Zampini   PetscFunctionBegin;
7645960306SStefano Zampini   *xx = x;
7745960306SStefano Zampini   if (shell->zrows) {
7845960306SStefano Zampini     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
7945960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8045960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_c,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
8145960306SStefano Zampini     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
8245960306SStefano Zampini   }
8345960306SStefano Zampini   if (shell->zcols) {
8445960306SStefano Zampini     if (!shell->right_work) {
8545960306SStefano Zampini       ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);
8645960306SStefano Zampini     }
8745960306SStefano Zampini     ierr = VecCopy(x,shell->right_work);CHKERRQ(ierr);
8845960306SStefano Zampini     ierr = VecISSet(shell->right_work,shell->zcols,0.0);CHKERRQ(ierr);
8945960306SStefano Zampini     *xx  = shell->right_work;
9045960306SStefano Zampini   }
9145960306SStefano Zampini   PetscFunctionReturn(0);
9245960306SStefano Zampini }
9345960306SStefano Zampini 
9445960306SStefano Zampini /* Insert properly diagonally scaled values stored in MatShellPreZeroRight */
9545960306SStefano Zampini static PetscErrorCode MatShellPostZeroLeft(Mat A,Vec x)
9645960306SStefano Zampini {
9745960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
9845960306SStefano Zampini   PetscErrorCode ierr;
9945960306SStefano Zampini 
10045960306SStefano Zampini   PetscFunctionBegin;
10145960306SStefano Zampini   if (shell->zrows) {
10245960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
10345960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
10445960306SStefano Zampini   }
10545960306SStefano Zampini   PetscFunctionReturn(0);
10645960306SStefano Zampini }
10745960306SStefano Zampini 
10845960306SStefano Zampini /*
10945960306SStefano Zampini      Store and scale values on zeroed rows
11045960306SStefano Zampini      xx = [x_1, 0], 0 on zeroed rows
11145960306SStefano Zampini */
11245960306SStefano Zampini static PetscErrorCode MatShellPreZeroLeft(Mat A,Vec x,Vec *xx)
11345960306SStefano Zampini {
11445960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
11545960306SStefano Zampini   PetscErrorCode ierr;
11645960306SStefano Zampini 
11745960306SStefano Zampini   PetscFunctionBegin;
11845960306SStefano Zampini   *xx = NULL;
11945960306SStefano Zampini   if (!shell->zrows) {
12045960306SStefano Zampini     *xx = x;
12145960306SStefano Zampini   } else {
12245960306SStefano Zampini     if (!shell->left_work) {
12345960306SStefano Zampini       ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);
12445960306SStefano Zampini     }
12545960306SStefano Zampini     ierr = VecCopy(x,shell->left_work);CHKERRQ(ierr);
12645960306SStefano Zampini     ierr = VecSet(shell->zvals_w,0.0);CHKERRQ(ierr);
12745960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
12845960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals_w,shell->left_work,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
12945960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
13045960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,x,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
13145960306SStefano Zampini     ierr = VecPointwiseMult(shell->zvals_w,shell->zvals_w,shell->zvals);CHKERRQ(ierr);
13245960306SStefano Zampini     *xx  = shell->left_work;
13345960306SStefano Zampini   }
13445960306SStefano Zampini   PetscFunctionReturn(0);
13545960306SStefano Zampini }
13645960306SStefano Zampini 
13745960306SStefano Zampini /* Zero zero-columns contributions, sum contributions from properly scaled values stored in MatShellPreZeroLeft */
13845960306SStefano Zampini static PetscErrorCode MatShellPostZeroRight(Mat A,Vec x)
13945960306SStefano Zampini {
14045960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
14145960306SStefano Zampini   PetscErrorCode ierr;
14245960306SStefano Zampini 
14345960306SStefano Zampini   PetscFunctionBegin;
14445960306SStefano Zampini   if (shell->zcols) {
14545960306SStefano Zampini     ierr = VecISSet(x,shell->zcols,0.0);CHKERRQ(ierr);
14645960306SStefano Zampini   }
14745960306SStefano Zampini   if (shell->zrows) {
14845960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
14945960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_c,shell->zvals_w,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
15045960306SStefano Zampini   }
15145960306SStefano Zampini   PetscFunctionReturn(0);
15245960306SStefano Zampini }
15345960306SStefano Zampini 
1548fe8eb27SJed Brown /*
1550c0fd78eSBarry Smith       xx = diag(left)*x
1568fe8eb27SJed Brown */
1578fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
1588fe8eb27SJed Brown {
1598fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1608fe8eb27SJed Brown   PetscErrorCode ierr;
1618fe8eb27SJed Brown 
1628fe8eb27SJed Brown   PetscFunctionBegin;
1630298fd71SBarry Smith   *xx = NULL;
1648fe8eb27SJed Brown   if (!shell->left) {
1658fe8eb27SJed Brown     *xx = x;
1668fe8eb27SJed Brown   } else {
1678fe8eb27SJed Brown     if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);}
1688fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr);
1698fe8eb27SJed Brown     *xx  = shell->left_work;
1708fe8eb27SJed Brown   }
1718fe8eb27SJed Brown   PetscFunctionReturn(0);
1728fe8eb27SJed Brown }
1738fe8eb27SJed Brown 
1740c0fd78eSBarry Smith /*
1750c0fd78eSBarry Smith      xx = diag(right)*x
1760c0fd78eSBarry Smith */
1778fe8eb27SJed Brown static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
1788fe8eb27SJed Brown {
1798fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
1808fe8eb27SJed Brown   PetscErrorCode ierr;
1818fe8eb27SJed Brown 
1828fe8eb27SJed Brown   PetscFunctionBegin;
1830298fd71SBarry Smith   *xx = NULL;
1848fe8eb27SJed Brown   if (!shell->right) {
1858fe8eb27SJed Brown     *xx = x;
1868fe8eb27SJed Brown   } else {
1878fe8eb27SJed Brown     if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);}
1888fe8eb27SJed Brown     ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr);
1898fe8eb27SJed Brown     *xx  = shell->right_work;
1908fe8eb27SJed Brown   }
1918fe8eb27SJed Brown   PetscFunctionReturn(0);
1928fe8eb27SJed Brown }
1938fe8eb27SJed Brown 
1940c0fd78eSBarry Smith /*
1950c0fd78eSBarry Smith     x = diag(left)*x
1960c0fd78eSBarry Smith */
1978fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
1988fe8eb27SJed Brown {
1998fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2008fe8eb27SJed Brown   PetscErrorCode ierr;
2018fe8eb27SJed Brown 
2028fe8eb27SJed Brown   PetscFunctionBegin;
2038fe8eb27SJed Brown   if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);}
2048fe8eb27SJed Brown   PetscFunctionReturn(0);
2058fe8eb27SJed Brown }
2068fe8eb27SJed Brown 
2070c0fd78eSBarry Smith /*
2080c0fd78eSBarry Smith     x = diag(right)*x
2090c0fd78eSBarry Smith */
2108fe8eb27SJed Brown static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
2118fe8eb27SJed Brown {
2128fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2138fe8eb27SJed Brown   PetscErrorCode ierr;
2148fe8eb27SJed Brown 
2158fe8eb27SJed Brown   PetscFunctionBegin;
2168fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);}
2178fe8eb27SJed Brown   PetscFunctionReturn(0);
2188fe8eb27SJed Brown }
2198fe8eb27SJed Brown 
2200c0fd78eSBarry Smith /*
2210c0fd78eSBarry Smith          Y = vscale*Y + diag(dshift)*X + vshift*X
2220c0fd78eSBarry Smith 
2230c0fd78eSBarry Smith          On input Y already contains A*x
2240c0fd78eSBarry Smith */
2258fe8eb27SJed Brown static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
2268fe8eb27SJed Brown {
2278fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
2288fe8eb27SJed Brown   PetscErrorCode ierr;
2298fe8eb27SJed Brown 
2308fe8eb27SJed Brown   PetscFunctionBegin;
2318fe8eb27SJed Brown   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
2328fe8eb27SJed Brown     PetscInt          i,m;
2338fe8eb27SJed Brown     const PetscScalar *x,*d;
2348fe8eb27SJed Brown     PetscScalar       *y;
2358fe8eb27SJed Brown     ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr);
2368fe8eb27SJed Brown     ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr);
2378fe8eb27SJed Brown     ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
2388fe8eb27SJed Brown     ierr = VecGetArray(Y,&y);CHKERRQ(ierr);
2398fe8eb27SJed Brown     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
2408fe8eb27SJed Brown     ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr);
2418fe8eb27SJed Brown     ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
2428fe8eb27SJed Brown     ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr);
2430c0fd78eSBarry Smith   } else {
244027c5fb5SJed Brown     ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr);
2458fe8eb27SJed Brown   }
246d4c7de66SBarry Smith   if (shell->vshift != 0.0) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */
2478fe8eb27SJed Brown   PetscFunctionReturn(0);
2488fe8eb27SJed Brown }
249e51e0e81SBarry Smith 
250789d8953SBarry Smith PetscErrorCode MatShellGetContext_Shell(Mat mat,void *ctx)
251789d8953SBarry Smith {
252789d8953SBarry Smith   PetscFunctionBegin;
253789d8953SBarry Smith   *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
254789d8953SBarry Smith   PetscFunctionReturn(0);
255789d8953SBarry Smith }
256789d8953SBarry Smith 
2579d225801SJed Brown /*@
258a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
259b4fd4287SBarry Smith 
260c7fcc2eaSBarry Smith     Not Collective
261c7fcc2eaSBarry Smith 
262b4fd4287SBarry Smith     Input Parameter:
263b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
264b4fd4287SBarry Smith 
265b4fd4287SBarry Smith     Output Parameter:
266b4fd4287SBarry Smith .   ctx - the user provided context
267b4fd4287SBarry Smith 
26815091d37SBarry Smith     Level: advanced
26915091d37SBarry Smith 
27095452b02SPatrick Sanan    Fortran Notes:
27195452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
272daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
273a62d957aSLois Curfman McInnes 
274ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
2750bc0a719SBarry Smith @*/
2768fe8eb27SJed Brown PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
277b4fd4287SBarry Smith {
278dfbe8321SBarry Smith   PetscErrorCode ierr;
279273d9f13SBarry Smith 
2803a40ed3dSBarry Smith   PetscFunctionBegin;
2810700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2824482741eSBarry Smith   PetscValidPointer(ctx,2);
283789d8953SBarry Smith   ierr = PetscUseMethod(mat,"MatShellGetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr);
2843a40ed3dSBarry Smith   PetscFunctionReturn(0);
285b4fd4287SBarry Smith }
286b4fd4287SBarry Smith 
28745960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Local_Shell(Mat mat,PetscInt nr,PetscInt rows[],PetscInt nc,PetscInt cols[],PetscScalar diag,PetscBool rc)
28845960306SStefano Zampini {
28945960306SStefano Zampini   PetscErrorCode ierr;
29045960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
29145960306SStefano Zampini   Vec            x = NULL,b = NULL;
29245960306SStefano Zampini   IS             is1, is2;
29345960306SStefano Zampini   const PetscInt *ridxs;
29445960306SStefano Zampini   PetscInt       *idxs,*gidxs;
29545960306SStefano Zampini   PetscInt       cum,rst,cst,i;
29645960306SStefano Zampini 
29745960306SStefano Zampini   PetscFunctionBegin;
29845960306SStefano Zampini   if (!shell->zvals) {
29945960306SStefano Zampini     ierr = MatCreateVecs(mat,NULL,&shell->zvals);CHKERRQ(ierr);
30045960306SStefano Zampini   }
30145960306SStefano Zampini   if (!shell->zvals_w) {
30245960306SStefano Zampini     ierr = VecDuplicate(shell->zvals,&shell->zvals_w);CHKERRQ(ierr);
30345960306SStefano Zampini   }
30445960306SStefano Zampini   ierr = MatGetOwnershipRange(mat,&rst,NULL);CHKERRQ(ierr);
30545960306SStefano Zampini   ierr = MatGetOwnershipRangeColumn(mat,&cst,NULL);CHKERRQ(ierr);
30645960306SStefano Zampini 
30745960306SStefano Zampini   /* Expand/create index set of zeroed rows */
30845960306SStefano Zampini   ierr = PetscMalloc1(nr,&idxs);CHKERRQ(ierr);
30945960306SStefano Zampini   for (i = 0; i < nr; i++) idxs[i] = rows[i] + rst;
31045960306SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF,nr,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
31145960306SStefano Zampini   ierr = ISSort(is1);CHKERRQ(ierr);
31245960306SStefano Zampini   ierr = VecISSet(shell->zvals,is1,diag);CHKERRQ(ierr);
31345960306SStefano Zampini   if (shell->zrows) {
31445960306SStefano Zampini     ierr = ISSum(shell->zrows,is1,&is2);CHKERRQ(ierr);
31545960306SStefano Zampini     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
31645960306SStefano Zampini     ierr = ISDestroy(&is1);CHKERRQ(ierr);
31745960306SStefano Zampini     shell->zrows = is2;
31845960306SStefano Zampini   } else shell->zrows = is1;
31945960306SStefano Zampini 
32045960306SStefano Zampini   /* Create scatters for diagonal values communications */
32145960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
32245960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
32345960306SStefano Zampini 
32445960306SStefano Zampini   /* row scatter: from/to left vector */
32545960306SStefano Zampini   ierr = MatCreateVecs(mat,&x,&b);CHKERRQ(ierr);
32645960306SStefano Zampini   ierr = VecScatterCreate(b,shell->zrows,shell->zvals_w,shell->zrows,&shell->zvals_sct_r);CHKERRQ(ierr);
32745960306SStefano Zampini 
32845960306SStefano Zampini   /* col scatter: from right vector to left vector */
32945960306SStefano Zampini   ierr = ISGetIndices(shell->zrows,&ridxs);CHKERRQ(ierr);
33045960306SStefano Zampini   ierr = ISGetLocalSize(shell->zrows,&nr);CHKERRQ(ierr);
33145960306SStefano Zampini   ierr = PetscMalloc1(nr,&gidxs);CHKERRQ(ierr);
33245960306SStefano Zampini   for (i = 0, cum  = 0; i < nr; i++) {
33345960306SStefano Zampini     if (ridxs[i] >= mat->cmap->N) continue;
33445960306SStefano Zampini     gidxs[cum] = ridxs[i];
33545960306SStefano Zampini     cum++;
33645960306SStefano Zampini   }
33745960306SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)mat),cum,gidxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
33845960306SStefano Zampini   ierr = VecScatterCreate(x,is1,shell->zvals_w,is1,&shell->zvals_sct_c);CHKERRQ(ierr);
33945960306SStefano Zampini   ierr = ISDestroy(&is1);CHKERRQ(ierr);
34045960306SStefano Zampini   ierr = VecDestroy(&x);CHKERRQ(ierr);
34145960306SStefano Zampini   ierr = VecDestroy(&b);CHKERRQ(ierr);
34245960306SStefano Zampini 
34345960306SStefano Zampini   /* Expand/create index set of zeroed columns */
34445960306SStefano Zampini   if (rc) {
34545960306SStefano Zampini     ierr = PetscMalloc1(nc,&idxs);CHKERRQ(ierr);
34645960306SStefano Zampini     for (i = 0; i < nc; i++) idxs[i] = cols[i] + cst;
34745960306SStefano Zampini     ierr = ISCreateGeneral(PETSC_COMM_SELF,nc,idxs,PETSC_OWN_POINTER,&is1);CHKERRQ(ierr);
34845960306SStefano Zampini     ierr = ISSort(is1);CHKERRQ(ierr);
34945960306SStefano Zampini     if (shell->zcols) {
35045960306SStefano Zampini       ierr = ISSum(shell->zcols,is1,&is2);CHKERRQ(ierr);
35145960306SStefano Zampini       ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
35245960306SStefano Zampini       ierr = ISDestroy(&is1);CHKERRQ(ierr);
35345960306SStefano Zampini       shell->zcols = is2;
35445960306SStefano Zampini     } else shell->zcols = is1;
35545960306SStefano Zampini   }
35645960306SStefano Zampini   PetscFunctionReturn(0);
35745960306SStefano Zampini }
35845960306SStefano Zampini 
35945960306SStefano Zampini static PetscErrorCode MatZeroRows_Shell(Mat mat,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
36045960306SStefano Zampini {
361ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
36245960306SStefano Zampini   PetscInt       nr, *lrows;
36345960306SStefano Zampini   PetscErrorCode ierr;
36445960306SStefano Zampini 
36545960306SStefano Zampini   PetscFunctionBegin;
36645960306SStefano Zampini   if (x && b) {
36745960306SStefano Zampini     Vec          xt;
36845960306SStefano Zampini     PetscScalar *vals;
36945960306SStefano Zampini     PetscInt    *gcols,i,st,nl,nc;
37045960306SStefano Zampini 
37145960306SStefano Zampini     ierr = PetscMalloc1(n,&gcols);CHKERRQ(ierr);
37245960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rows[i] < mat->cmap->N) gcols[nc++] = rows[i];
37345960306SStefano Zampini 
37445960306SStefano Zampini     ierr = MatCreateVecs(mat,&xt,NULL);CHKERRQ(ierr);
37545960306SStefano Zampini     ierr = VecCopy(x,xt);CHKERRQ(ierr);
37645960306SStefano Zampini     ierr = PetscCalloc1(nc,&vals);CHKERRQ(ierr);
37745960306SStefano Zampini     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
37845960306SStefano Zampini     ierr = PetscFree(vals);CHKERRQ(ierr);
37945960306SStefano Zampini     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
38045960306SStefano Zampini     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
38145960306SStefano Zampini     ierr = VecAYPX(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, x2] */
38245960306SStefano Zampini 
38345960306SStefano Zampini     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
38445960306SStefano Zampini     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
38545960306SStefano Zampini     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
38645960306SStefano Zampini     for (i = 0; i < nl; i++) {
38745960306SStefano Zampini       PetscInt g = i + st;
38845960306SStefano Zampini       if (g > mat->rmap->N) continue;
38945960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
39045960306SStefano Zampini       ierr = VecSetValue(b,g,diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
39145960306SStefano Zampini     }
39245960306SStefano Zampini     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
39345960306SStefano Zampini     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
39445960306SStefano Zampini     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1, x2 * diag] */
39545960306SStefano Zampini     ierr = VecDestroy(&xt);CHKERRQ(ierr);
39645960306SStefano Zampini     ierr = PetscFree(gcols);CHKERRQ(ierr);
39745960306SStefano Zampini   }
39845960306SStefano Zampini   ierr = PetscLayoutMapLocal(mat->rmap,n,rows,&nr,&lrows,NULL);CHKERRQ(ierr);
39945960306SStefano Zampini   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,0,NULL,diag,PETSC_FALSE);CHKERRQ(ierr);
400ef5c7bd2SStefano Zampini   if (shell->axpy) {
401ef5c7bd2SStefano Zampini     ierr = MatZeroRows(shell->axpy,n,rows,0.0,NULL,NULL);CHKERRQ(ierr);
402ef5c7bd2SStefano Zampini   }
40345960306SStefano Zampini   ierr = PetscFree(lrows);CHKERRQ(ierr);
40445960306SStefano Zampini   PetscFunctionReturn(0);
40545960306SStefano Zampini }
40645960306SStefano Zampini 
40745960306SStefano Zampini static PetscErrorCode MatZeroRowsColumns_Shell(Mat mat,PetscInt n,const PetscInt rowscols[],PetscScalar diag,Vec x,Vec b)
40845960306SStefano Zampini {
409ef5c7bd2SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)mat->data;
41045960306SStefano Zampini   PetscInt       *lrows, *lcols;
41145960306SStefano Zampini   PetscInt       nr, nc;
41245960306SStefano Zampini   PetscBool      congruent;
41345960306SStefano Zampini   PetscErrorCode ierr;
41445960306SStefano Zampini 
41545960306SStefano Zampini   PetscFunctionBegin;
41645960306SStefano Zampini   if (x && b) {
41745960306SStefano Zampini     Vec          xt, bt;
41845960306SStefano Zampini     PetscScalar *vals;
41945960306SStefano Zampini     PetscInt    *grows,*gcols,i,st,nl;
42045960306SStefano Zampini 
42145960306SStefano Zampini     ierr = PetscMalloc2(n,&grows,n,&gcols);CHKERRQ(ierr);
42245960306SStefano Zampini     for (i = 0, nr = 0; i < n; i++) if (rowscols[i] < mat->rmap->N) grows[nr++] = rowscols[i];
42345960306SStefano Zampini     for (i = 0, nc = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) gcols[nc++] = rowscols[i];
42445960306SStefano Zampini     ierr = PetscCalloc1(n,&vals);CHKERRQ(ierr);
42545960306SStefano Zampini 
42645960306SStefano Zampini     ierr = MatCreateVecs(mat,&xt,&bt);CHKERRQ(ierr);
42745960306SStefano Zampini     ierr = VecCopy(x,xt);CHKERRQ(ierr);
42845960306SStefano Zampini     ierr = VecSetValues(xt,nc,gcols,vals,INSERT_VALUES);CHKERRQ(ierr); /* xt = [x1, 0] */
42945960306SStefano Zampini     ierr = VecAssemblyBegin(xt);CHKERRQ(ierr);
43045960306SStefano Zampini     ierr = VecAssemblyEnd(xt);CHKERRQ(ierr);
43145960306SStefano Zampini     ierr = VecAXPY(xt,-1.0,x);CHKERRQ(ierr);                           /* xt = [0, -x2] */
43245960306SStefano Zampini     ierr = MatMult(mat,xt,bt);CHKERRQ(ierr);                           /* bt = [-A12*x2,-A22*x2] */
43345960306SStefano Zampini     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* bt = [-A12*x2,0] */
43445960306SStefano Zampini     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
43545960306SStefano Zampini     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
43645960306SStefano Zampini     ierr = VecAXPY(b,1.0,bt);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, b2] */
43745960306SStefano Zampini     ierr = VecSetValues(bt,nr,grows,vals,INSERT_VALUES);CHKERRQ(ierr); /* b  = [b1 - A12*x2, 0] */
43845960306SStefano Zampini     ierr = VecAssemblyBegin(bt);CHKERRQ(ierr);
43945960306SStefano Zampini     ierr = VecAssemblyEnd(bt);CHKERRQ(ierr);
44045960306SStefano Zampini     ierr = PetscFree(vals);CHKERRQ(ierr);
44145960306SStefano Zampini 
44245960306SStefano Zampini     ierr = VecGetOwnershipRange(xt,&st,NULL);CHKERRQ(ierr);
44345960306SStefano Zampini     ierr = VecGetLocalSize(xt,&nl);CHKERRQ(ierr);
44445960306SStefano Zampini     ierr = VecGetArray(xt,&vals);CHKERRQ(ierr);
44545960306SStefano Zampini     for (i = 0; i < nl; i++) {
44645960306SStefano Zampini       PetscInt g = i + st;
44745960306SStefano Zampini       if (g > mat->rmap->N) continue;
44845960306SStefano Zampini       if (PetscAbsScalar(vals[i]) == 0.0) continue;
44945960306SStefano Zampini       ierr = VecSetValue(b,g,-diag*vals[i],INSERT_VALUES);CHKERRQ(ierr);
45045960306SStefano Zampini     }
45145960306SStefano Zampini     ierr = VecRestoreArray(xt,&vals);CHKERRQ(ierr);
45245960306SStefano Zampini     ierr = VecAssemblyBegin(b);CHKERRQ(ierr);
45345960306SStefano Zampini     ierr = VecAssemblyEnd(b);CHKERRQ(ierr);                            /* b  = [b1 - A12*x2, x2 * diag] */
45445960306SStefano Zampini     ierr = VecDestroy(&xt);CHKERRQ(ierr);
45545960306SStefano Zampini     ierr = VecDestroy(&bt);CHKERRQ(ierr);
45645960306SStefano Zampini     ierr = PetscFree2(grows,gcols);CHKERRQ(ierr);
45745960306SStefano Zampini   }
45845960306SStefano Zampini   ierr = PetscLayoutMapLocal(mat->rmap,n,rowscols,&nr,&lrows,NULL);CHKERRQ(ierr);
45945960306SStefano Zampini   ierr = MatHasCongruentLayouts(mat,&congruent);CHKERRQ(ierr);
46045960306SStefano Zampini   if (congruent) {
46145960306SStefano Zampini     nc    = nr;
46245960306SStefano Zampini     lcols = lrows;
46345960306SStefano Zampini   } else { /* MatZeroRowsColumns implicitly assumes the rowscols indices are for a square matrix, here we handle a more general case */
46445960306SStefano Zampini     PetscInt i,nt,*t;
46545960306SStefano Zampini 
46645960306SStefano Zampini     ierr = PetscMalloc1(n,&t);CHKERRQ(ierr);
46745960306SStefano Zampini     for (i = 0, nt = 0; i < n; i++) if (rowscols[i] < mat->cmap->N) t[nt++] = rowscols[i];
46845960306SStefano Zampini     ierr = PetscLayoutMapLocal(mat->cmap,nt,t,&nc,&lcols,NULL);CHKERRQ(ierr);
46945960306SStefano Zampini     ierr = PetscFree(t);CHKERRQ(ierr);
47045960306SStefano Zampini   }
47145960306SStefano Zampini   ierr = MatZeroRowsColumns_Local_Shell(mat,nr,lrows,nc,lcols,diag,PETSC_TRUE);CHKERRQ(ierr);
47245960306SStefano Zampini   if (!congruent) {
47345960306SStefano Zampini     ierr = PetscFree(lcols);CHKERRQ(ierr);
47445960306SStefano Zampini   }
47545960306SStefano Zampini   ierr = PetscFree(lrows);CHKERRQ(ierr);
476ef5c7bd2SStefano Zampini   if (shell->axpy) {
477ef5c7bd2SStefano Zampini     ierr = MatZeroRowsColumns(shell->axpy,n,rowscols,0.0,NULL,NULL);CHKERRQ(ierr);
478ef5c7bd2SStefano Zampini   }
47945960306SStefano Zampini   PetscFunctionReturn(0);
48045960306SStefano Zampini }
48145960306SStefano Zampini 
482dfbe8321SBarry Smith PetscErrorCode MatDestroy_Shell(Mat mat)
483e51e0e81SBarry Smith {
484dfbe8321SBarry Smith   PetscErrorCode          ierr;
485bf0cc555SLisandro Dalcin   Mat_Shell               *shell = (Mat_Shell*)mat->data;
486*b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
487ed3cc1f0SBarry Smith 
4883a40ed3dSBarry Smith   PetscFunctionBegin;
48928f357e3SAlex Fikl   if (shell->ops->destroy) {
49028f357e3SAlex Fikl     ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr);
491bf0cc555SLisandro Dalcin   }
492ef5c7bd2SStefano Zampini   ierr = PetscMemzero(shell->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
4930c0fd78eSBarry Smith   ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
4940c0fd78eSBarry Smith   ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
4950c0fd78eSBarry Smith   ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
4968fe8eb27SJed Brown   ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr);
4978fe8eb27SJed Brown   ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr);
4985edf6516SJed Brown   ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr);
4995edf6516SJed Brown   ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr);
500*b77ba244SStefano Zampini   ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr);
501*b77ba244SStefano Zampini   ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr);
5029f137db4SBarry Smith   ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
50345960306SStefano Zampini   ierr = VecDestroy(&shell->zvals_w);CHKERRQ(ierr);
50445960306SStefano Zampini   ierr = VecDestroy(&shell->zvals);CHKERRQ(ierr);
50545960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
50645960306SStefano Zampini   ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
50745960306SStefano Zampini   ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
50845960306SStefano Zampini   ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
509*b77ba244SStefano Zampini 
510*b77ba244SStefano Zampini   matmat = shell->matmat;
511*b77ba244SStefano Zampini   while (matmat) {
512*b77ba244SStefano Zampini     MatShellMatFunctionList next = matmat->next;
513*b77ba244SStefano Zampini 
514*b77ba244SStefano Zampini     ierr = PetscObjectComposeFunction((PetscObject)mat,matmat->composedname,NULL);CHKERRQ(ierr);
515*b77ba244SStefano Zampini     ierr = PetscFree(matmat->composedname);CHKERRQ(ierr);
516*b77ba244SStefano Zampini     ierr = PetscFree(matmat->resultname);CHKERRQ(ierr);
517*b77ba244SStefano Zampini     ierr = PetscFree(matmat);CHKERRQ(ierr);
518*b77ba244SStefano Zampini     matmat = next;
519*b77ba244SStefano Zampini   }
520789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetContext_C",NULL);CHKERRQ(ierr);
521789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetContext_C",NULL);CHKERRQ(ierr);
522db77db73SJeremy L Thompson   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetVecType_C",NULL);CHKERRQ(ierr);
523789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetManageScalingShifts_C",NULL);CHKERRQ(ierr);
524789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetOperation_C",NULL);CHKERRQ(ierr);
525789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellGetOperation_C",NULL);CHKERRQ(ierr);
526*b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatShellSetMatProductOperation_C",NULL);CHKERRQ(ierr);
527*b77ba244SStefano Zampini   ierr = PetscFree(mat->data);CHKERRQ(ierr);
528*b77ba244SStefano Zampini   PetscFunctionReturn(0);
529*b77ba244SStefano Zampini }
530*b77ba244SStefano Zampini 
531*b77ba244SStefano Zampini typedef struct {
532*b77ba244SStefano Zampini   PetscErrorCode (*numeric)(Mat,Mat,Mat,void*);
533*b77ba244SStefano Zampini   PetscErrorCode (*destroy)(void*);
534*b77ba244SStefano Zampini   void           *userdata;
535*b77ba244SStefano Zampini   Mat            B;
536*b77ba244SStefano Zampini   Mat            Bt;
537*b77ba244SStefano Zampini   Mat            axpy;
538*b77ba244SStefano Zampini } MatMatDataShell;
539*b77ba244SStefano Zampini 
540*b77ba244SStefano Zampini static PetscErrorCode DestroyMatMatDataShell(void *data)
541*b77ba244SStefano Zampini {
542*b77ba244SStefano Zampini   MatMatDataShell *mmdata = (MatMatDataShell *)data;
543*b77ba244SStefano Zampini   PetscErrorCode ierr;
544*b77ba244SStefano Zampini 
545*b77ba244SStefano Zampini   PetscFunctionBegin;
546*b77ba244SStefano Zampini   if (mmdata->destroy) {
547*b77ba244SStefano Zampini     ierr = (*mmdata->destroy)(mmdata->userdata);CHKERRQ(ierr);
548*b77ba244SStefano Zampini   }
549*b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->B);CHKERRQ(ierr);
550*b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->Bt);CHKERRQ(ierr);
551*b77ba244SStefano Zampini   ierr = MatDestroy(&mmdata->axpy);CHKERRQ(ierr);
552*b77ba244SStefano Zampini   ierr = PetscFree(mmdata);CHKERRQ(ierr);
553*b77ba244SStefano Zampini   PetscFunctionReturn(0);
554*b77ba244SStefano Zampini }
555*b77ba244SStefano Zampini 
556*b77ba244SStefano Zampini static PetscErrorCode MatProductNumeric_Shell_X(Mat D)
557*b77ba244SStefano Zampini {
558*b77ba244SStefano Zampini   PetscErrorCode  ierr;
559*b77ba244SStefano Zampini   Mat_Product     *product;
560*b77ba244SStefano Zampini   Mat             A, B;
561*b77ba244SStefano Zampini   MatMatDataShell *mdata;
562*b77ba244SStefano Zampini   PetscScalar     zero = 0.0;
563*b77ba244SStefano Zampini 
564*b77ba244SStefano Zampini   PetscFunctionBegin;
565*b77ba244SStefano Zampini   MatCheckProduct(D,1);
566*b77ba244SStefano Zampini   product = D->product;
567*b77ba244SStefano Zampini   if (!product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data empty");
568*b77ba244SStefano Zampini   A = product->A;
569*b77ba244SStefano Zampini   B = product->B;
570*b77ba244SStefano Zampini   mdata = (MatMatDataShell*)product->data;
571*b77ba244SStefano Zampini   if (mdata->numeric) {
572*b77ba244SStefano Zampini     Mat_Shell      *shell = (Mat_Shell*)A->data;
573*b77ba244SStefano Zampini     PetscErrorCode (*stashsym)(Mat) = D->ops->productsymbolic;
574*b77ba244SStefano Zampini     PetscErrorCode (*stashnum)(Mat) = D->ops->productnumeric;
575*b77ba244SStefano Zampini     PetscBool      useBmdata = PETSC_FALSE, newB = PETSC_TRUE;
576*b77ba244SStefano Zampini 
577*b77ba244SStefano Zampini     if (shell->managescalingshifts) {
578*b77ba244SStefano Zampini       if (shell->zcols || shell->zrows) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"MatProduct not supported with zeroed rows/columns");
579*b77ba244SStefano Zampini       if (shell->right || shell->left) {
580*b77ba244SStefano Zampini         useBmdata = PETSC_TRUE;
581*b77ba244SStefano Zampini         if (!mdata->B) {
582*b77ba244SStefano Zampini           ierr = MatDuplicate(B,MAT_SHARE_NONZERO_PATTERN,&mdata->B);CHKERRQ(ierr);
583*b77ba244SStefano Zampini         } else {
584*b77ba244SStefano Zampini           newB = PETSC_FALSE;
585*b77ba244SStefano Zampini         }
586*b77ba244SStefano Zampini         ierr = MatCopy(B,mdata->B,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
587*b77ba244SStefano Zampini       }
588*b77ba244SStefano Zampini       switch (product->type) {
589*b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
590*b77ba244SStefano Zampini         if (shell->right) {
591*b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr);
592*b77ba244SStefano Zampini         }
593*b77ba244SStefano Zampini         break;
594*b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
595*b77ba244SStefano Zampini         if (shell->left) {
596*b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->left,NULL);CHKERRQ(ierr);
597*b77ba244SStefano Zampini         }
598*b77ba244SStefano Zampini         break;
599*b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
600*b77ba244SStefano Zampini         if (shell->right) {
601*b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr);
602*b77ba244SStefano Zampini         }
603*b77ba244SStefano Zampini         break;
604*b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
605*b77ba244SStefano Zampini         if (shell->right && shell->left) {
606*b77ba244SStefano Zampini           PetscBool flg;
607*b77ba244SStefano Zampini 
608*b77ba244SStefano Zampini           ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr);
609*b77ba244SStefano Zampini           if (!flg) SETERRQ3(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);
610*b77ba244SStefano Zampini         }
611*b77ba244SStefano Zampini         if (shell->right) {
612*b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,NULL,shell->right);CHKERRQ(ierr);
613*b77ba244SStefano Zampini         }
614*b77ba244SStefano Zampini         break;
615*b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
616*b77ba244SStefano Zampini         if (shell->right && shell->left) {
617*b77ba244SStefano Zampini           PetscBool flg;
618*b77ba244SStefano Zampini 
619*b77ba244SStefano Zampini           ierr = VecEqual(shell->right,shell->left,&flg);CHKERRQ(ierr);
620*b77ba244SStefano Zampini           if (!flg) SETERRQ3(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);
621*b77ba244SStefano Zampini         }
622*b77ba244SStefano Zampini         if (shell->right) {
623*b77ba244SStefano Zampini           ierr = MatDiagonalScale(mdata->B,shell->right,NULL);CHKERRQ(ierr);
624*b77ba244SStefano Zampini         }
625*b77ba244SStefano Zampini         break;
626*b77ba244SStefano Zampini       default: SETERRQ3(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);
627*b77ba244SStefano Zampini       }
628*b77ba244SStefano Zampini     }
629*b77ba244SStefano Zampini     /* allow the user to call MatMat operations on D */
630*b77ba244SStefano Zampini     D->product = NULL;
631*b77ba244SStefano Zampini     D->ops->productsymbolic = NULL;
632*b77ba244SStefano Zampini     D->ops->productnumeric  = NULL;
633*b77ba244SStefano Zampini 
634*b77ba244SStefano Zampini     ierr = (*mdata->numeric)(A,useBmdata ? mdata->B : B,D,mdata->userdata);CHKERRQ(ierr);
635*b77ba244SStefano Zampini 
636*b77ba244SStefano Zampini     /* clear any leftover user data and restore D pointers */
637*b77ba244SStefano Zampini     ierr = MatProductClear(D);CHKERRQ(ierr);
638*b77ba244SStefano Zampini     D->ops->productsymbolic = stashsym;
639*b77ba244SStefano Zampini     D->ops->productnumeric  = stashnum;
640*b77ba244SStefano Zampini     D->product = product;
641*b77ba244SStefano Zampini 
642*b77ba244SStefano Zampini     if (shell->managescalingshifts) {
643*b77ba244SStefano Zampini       ierr = MatScale(D,shell->vscale);CHKERRQ(ierr);
644*b77ba244SStefano Zampini       switch (product->type) {
645*b77ba244SStefano Zampini       case MATPRODUCT_AB: /* s L A R B + v L R B + L D R B */
646*b77ba244SStefano Zampini       case MATPRODUCT_ABt: /* s L A R B^t + v L R B^t + L D R B^t */
647*b77ba244SStefano Zampini         if (shell->left) {
648*b77ba244SStefano Zampini           ierr = MatDiagonalScale(D,shell->left,NULL);CHKERRQ(ierr);
649*b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
650*b77ba244SStefano Zampini             if (!shell->left_work) {ierr = MatCreateVecs(A,NULL,&shell->left_work);CHKERRQ(ierr);}
651*b77ba244SStefano Zampini             if (shell->dshift) {
652*b77ba244SStefano Zampini               ierr = VecCopy(shell->dshift,shell->left_work);CHKERRQ(ierr);
653*b77ba244SStefano Zampini               ierr = VecShift(shell->left_work,shell->vshift);CHKERRQ(ierr);
654*b77ba244SStefano Zampini               ierr = VecPointwiseMult(shell->left_work,shell->left_work,shell->left);CHKERRQ(ierr);
655*b77ba244SStefano Zampini             } else {
656*b77ba244SStefano Zampini               ierr = VecSet(shell->left_work,shell->vshift);CHKERRQ(ierr);
657*b77ba244SStefano Zampini             }
658*b77ba244SStefano Zampini             if (product->type == MATPRODUCT_ABt) {
659*b77ba244SStefano Zampini               MatReuse     reuse = mdata->Bt ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
660*b77ba244SStefano Zampini               MatStructure str = mdata->Bt ? SUBSET_NONZERO_PATTERN : DIFFERENT_NONZERO_PATTERN;
661*b77ba244SStefano Zampini 
662*b77ba244SStefano Zampini               ierr = MatTranspose(mdata->B,reuse,&mdata->Bt);CHKERRQ(ierr);
663*b77ba244SStefano Zampini               ierr = MatDiagonalScale(mdata->Bt,shell->left_work,NULL);CHKERRQ(ierr);
664*b77ba244SStefano Zampini               ierr = MatAXPY(D,1.0,mdata->Bt,str);CHKERRQ(ierr);
665*b77ba244SStefano Zampini             } else {
666*b77ba244SStefano Zampini               MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
667*b77ba244SStefano Zampini 
668*b77ba244SStefano Zampini               ierr = MatDiagonalScale(mdata->B,shell->left_work,NULL);CHKERRQ(ierr);
669*b77ba244SStefano Zampini               ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr);
670*b77ba244SStefano Zampini             }
671*b77ba244SStefano Zampini           }
672*b77ba244SStefano Zampini         }
673*b77ba244SStefano Zampini         break;
674*b77ba244SStefano Zampini       case MATPRODUCT_AtB: /* s R A^t L B + v R L B + R D L B */
675*b77ba244SStefano Zampini         if (shell->right) {
676*b77ba244SStefano Zampini           ierr = MatDiagonalScale(D,shell->right,NULL);CHKERRQ(ierr);
677*b77ba244SStefano Zampini           if (shell->dshift || shell->vshift != zero) {
678*b77ba244SStefano Zampini             MatStructure str = newB ? DIFFERENT_NONZERO_PATTERN : SUBSET_NONZERO_PATTERN;
679*b77ba244SStefano Zampini 
680*b77ba244SStefano Zampini             if (!shell->right_work) {ierr = MatCreateVecs(A,&shell->right_work,NULL);CHKERRQ(ierr);}
681*b77ba244SStefano Zampini             if (shell->dshift) {
682*b77ba244SStefano Zampini               ierr = VecCopy(shell->dshift,shell->right_work);CHKERRQ(ierr);
683*b77ba244SStefano Zampini               ierr = VecShift(shell->right_work,shell->vshift);CHKERRQ(ierr);
684*b77ba244SStefano Zampini               ierr = VecPointwiseMult(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
685*b77ba244SStefano Zampini             } else {
686*b77ba244SStefano Zampini               ierr = VecSet(shell->right_work,shell->vshift);CHKERRQ(ierr);
687*b77ba244SStefano Zampini             }
688*b77ba244SStefano Zampini             ierr = MatDiagonalScale(mdata->B,shell->right_work,NULL);CHKERRQ(ierr);
689*b77ba244SStefano Zampini             ierr = MatAXPY(D,1.0,mdata->B,str);CHKERRQ(ierr);
690*b77ba244SStefano Zampini           }
691*b77ba244SStefano Zampini         }
692*b77ba244SStefano Zampini         break;
693*b77ba244SStefano Zampini       case MATPRODUCT_PtAP: /* s B^t L A R B + v B^t L R B + B^t L D R B */
694*b77ba244SStefano Zampini       case MATPRODUCT_RARt: /* s B L A R B^t + v B L R B^t + B L D R B^t */
695*b77ba244SStefano Zampini         if (shell->dshift || shell->vshift != zero) SETERRQ3(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);
696*b77ba244SStefano Zampini         break;
697*b77ba244SStefano Zampini       default: SETERRQ3(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);
698*b77ba244SStefano Zampini       }
699*b77ba244SStefano Zampini       if (shell->axpy && shell->axpy_vscale != zero) {
700*b77ba244SStefano Zampini         Mat              X;
701*b77ba244SStefano Zampini         PetscObjectState axpy_state;
702*b77ba244SStefano Zampini         MatStructure     str = DIFFERENT_NONZERO_PATTERN; /* not sure it is safe to ever use SUBSET_NONZERO_PATTERN */
703*b77ba244SStefano Zampini 
704*b77ba244SStefano Zampini         ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr);
705*b77ba244SStefano Zampini         ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
706*b77ba244SStefano Zampini         if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
707*b77ba244SStefano Zampini         if (!mdata->axpy) {
708*b77ba244SStefano Zampini           str  = DIFFERENT_NONZERO_PATTERN;
709*b77ba244SStefano Zampini           ierr = MatProductCreate(shell->axpy,B,NULL,&mdata->axpy);CHKERRQ(ierr);
710*b77ba244SStefano Zampini           ierr = MatProductSetType(mdata->axpy,product->type);CHKERRQ(ierr);
711*b77ba244SStefano Zampini           ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr);
712*b77ba244SStefano Zampini           ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr);
713*b77ba244SStefano Zampini         } else { /* May be that shell->axpy has changed */
714*b77ba244SStefano Zampini           PetscBool flg;
715*b77ba244SStefano Zampini 
716*b77ba244SStefano Zampini           ierr = MatProductReplaceMats(shell->axpy,B,NULL,mdata->axpy);CHKERRQ(ierr);
717*b77ba244SStefano Zampini           ierr = MatHasOperation(mdata->axpy,MATOP_PRODUCTSYMBOLIC,&flg);CHKERRQ(ierr);
718*b77ba244SStefano Zampini           if (!flg) {
719*b77ba244SStefano Zampini             str  = DIFFERENT_NONZERO_PATTERN;
720*b77ba244SStefano Zampini             ierr = MatProductSetFromOptions(mdata->axpy);CHKERRQ(ierr);
721*b77ba244SStefano Zampini             ierr = MatProductSymbolic(mdata->axpy);CHKERRQ(ierr);
722*b77ba244SStefano Zampini           }
723*b77ba244SStefano Zampini         }
724*b77ba244SStefano Zampini         ierr = MatProductNumeric(mdata->axpy);CHKERRQ(ierr);
725*b77ba244SStefano Zampini         ierr = MatAXPY(D,shell->axpy_vscale,mdata->axpy,str);CHKERRQ(ierr);
726*b77ba244SStefano Zampini       }
727*b77ba244SStefano Zampini     }
728*b77ba244SStefano Zampini   } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Missing numeric operation");
729*b77ba244SStefano Zampini   PetscFunctionReturn(0);
730*b77ba244SStefano Zampini }
731*b77ba244SStefano Zampini 
732*b77ba244SStefano Zampini static PetscErrorCode MatProductSymbolic_Shell_X(Mat D)
733*b77ba244SStefano Zampini {
734*b77ba244SStefano Zampini   PetscErrorCode          ierr;
735*b77ba244SStefano Zampini   Mat_Product             *product;
736*b77ba244SStefano Zampini   Mat                     A,B;
737*b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
738*b77ba244SStefano Zampini   Mat_Shell               *shell;
739*b77ba244SStefano Zampini   PetscBool               flg;
740*b77ba244SStefano Zampini   char                    composedname[256];
741*b77ba244SStefano Zampini   MatMatDataShell         *mdata;
742*b77ba244SStefano Zampini 
743*b77ba244SStefano Zampini   PetscFunctionBegin;
744*b77ba244SStefano Zampini   MatCheckProduct(D,1);
745*b77ba244SStefano Zampini   product = D->product;
746*b77ba244SStefano Zampini   if (product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product data not empty");
747*b77ba244SStefano Zampini   A = product->A;
748*b77ba244SStefano Zampini   B = product->B;
749*b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
750*b77ba244SStefano Zampini   matmat = shell->matmat;
751*b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
752*b77ba244SStefano Zampini   while (matmat) {
753*b77ba244SStefano Zampini     ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr);
754*b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
755*b77ba244SStefano Zampini     if (flg) break;
756*b77ba244SStefano Zampini     matmat = matmat->next;
757*b77ba244SStefano Zampini   }
758*b77ba244SStefano Zampini   if (!flg) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Composedname \"%s\" for product type %s not found",composedname,MatProductTypes[product->type]);
759*b77ba244SStefano Zampini   switch (product->type) {
760*b77ba244SStefano Zampini   case MATPRODUCT_AB:
761*b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);CHKERRQ(ierr);
762*b77ba244SStefano Zampini     break;
763*b77ba244SStefano Zampini   case MATPRODUCT_AtB:
764*b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);CHKERRQ(ierr);
765*b77ba244SStefano Zampini     break;
766*b77ba244SStefano Zampini   case MATPRODUCT_ABt:
767*b77ba244SStefano Zampini     ierr = MatSetSizes(D,A->rmap->n,B->rmap->n,A->rmap->N,B->rmap->N);CHKERRQ(ierr);
768*b77ba244SStefano Zampini     break;
769*b77ba244SStefano Zampini   case MATPRODUCT_RARt:
770*b77ba244SStefano Zampini     ierr = MatSetSizes(D,B->rmap->n,B->rmap->n,B->rmap->N,B->rmap->N);CHKERRQ(ierr);
771*b77ba244SStefano Zampini     break;
772*b77ba244SStefano Zampini   case MATPRODUCT_PtAP:
773*b77ba244SStefano Zampini     ierr = MatSetSizes(D,B->cmap->n,B->cmap->n,B->cmap->N,B->cmap->N);CHKERRQ(ierr);
774*b77ba244SStefano Zampini     break;
775*b77ba244SStefano Zampini   default: SETERRQ3(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);
776*b77ba244SStefano Zampini   }
777*b77ba244SStefano Zampini   /* respect users who passed in a matrix for which resultname is the base type */
778*b77ba244SStefano Zampini   if (matmat->resultname) {
779*b77ba244SStefano Zampini     ierr = PetscObjectBaseTypeCompare((PetscObject)D,matmat->resultname,&flg);CHKERRQ(ierr);
780*b77ba244SStefano Zampini     if (!flg) {
781*b77ba244SStefano Zampini       ierr = MatSetType(D,matmat->resultname);CHKERRQ(ierr);
782*b77ba244SStefano Zampini     }
783*b77ba244SStefano Zampini   }
784*b77ba244SStefano Zampini   /* If matrix type was not set or different, we need to reset this pointers */
785*b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
786*b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
787*b77ba244SStefano Zampini   /* attach product data */
788*b77ba244SStefano Zampini   ierr = PetscNew(&mdata);CHKERRQ(ierr);
789*b77ba244SStefano Zampini   mdata->numeric = matmat->numeric;
790*b77ba244SStefano Zampini   mdata->destroy = matmat->destroy;
791*b77ba244SStefano Zampini   if (matmat->symbolic) {
792*b77ba244SStefano Zampini     ierr = (*matmat->symbolic)(A,B,D,&mdata->userdata);CHKERRQ(ierr);
793*b77ba244SStefano Zampini   } else { /* call general setup if symbolic operation not provided */
794*b77ba244SStefano Zampini     ierr = MatSetUp(D);CHKERRQ(ierr);
795*b77ba244SStefano Zampini   }
796*b77ba244SStefano Zampini   if (!D->product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product disappeared after user symbolic phase");
797*b77ba244SStefano Zampini   if (D->product->data) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_COR,"Product data not empty after user symbolic phase");
798*b77ba244SStefano Zampini   D->product->data = mdata;
799*b77ba244SStefano Zampini   D->product->destroy = DestroyMatMatDataShell;
800*b77ba244SStefano Zampini   /* Be sure to reset these pointers if the user did something unexpected */
801*b77ba244SStefano Zampini   D->ops->productsymbolic = MatProductSymbolic_Shell_X;
802*b77ba244SStefano Zampini   D->ops->productnumeric  = MatProductNumeric_Shell_X;
803*b77ba244SStefano Zampini   PetscFunctionReturn(0);
804*b77ba244SStefano Zampini }
805*b77ba244SStefano Zampini 
806*b77ba244SStefano Zampini static PetscErrorCode MatProductSetFromOptions_Shell_X(Mat D)
807*b77ba244SStefano Zampini {
808*b77ba244SStefano Zampini   PetscErrorCode          ierr;
809*b77ba244SStefano Zampini   Mat_Product             *product;
810*b77ba244SStefano Zampini   Mat                     A,B;
811*b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
812*b77ba244SStefano Zampini   Mat_Shell               *shell;
813*b77ba244SStefano Zampini   PetscBool               flg;
814*b77ba244SStefano Zampini   char                    composedname[256];
815*b77ba244SStefano Zampini 
816*b77ba244SStefano Zampini   PetscFunctionBegin;
817*b77ba244SStefano Zampini   MatCheckProduct(D,1);
818*b77ba244SStefano Zampini   product = D->product;
819*b77ba244SStefano Zampini   A = product->A;
820*b77ba244SStefano Zampini   B = product->B;
821*b77ba244SStefano Zampini   ierr = MatIsShell(A,&flg);CHKERRQ(ierr);
822*b77ba244SStefano Zampini   if (!flg) PetscFunctionReturn(0);
823*b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
824*b77ba244SStefano Zampini   matmat = shell->matmat;
825*b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
826*b77ba244SStefano Zampini   while (matmat) {
827*b77ba244SStefano Zampini     ierr = PetscStrcmp(composedname,matmat->composedname,&flg);CHKERRQ(ierr);
828*b77ba244SStefano Zampini     flg  = (PetscBool)(flg && (matmat->ptype == product->type));
829*b77ba244SStefano Zampini     if (flg) break;
830*b77ba244SStefano Zampini     matmat = matmat->next;
831*b77ba244SStefano Zampini   }
832*b77ba244SStefano Zampini   if (flg) { D->ops->productsymbolic = MatProductSymbolic_Shell_X; }
833*b77ba244SStefano Zampini   else { ierr = PetscInfo2(D,"  symbolic product %s not registered for product type %s\n",composedname,MatProductTypes[product->type]);CHKERRQ(ierr); }
834*b77ba244SStefano Zampini   PetscFunctionReturn(0);
835*b77ba244SStefano Zampini }
836*b77ba244SStefano Zampini 
837*b77ba244SStefano 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)
838*b77ba244SStefano Zampini {
839*b77ba244SStefano Zampini   PetscBool               flg;
840*b77ba244SStefano Zampini   PetscErrorCode          ierr;
841*b77ba244SStefano Zampini   Mat_Shell               *shell;
842*b77ba244SStefano Zampini   MatShellMatFunctionList matmat;
843*b77ba244SStefano Zampini 
844*b77ba244SStefano Zampini   PetscFunctionBegin;
845*b77ba244SStefano Zampini   if (!numeric) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing numeric routine");
846*b77ba244SStefano Zampini   if (!composedname) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing composed name");
847*b77ba244SStefano Zampini 
848*b77ba244SStefano Zampini   /* add product callback */
849*b77ba244SStefano Zampini   shell = (Mat_Shell*)A->data;
850*b77ba244SStefano Zampini   matmat = shell->matmat;
851*b77ba244SStefano Zampini   if (!matmat) {
852*b77ba244SStefano Zampini     ierr = PetscNew(&shell->matmat);CHKERRQ(ierr);
853*b77ba244SStefano Zampini     matmat = shell->matmat;
854*b77ba244SStefano Zampini   } else {
855*b77ba244SStefano Zampini     MatShellMatFunctionList entry = matmat;
856*b77ba244SStefano Zampini     while (entry) {
857*b77ba244SStefano Zampini       ierr = PetscStrcmp(composedname,entry->composedname,&flg);CHKERRQ(ierr);
858*b77ba244SStefano Zampini       flg  = (PetscBool)(flg && (entry->ptype == ptype));
859*b77ba244SStefano Zampini       if (flg) break;
860*b77ba244SStefano Zampini       matmat = entry;
861*b77ba244SStefano Zampini       entry = entry->next;
862*b77ba244SStefano Zampini     }
863*b77ba244SStefano Zampini     if (!flg) {
864*b77ba244SStefano Zampini       ierr = PetscNew(&matmat->next);CHKERRQ(ierr);
865*b77ba244SStefano Zampini       matmat = matmat->next;
866*b77ba244SStefano Zampini     } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"This should not happen");
867*b77ba244SStefano Zampini   }
868*b77ba244SStefano Zampini 
869*b77ba244SStefano Zampini   matmat->symbolic = symbolic;
870*b77ba244SStefano Zampini   matmat->numeric  = numeric;
871*b77ba244SStefano Zampini   matmat->destroy  = destroy;
872*b77ba244SStefano Zampini   matmat->ptype    = ptype;
873*b77ba244SStefano Zampini   ierr = PetscFree(matmat->composedname);CHKERRQ(ierr);
874*b77ba244SStefano Zampini   ierr = PetscFree(matmat->resultname);CHKERRQ(ierr);
875*b77ba244SStefano Zampini   ierr = PetscStrallocpy(composedname,&matmat->composedname);CHKERRQ(ierr);
876*b77ba244SStefano Zampini   ierr = PetscStrallocpy(resultname,&matmat->resultname);CHKERRQ(ierr);
877*b77ba244SStefano Zampini   ierr = PetscInfo3(A,"Composing %s for product type %s with result %s\n",matmat->composedname,MatProductTypes[matmat->ptype],matmat->resultname ? matmat->resultname : "not specified");CHKERRQ(ierr);
878*b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,matmat->composedname,MatProductSetFromOptions_Shell_X);CHKERRQ(ierr);
879*b77ba244SStefano Zampini   PetscFunctionReturn(0);
880*b77ba244SStefano Zampini }
881*b77ba244SStefano Zampini 
882*b77ba244SStefano Zampini /*@C
883*b77ba244SStefano Zampini     MatShellSetMatProductOperation - Allows user to set a matrix matrix operation for a shell matrix.
884*b77ba244SStefano Zampini 
885*b77ba244SStefano Zampini    Logically Collective on Mat
886*b77ba244SStefano Zampini 
887*b77ba244SStefano Zampini     Input Parameters:
888*b77ba244SStefano Zampini +   A - the shell matrix
889*b77ba244SStefano Zampini .   ptype - the product type
890*b77ba244SStefano Zampini .   symbolic - the function for the symbolic phase (can be NULL)
891*b77ba244SStefano Zampini .   numeric - the function for the numerical phase
892*b77ba244SStefano Zampini .   destroy - the function for the destruction of the needed data generated during the symbolic phase (can be NULL)
893*b77ba244SStefano Zampini .   Btype - the matrix type for the matrix to be multiplied against
894*b77ba244SStefano Zampini -   Ctype - the matrix type for the result (can be NULL)
895*b77ba244SStefano Zampini 
896*b77ba244SStefano Zampini    Level: advanced
897*b77ba244SStefano Zampini 
898*b77ba244SStefano Zampini     Usage:
899*b77ba244SStefano Zampini $      extern PetscErrorCode usersymbolic(Mat,Mat,Mat,void**);
900*b77ba244SStefano Zampini $      extern PetscErrorCode usernumeric(Mat,Mat,Mat,void*);
901*b77ba244SStefano Zampini $      extern PetscErrorCode userdestroy(void*);
902*b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
903*b77ba244SStefano Zampini $      MatShellSetMatProductOperation(A,MATPRODUCT_AB,usersymbolic,usernumeric,userdestroy,MATSEQAIJ,MATDENSE);
904*b77ba244SStefano Zampini $      [ create B of type SEQAIJ etc..]
905*b77ba244SStefano Zampini $      MatProductCreate(A,B,NULL,&C);
906*b77ba244SStefano Zampini $      MatProductSetType(C,MATPRODUCT_AB);
907*b77ba244SStefano Zampini $      MatProductSetFromOptions(C);
908*b77ba244SStefano Zampini $      MatProductSymbolic(C); -> actually runs the user defined symbolic operation
909*b77ba244SStefano Zampini $      MatProductNumeric(C); -> actually runs the user defined numeric operation
910*b77ba244SStefano Zampini $      [ use C = A*B ]
911*b77ba244SStefano Zampini 
912*b77ba244SStefano Zampini     Notes:
913*b77ba244SStefano Zampini     MATPRODUCT_ABC is not supported yet. Not supported in Fortran.
914*b77ba244SStefano 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.
915*b77ba244SStefano Zampini     Any additional data needed by the matrix product needs to be returned during the symbolic phase and destroyed with the destroy callback.
916*b77ba244SStefano Zampini     PETSc will take care of calling the user-defined callbacks.
917*b77ba244SStefano Zampini     It is allowed to specify the same callbacks for different Btype matrix types.
918*b77ba244SStefano Zampini     The couple (Btype,ptype) uniquely identifies the operation: the last specified callbacks takes precedence.
919*b77ba244SStefano Zampini 
920*b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatProductType, MatType, MatSetUp()
921*b77ba244SStefano Zampini @*/
922*b77ba244SStefano 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)
923*b77ba244SStefano Zampini {
924*b77ba244SStefano Zampini   PetscErrorCode ierr;
925*b77ba244SStefano Zampini 
926*b77ba244SStefano Zampini   PetscFunctionBegin;
927*b77ba244SStefano Zampini   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
928*b77ba244SStefano Zampini   PetscValidLogicalCollectiveEnum(A,ptype,2);
929*b77ba244SStefano Zampini   if (ptype == MATPRODUCT_ABC) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not for product type %s",MatProductTypes[ptype]);
930*b77ba244SStefano Zampini   if (!numeric) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Missing numeric routine, argument 4");
931*b77ba244SStefano Zampini   PetscValidPointer(Btype,6);
932*b77ba244SStefano Zampini   if (Ctype) PetscValidPointer(Ctype,7);
933*b77ba244SStefano 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);
934*b77ba244SStefano Zampini   PetscFunctionReturn(0);
935*b77ba244SStefano Zampini }
936*b77ba244SStefano Zampini 
937*b77ba244SStefano 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)
938*b77ba244SStefano Zampini {
939*b77ba244SStefano Zampini   PetscBool      flg;
940*b77ba244SStefano Zampini   PetscErrorCode ierr;
941*b77ba244SStefano Zampini   char           composedname[256];
942*b77ba244SStefano Zampini   MatRootName    Bnames = MatRootNameList, Cnames = MatRootNameList;
943*b77ba244SStefano Zampini   PetscMPIInt    size;
944*b77ba244SStefano Zampini 
945*b77ba244SStefano Zampini   PetscFunctionBegin;
946*b77ba244SStefano Zampini   PetscValidType(A,1);
947*b77ba244SStefano Zampini   while (Bnames) { /* user passed in the root name */
948*b77ba244SStefano Zampini     ierr = PetscStrcmp(Btype,Bnames->rname,&flg);CHKERRQ(ierr);
949*b77ba244SStefano Zampini     if (flg) break;
950*b77ba244SStefano Zampini     Bnames = Bnames->next;
951*b77ba244SStefano Zampini   }
952*b77ba244SStefano Zampini   while (Cnames) { /* user passed in the root name */
953*b77ba244SStefano Zampini     ierr = PetscStrcmp(Ctype,Cnames->rname,&flg);CHKERRQ(ierr);
954*b77ba244SStefano Zampini     if (flg) break;
955*b77ba244SStefano Zampini     Cnames = Cnames->next;
956*b77ba244SStefano Zampini   }
957*b77ba244SStefano Zampini   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
958*b77ba244SStefano Zampini   Btype = Bnames ? (size > 1 ? Bnames->mname : Bnames->sname) : Btype;
959*b77ba244SStefano Zampini   Ctype = Cnames ? (size > 1 ? Cnames->mname : Cnames->sname) : Ctype;
960*b77ba244SStefano Zampini   ierr = PetscSNPrintf(composedname,sizeof(composedname),"MatProductSetFromOptions_%s_%s_C",((PetscObject)A)->type_name,Btype);CHKERRQ(ierr);
961*b77ba244SStefano Zampini   ierr = MatShellSetMatProductOperation_Private(A,ptype,symbolic,numeric,destroy,composedname,Ctype);CHKERRQ(ierr);
9623a40ed3dSBarry Smith   PetscFunctionReturn(0);
963e51e0e81SBarry Smith }
964e51e0e81SBarry Smith 
9657fabda3fSAlex Fikl PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str)
9667fabda3fSAlex Fikl {
96728f357e3SAlex Fikl   Mat_Shell               *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data;
9687fabda3fSAlex Fikl   PetscErrorCode          ierr;
969cb8c8a77SBarry Smith   PetscBool               matflg;
970*b77ba244SStefano Zampini   MatShellMatFunctionList matmatA;
9717fabda3fSAlex Fikl 
9727fabda3fSAlex Fikl   PetscFunctionBegin;
973*b77ba244SStefano Zampini   ierr = MatIsShell(B,&matflg);CHKERRQ(ierr);
974*b77ba244SStefano Zampini   if (!matflg) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix %s not derived from MATSHELL",((PetscObject)B)->type_name);
9757fabda3fSAlex Fikl 
976cb8c8a77SBarry Smith   ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
977cb8c8a77SBarry Smith   ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr);
9787fabda3fSAlex Fikl 
979cb8c8a77SBarry Smith   if (shellA->ops->copy) {
98028f357e3SAlex Fikl     ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr);
981cb8c8a77SBarry Smith   }
9827fabda3fSAlex Fikl   shellB->vscale = shellA->vscale;
9837fabda3fSAlex Fikl   shellB->vshift = shellA->vshift;
9840c0fd78eSBarry Smith   if (shellA->dshift) {
9850c0fd78eSBarry Smith     if (!shellB->dshift) {
9860c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr);
9877fabda3fSAlex Fikl     }
9880c0fd78eSBarry Smith     ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr);
9897fabda3fSAlex Fikl   } else {
9909f137db4SBarry Smith     ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr);
9917fabda3fSAlex Fikl   }
9920c0fd78eSBarry Smith   if (shellA->left) {
9930c0fd78eSBarry Smith     if (!shellB->left) {
9940c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr);
9957fabda3fSAlex Fikl     }
9960c0fd78eSBarry Smith     ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr);
9977fabda3fSAlex Fikl   } else {
9989f137db4SBarry Smith     ierr = VecDestroy(&shellB->left);CHKERRQ(ierr);
9997fabda3fSAlex Fikl   }
10000c0fd78eSBarry Smith   if (shellA->right) {
10010c0fd78eSBarry Smith     if (!shellB->right) {
10020c0fd78eSBarry Smith       ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr);
10037fabda3fSAlex Fikl     }
10040c0fd78eSBarry Smith     ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr);
10057fabda3fSAlex Fikl   } else {
10069f137db4SBarry Smith     ierr = VecDestroy(&shellB->right);CHKERRQ(ierr);
10077fabda3fSAlex Fikl   }
100840e381c3SBarry Smith   ierr = MatDestroy(&shellB->axpy);CHKERRQ(ierr);
1009ef5c7bd2SStefano Zampini   shellB->axpy_vscale = 0.0;
1010ef5c7bd2SStefano Zampini   shellB->axpy_state  = 0;
101140e381c3SBarry Smith   if (shellA->axpy) {
101240e381c3SBarry Smith     ierr                = PetscObjectReference((PetscObject)shellA->axpy);CHKERRQ(ierr);
101340e381c3SBarry Smith     shellB->axpy        = shellA->axpy;
101440e381c3SBarry Smith     shellB->axpy_vscale = shellA->axpy_vscale;
1015ef5c7bd2SStefano Zampini     shellB->axpy_state  = shellA->axpy_state;
101640e381c3SBarry Smith   }
101745960306SStefano Zampini   if (shellA->zrows) {
101845960306SStefano Zampini     ierr = ISDuplicate(shellA->zrows,&shellB->zrows);CHKERRQ(ierr);
101945960306SStefano Zampini     if (shellA->zcols) {
102045960306SStefano Zampini       ierr = ISDuplicate(shellA->zcols,&shellB->zcols);CHKERRQ(ierr);
102145960306SStefano Zampini     }
102245960306SStefano Zampini     ierr = VecDuplicate(shellA->zvals,&shellB->zvals);CHKERRQ(ierr);
102345960306SStefano Zampini     ierr = VecCopy(shellA->zvals,shellB->zvals);CHKERRQ(ierr);
102445960306SStefano Zampini     ierr = VecDuplicate(shellA->zvals_w,&shellB->zvals_w);CHKERRQ(ierr);
102545960306SStefano Zampini     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_r);CHKERRQ(ierr);
102645960306SStefano Zampini     ierr = PetscObjectReference((PetscObject)shellA->zvals_sct_c);CHKERRQ(ierr);
102745960306SStefano Zampini     shellB->zvals_sct_r = shellA->zvals_sct_r;
102845960306SStefano Zampini     shellB->zvals_sct_c = shellA->zvals_sct_c;
102945960306SStefano Zampini   }
1030*b77ba244SStefano Zampini 
1031*b77ba244SStefano Zampini   matmatA = shellA->matmat;
1032*b77ba244SStefano Zampini   if (matmatA) {
1033*b77ba244SStefano Zampini     while (matmatA->next) {
1034*b77ba244SStefano Zampini       ierr = MatShellSetMatProductOperation_Private(B,matmatA->ptype,matmatA->symbolic,matmatA->numeric,matmatA->destroy,matmatA->composedname,matmatA->resultname);CHKERRQ(ierr);
1035*b77ba244SStefano Zampini       matmatA = matmatA->next;
1036*b77ba244SStefano Zampini     }
1037*b77ba244SStefano Zampini   }
10387fabda3fSAlex Fikl   PetscFunctionReturn(0);
10397fabda3fSAlex Fikl }
10407fabda3fSAlex Fikl 
1041cb8c8a77SBarry Smith PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M)
1042cb8c8a77SBarry Smith {
1043cb8c8a77SBarry Smith   PetscErrorCode ierr;
1044cb8c8a77SBarry Smith   void           *ctx;
1045cb8c8a77SBarry Smith 
1046cb8c8a77SBarry Smith   PetscFunctionBegin;
1047cb8c8a77SBarry Smith   ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr);
1048cb8c8a77SBarry Smith   ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr);
1049*b77ba244SStefano Zampini   ierr = PetscObjectChangeTypeName((PetscObject)(*M),((PetscObject)mat)->type_name);CHKERRQ(ierr);
1050a4b1380bSStefano Zampini   if (op != MAT_DO_NOT_COPY_VALUES) {
1051cb8c8a77SBarry Smith     ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
1052a4b1380bSStefano Zampini   }
1053cb8c8a77SBarry Smith   PetscFunctionReturn(0);
1054cb8c8a77SBarry Smith }
1055cb8c8a77SBarry Smith 
1056dfbe8321SBarry Smith PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
1057ef66eb69SBarry Smith {
1058ef66eb69SBarry Smith   Mat_Shell        *shell = (Mat_Shell*)A->data;
1059dfbe8321SBarry Smith   PetscErrorCode   ierr;
106025578ef6SJed Brown   Vec              xx;
1061e3f487b0SBarry Smith   PetscObjectState instate,outstate;
1062ef66eb69SBarry Smith 
1063ef66eb69SBarry Smith   PetscFunctionBegin;
1064976e8c5aSLisandro Dalcin   if (!shell->ops->mult) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMult() for this MATSHELL");
106545960306SStefano Zampini   ierr = MatShellPreZeroRight(A,x,&xx);CHKERRQ(ierr);
106645960306SStefano Zampini   ierr = MatShellPreScaleRight(A,xx,&xx);CHKERRQ(ierr);
106745960306SStefano Zampini   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
106828f357e3SAlex Fikl   ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr);
1069e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
1070e3f487b0SBarry Smith   if (instate == outstate) {
1071e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1072e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
1073e3f487b0SBarry Smith   }
10748fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
10758fe8eb27SJed Brown   ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr);
107645960306SStefano Zampini   ierr = MatShellPostZeroLeft(A,y);CHKERRQ(ierr);
10779f137db4SBarry Smith 
10789f137db4SBarry Smith   if (shell->axpy) {
1079ef5c7bd2SStefano Zampini     Mat              X;
1080ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1081ef5c7bd2SStefano Zampini 
1082ef5c7bd2SStefano Zampini     ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr);
1083ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
108431c70108SStefano Zampini     if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1085*b77ba244SStefano Zampini 
1086*b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1087*b77ba244SStefano Zampini     ierr = VecCopy(x,shell->axpy_right);CHKERRQ(ierr);
1088*b77ba244SStefano Zampini     ierr = MatMult(shell->axpy,shell->axpy_right,shell->axpy_left);CHKERRQ(ierr);
1089*b77ba244SStefano Zampini     ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr);
10909f137db4SBarry Smith   }
1091ef66eb69SBarry Smith   PetscFunctionReturn(0);
1092ef66eb69SBarry Smith }
1093ef66eb69SBarry Smith 
10945edf6516SJed Brown PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
10955edf6516SJed Brown {
10965edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
10975edf6516SJed Brown   PetscErrorCode ierr;
10985edf6516SJed Brown 
10995edf6516SJed Brown   PetscFunctionBegin;
11005edf6516SJed Brown   if (y == z) {
11015edf6516SJed Brown     if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);}
11025edf6516SJed Brown     ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr);
1103b8430d49SBarry Smith     ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr);
11045edf6516SJed Brown   } else {
11055edf6516SJed Brown     ierr = MatMult(A,x,z);CHKERRQ(ierr);
11065edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
11075edf6516SJed Brown   }
11085edf6516SJed Brown   PetscFunctionReturn(0);
11095edf6516SJed Brown }
11105edf6516SJed Brown 
111118be62a5SSatish Balay PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
111218be62a5SSatish Balay {
111318be62a5SSatish Balay   Mat_Shell        *shell = (Mat_Shell*)A->data;
111418be62a5SSatish Balay   PetscErrorCode   ierr;
111525578ef6SJed Brown   Vec              xx;
1116e3f487b0SBarry Smith   PetscObjectState instate,outstate;
111718be62a5SSatish Balay 
111818be62a5SSatish Balay   PetscFunctionBegin;
1119*b77ba244SStefano Zampini   if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL");
112045960306SStefano Zampini   ierr = MatShellPreZeroLeft(A,x,&xx);CHKERRQ(ierr);
112145960306SStefano Zampini   ierr = MatShellPreScaleLeft(A,xx,&xx);CHKERRQ(ierr);
1122e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr);
112328f357e3SAlex Fikl   ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr);
1124e3f487b0SBarry Smith   ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr);
1125e3f487b0SBarry Smith   if (instate == outstate) {
1126e3f487b0SBarry Smith     /* increase the state of the output vector since the user did not update its state themself as should have been done */
1127e3f487b0SBarry Smith     ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr);
1128e3f487b0SBarry Smith   }
11298fe8eb27SJed Brown   ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr);
11308fe8eb27SJed Brown   ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr);
113145960306SStefano Zampini   ierr = MatShellPostZeroRight(A,y);CHKERRQ(ierr);
1132350ec83bSStefano Zampini 
1133350ec83bSStefano Zampini   if (shell->axpy) {
1134ef5c7bd2SStefano Zampini     Mat              X;
1135ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1136ef5c7bd2SStefano Zampini 
1137ef5c7bd2SStefano Zampini     ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr);
1138ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
113931c70108SStefano Zampini     if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1140*b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,shell->axpy_right ? NULL : &shell->axpy_right,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1141*b77ba244SStefano Zampini     ierr = VecCopy(x,shell->axpy_left);CHKERRQ(ierr);
1142*b77ba244SStefano Zampini     ierr = MatMultTranspose(shell->axpy,shell->axpy_left,shell->axpy_right);CHKERRQ(ierr);
1143*b77ba244SStefano Zampini     ierr = VecAXPY(y,shell->axpy_vscale,shell->axpy_right);CHKERRQ(ierr);
1144350ec83bSStefano Zampini   }
114518be62a5SSatish Balay   PetscFunctionReturn(0);
114618be62a5SSatish Balay }
114718be62a5SSatish Balay 
11485edf6516SJed Brown PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
11495edf6516SJed Brown {
11505edf6516SJed Brown   Mat_Shell      *shell = (Mat_Shell*)A->data;
11515edf6516SJed Brown   PetscErrorCode ierr;
11525edf6516SJed Brown 
11535edf6516SJed Brown   PetscFunctionBegin;
11545edf6516SJed Brown   if (y == z) {
11555edf6516SJed Brown     if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);}
11565edf6516SJed Brown     ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr);
1157dac989eaS“Marek     ierr = VecAXPY(z,1.0,shell->left_add_work);CHKERRQ(ierr);
11585edf6516SJed Brown   } else {
11595edf6516SJed Brown     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
11605edf6516SJed Brown     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
11615edf6516SJed Brown   }
11625edf6516SJed Brown   PetscFunctionReturn(0);
11635edf6516SJed Brown }
11645edf6516SJed Brown 
11650c0fd78eSBarry Smith /*
11660c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
11670c0fd78eSBarry Smith */
116818be62a5SSatish Balay PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
116918be62a5SSatish Balay {
117018be62a5SSatish Balay   Mat_Shell      *shell = (Mat_Shell*)A->data;
117118be62a5SSatish Balay   PetscErrorCode ierr;
117218be62a5SSatish Balay 
117318be62a5SSatish Balay   PetscFunctionBegin;
11740c0fd78eSBarry Smith   if (shell->ops->getdiagonal) {
117528f357e3SAlex Fikl     ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr);
1176305211d5SBarry 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,...)");
117718be62a5SSatish Balay   ierr = VecScale(v,shell->vscale);CHKERRQ(ierr);
11788fe8eb27SJed Brown   if (shell->dshift) {
11790c0fd78eSBarry Smith     ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr);
118018be62a5SSatish Balay   }
11810c0fd78eSBarry Smith   ierr = VecShift(v,shell->vshift);CHKERRQ(ierr);
11828fe8eb27SJed Brown   if (shell->left)  {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);}
11838fe8eb27SJed Brown   if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);}
118445960306SStefano Zampini   if (shell->zrows) {
118545960306SStefano Zampini     ierr = VecScatterBegin(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
118645960306SStefano Zampini     ierr = VecScatterEnd(shell->zvals_sct_r,shell->zvals,v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
118745960306SStefano Zampini   }
118881c02519SBarry Smith   if (shell->axpy) {
1189ef5c7bd2SStefano Zampini     Mat              X;
1190ef5c7bd2SStefano Zampini     PetscObjectState axpy_state;
1191ef5c7bd2SStefano Zampini 
1192ef5c7bd2SStefano Zampini     ierr = MatShellGetContext(shell->axpy,(void *)&X);CHKERRQ(ierr);
1193ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&axpy_state);CHKERRQ(ierr);
119431c70108SStefano Zampini     if (shell->axpy_state != axpy_state) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Invalid AXPY state: cannot modify the X matrix passed to MatAXPY(Y,a,X,...)");
1195*b77ba244SStefano Zampini     ierr = MatCreateVecs(shell->axpy,NULL,shell->axpy_left ? NULL : &shell->axpy_left);CHKERRQ(ierr);
1196*b77ba244SStefano Zampini     ierr = MatGetDiagonal(shell->axpy,shell->axpy_left);CHKERRQ(ierr);
1197*b77ba244SStefano Zampini     ierr = VecAXPY(v,shell->axpy_vscale,shell->axpy_left);CHKERRQ(ierr);
119881c02519SBarry Smith   }
119918be62a5SSatish Balay   PetscFunctionReturn(0);
120018be62a5SSatish Balay }
120118be62a5SSatish Balay 
1202f4df32b1SMatthew Knepley PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
1203ef66eb69SBarry Smith {
1204ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12058fe8eb27SJed Brown   PetscErrorCode ierr;
1206789d8953SBarry Smith   PetscBool      flg;
1207b24ad042SBarry Smith 
1208ef66eb69SBarry Smith   PetscFunctionBegin;
1209789d8953SBarry Smith   ierr = MatHasCongruentLayouts(Y,&flg);CHKERRQ(ierr);
1210789d8953SBarry Smith   if (!flg) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot shift shell matrix if it is not congruent");
12110c0fd78eSBarry Smith   if (shell->left || shell->right) {
12128fe8eb27SJed Brown     if (!shell->dshift) {
12130c0fd78eSBarry Smith       ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr);
12140c0fd78eSBarry Smith       ierr = VecSet(shell->dshift,a);CHKERRQ(ierr);
12150c0fd78eSBarry Smith     } else {
12160c0fd78eSBarry Smith       if (shell->left)  {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
12170c0fd78eSBarry Smith       if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
12189f137db4SBarry Smith       ierr = VecShift(shell->dshift,a);CHKERRQ(ierr);
12190c0fd78eSBarry Smith     }
12208fe8eb27SJed Brown     if (shell->left)  {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);}
12218fe8eb27SJed Brown     if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);}
12228fe8eb27SJed Brown   } else shell->vshift += a;
122345960306SStefano Zampini   if (shell->zrows) {
122445960306SStefano Zampini     ierr = VecShift(shell->zvals,a);CHKERRQ(ierr);
122545960306SStefano Zampini   }
1226ef66eb69SBarry Smith   PetscFunctionReturn(0);
1227ef66eb69SBarry Smith }
1228ef66eb69SBarry Smith 
1229b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell_Private(Mat A,Vec D,PetscScalar s)
12306464bf51SAlex Fikl {
12316464bf51SAlex Fikl   Mat_Shell      *shell = (Mat_Shell*)A->data;
12326464bf51SAlex Fikl   PetscErrorCode ierr;
12336464bf51SAlex Fikl 
12346464bf51SAlex Fikl   PetscFunctionBegin;
12350c0fd78eSBarry Smith   if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);}
12360c0fd78eSBarry Smith   if (shell->left || shell->right) {
123792fabd1fSBarry Smith     if (!shell->right_work) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr);}
12389f137db4SBarry Smith     if (shell->left && shell->right)  {
12399f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
12409f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr);
12419f137db4SBarry Smith     } else if (shell->left) {
12429f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr);
12439f137db4SBarry Smith     } else {
12449f137db4SBarry Smith       ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr);
12459f137db4SBarry Smith     }
1246b253ae0bS“Marek     ierr = VecAXPY(shell->dshift,s,shell->right_work);CHKERRQ(ierr);
12470c0fd78eSBarry Smith   } else {
1248b253ae0bS“Marek     ierr = VecAXPY(shell->dshift,s,D);CHKERRQ(ierr);
1249b253ae0bS“Marek   }
1250b253ae0bS“Marek   PetscFunctionReturn(0);
1251b253ae0bS“Marek }
1252b253ae0bS“Marek 
1253b253ae0bS“Marek PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins)
1254b253ae0bS“Marek {
125545960306SStefano Zampini   Mat_Shell      *shell = (Mat_Shell*)A->data;
1256b253ae0bS“Marek   Vec            d;
1257b253ae0bS“Marek   PetscErrorCode ierr;
1258789d8953SBarry Smith   PetscBool      flg;
1259b253ae0bS“Marek 
1260b253ae0bS“Marek   PetscFunctionBegin;
1261789d8953SBarry Smith   ierr = MatHasCongruentLayouts(A,&flg);CHKERRQ(ierr);
1262789d8953SBarry Smith   if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot diagonal set or shift shell matrix if it is not congruent");
1263b253ae0bS“Marek   if (ins == INSERT_VALUES) {
1264b253ae0bS“Marek     if (!A->ops->getdiagonal) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Operation MATOP_GETDIAGONAL must be set first");
1265b253ae0bS“Marek     ierr = VecDuplicate(D,&d);CHKERRQ(ierr);
1266b253ae0bS“Marek     ierr = MatGetDiagonal(A,d);CHKERRQ(ierr);
1267b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,d,-1.);CHKERRQ(ierr);
1268b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
1269b253ae0bS“Marek     ierr = VecDestroy(&d);CHKERRQ(ierr);
127045960306SStefano Zampini     if (shell->zrows) {
127145960306SStefano Zampini       ierr = VecCopy(D,shell->zvals);CHKERRQ(ierr);
127245960306SStefano Zampini     }
1273b253ae0bS“Marek   } else {
1274b253ae0bS“Marek     ierr = MatDiagonalSet_Shell_Private(A,D,1.);CHKERRQ(ierr);
127545960306SStefano Zampini     if (shell->zrows) {
127645960306SStefano Zampini       ierr = VecAXPY(shell->zvals,1.0,D);CHKERRQ(ierr);
127745960306SStefano Zampini     }
12786464bf51SAlex Fikl   }
12796464bf51SAlex Fikl   PetscFunctionReturn(0);
12806464bf51SAlex Fikl }
12816464bf51SAlex Fikl 
1282f4df32b1SMatthew Knepley PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
1283ef66eb69SBarry Smith {
1284ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
12858fe8eb27SJed Brown   PetscErrorCode ierr;
1286b24ad042SBarry Smith 
1287ef66eb69SBarry Smith   PetscFunctionBegin;
1288f4df32b1SMatthew Knepley   shell->vscale *= a;
12890c0fd78eSBarry Smith   shell->vshift *= a;
12902205254eSKarl Rupp   if (shell->dshift) {
12912205254eSKarl Rupp     ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);
12920c0fd78eSBarry Smith   }
129381c02519SBarry Smith   shell->axpy_vscale *= a;
129445960306SStefano Zampini   if (shell->zrows) {
129545960306SStefano Zampini     ierr = VecScale(shell->zvals,a);CHKERRQ(ierr);
129645960306SStefano Zampini   }
12978fe8eb27SJed Brown   PetscFunctionReturn(0);
129818be62a5SSatish Balay }
12998fe8eb27SJed Brown 
13008fe8eb27SJed Brown static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
13018fe8eb27SJed Brown {
13028fe8eb27SJed Brown   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13038fe8eb27SJed Brown   PetscErrorCode ierr;
13048fe8eb27SJed Brown 
13058fe8eb27SJed Brown   PetscFunctionBegin;
13068fe8eb27SJed Brown   if (left) {
13070c0fd78eSBarry Smith     if (!shell->left) {
13080c0fd78eSBarry Smith       ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr);
13098fe8eb27SJed Brown       ierr = VecCopy(left,shell->left);CHKERRQ(ierr);
13100c0fd78eSBarry Smith     } else {
13110c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);
131218be62a5SSatish Balay     }
131345960306SStefano Zampini     if (shell->zrows) {
131445960306SStefano Zampini       ierr = VecPointwiseMult(shell->zvals,shell->zvals,left);CHKERRQ(ierr);
131545960306SStefano Zampini     }
1316ef66eb69SBarry Smith   }
13178fe8eb27SJed Brown   if (right) {
13180c0fd78eSBarry Smith     if (!shell->right) {
13190c0fd78eSBarry Smith       ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr);
13208fe8eb27SJed Brown       ierr = VecCopy(right,shell->right);CHKERRQ(ierr);
13210c0fd78eSBarry Smith     } else {
13220c0fd78eSBarry Smith       ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);
13238fe8eb27SJed Brown     }
132445960306SStefano Zampini     if (shell->zrows) {
132545960306SStefano Zampini       if (!shell->left_work) {
132645960306SStefano Zampini         ierr = MatCreateVecs(Y,NULL,&shell->left_work);CHKERRQ(ierr);
132745960306SStefano Zampini       }
132845960306SStefano Zampini       ierr = VecSet(shell->zvals_w,1.0);CHKERRQ(ierr);
132945960306SStefano Zampini       ierr = VecScatterBegin(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
133045960306SStefano Zampini       ierr = VecScatterEnd(shell->zvals_sct_c,right,shell->zvals_w,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
133145960306SStefano Zampini       ierr = VecPointwiseMult(shell->zvals,shell->zvals,shell->zvals_w);CHKERRQ(ierr);
133245960306SStefano Zampini     }
13338fe8eb27SJed Brown   }
1334ef5c7bd2SStefano Zampini   if (shell->axpy) {
1335ef5c7bd2SStefano Zampini     ierr = MatDiagonalScale(shell->axpy,left,right);CHKERRQ(ierr);
1336ef5c7bd2SStefano Zampini   }
1337ef66eb69SBarry Smith   PetscFunctionReturn(0);
1338ef66eb69SBarry Smith }
1339ef66eb69SBarry Smith 
1340dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
1341ef66eb69SBarry Smith {
1342ef66eb69SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13430c0fd78eSBarry Smith   PetscErrorCode ierr;
1344ef66eb69SBarry Smith 
1345ef66eb69SBarry Smith   PetscFunctionBegin;
13468fe8eb27SJed Brown   if (t == MAT_FINAL_ASSEMBLY) {
1347ef66eb69SBarry Smith     shell->vshift = 0.0;
1348ef66eb69SBarry Smith     shell->vscale = 1.0;
1349ef5c7bd2SStefano Zampini     shell->axpy_vscale = 0.0;
1350ef5c7bd2SStefano Zampini     shell->axpy_state  = 0;
13510c0fd78eSBarry Smith     ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr);
13520c0fd78eSBarry Smith     ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
13530c0fd78eSBarry Smith     ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
135481c02519SBarry Smith     ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr);
1355*b77ba244SStefano Zampini     ierr = VecDestroy(&shell->axpy_left);CHKERRQ(ierr);
1356*b77ba244SStefano Zampini     ierr = VecDestroy(&shell->axpy_right);CHKERRQ(ierr);
135745960306SStefano Zampini     ierr = VecScatterDestroy(&shell->zvals_sct_c);CHKERRQ(ierr);
135845960306SStefano Zampini     ierr = VecScatterDestroy(&shell->zvals_sct_r);CHKERRQ(ierr);
135945960306SStefano Zampini     ierr = ISDestroy(&shell->zrows);CHKERRQ(ierr);
136045960306SStefano Zampini     ierr = ISDestroy(&shell->zcols);CHKERRQ(ierr);
1361ef66eb69SBarry Smith   }
1362ef66eb69SBarry Smith   PetscFunctionReturn(0);
1363ef66eb69SBarry Smith }
1364ef66eb69SBarry Smith 
13653b49f96aSBarry Smith static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d)
13663b49f96aSBarry Smith {
13673b49f96aSBarry Smith   PetscFunctionBegin;
13683b49f96aSBarry Smith   *missing = PETSC_FALSE;
13693b49f96aSBarry Smith   PetscFunctionReturn(0);
13703b49f96aSBarry Smith }
13713b49f96aSBarry Smith 
13729f137db4SBarry Smith PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str)
13739f137db4SBarry Smith {
13749f137db4SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)Y->data;
13759f137db4SBarry Smith   PetscErrorCode ierr;
13769f137db4SBarry Smith 
13779f137db4SBarry Smith   PetscFunctionBegin;
1378ef5c7bd2SStefano Zampini   if (X == Y) {
1379ef5c7bd2SStefano Zampini     ierr = MatScale(Y,1.0 + a);CHKERRQ(ierr);
1380ef5c7bd2SStefano Zampini     PetscFunctionReturn(0);
1381ef5c7bd2SStefano Zampini   }
1382ef5c7bd2SStefano Zampini   if (!shell->axpy) {
1383ef5c7bd2SStefano Zampini     ierr = MatConvertFrom_Shell(X,MATSHELL,MAT_INITIAL_MATRIX,&shell->axpy);CHKERRQ(ierr);
13849f137db4SBarry Smith     shell->axpy_vscale = a;
1385ef5c7bd2SStefano Zampini     ierr = PetscObjectStateGet((PetscObject)X,&shell->axpy_state);CHKERRQ(ierr);
1386ef5c7bd2SStefano Zampini   } else {
1387ef5c7bd2SStefano Zampini     ierr = MatAXPY(shell->axpy,a/shell->axpy_vscale,X,str);CHKERRQ(ierr);
1388ef5c7bd2SStefano Zampini   }
13899f137db4SBarry Smith   PetscFunctionReturn(0);
13909f137db4SBarry Smith }
13919f137db4SBarry Smith 
139209dc0095SBarry Smith static struct _MatOps MatOps_Values = {0,
139320563c6bSBarry Smith                                        0,
139420563c6bSBarry Smith                                        0,
13959f137db4SBarry Smith                                        0,
13960c0fd78eSBarry Smith                                 /* 4*/ MatMultAdd_Shell,
13979f137db4SBarry Smith                                        0,
13980c0fd78eSBarry Smith                                        MatMultTransposeAdd_Shell,
1399b951964fSBarry Smith                                        0,
1400b951964fSBarry Smith                                        0,
1401b951964fSBarry Smith                                        0,
140297304618SKris Buschelman                                 /*10*/ 0,
1403b951964fSBarry Smith                                        0,
1404b951964fSBarry Smith                                        0,
1405b951964fSBarry Smith                                        0,
1406b951964fSBarry Smith                                        0,
140797304618SKris Buschelman                                 /*15*/ 0,
1408b951964fSBarry Smith                                        0,
140900849d43SBarry Smith                                        0,
14108fe8eb27SJed Brown                                        MatDiagonalScale_Shell,
1411b951964fSBarry Smith                                        0,
141297304618SKris Buschelman                                 /*20*/ 0,
1413ef66eb69SBarry Smith                                        MatAssemblyEnd_Shell,
1414b951964fSBarry Smith                                        0,
1415b951964fSBarry Smith                                        0,
141645960306SStefano Zampini                                 /*24*/ MatZeroRows_Shell,
1417b951964fSBarry Smith                                        0,
1418b951964fSBarry Smith                                        0,
1419b951964fSBarry Smith                                        0,
1420b951964fSBarry Smith                                        0,
1421d519adbfSMatthew Knepley                                 /*29*/ 0,
1422b951964fSBarry Smith                                        0,
1423273d9f13SBarry Smith                                        0,
1424b951964fSBarry Smith                                        0,
1425b951964fSBarry Smith                                        0,
1426cb8c8a77SBarry Smith                                 /*34*/ MatDuplicate_Shell,
1427b951964fSBarry Smith                                        0,
1428b951964fSBarry Smith                                        0,
142909dc0095SBarry Smith                                        0,
143009dc0095SBarry Smith                                        0,
14319f137db4SBarry Smith                                 /*39*/ MatAXPY_Shell,
143209dc0095SBarry Smith                                        0,
143309dc0095SBarry Smith                                        0,
143409dc0095SBarry Smith                                        0,
1435cb8c8a77SBarry Smith                                        MatCopy_Shell,
1436d519adbfSMatthew Knepley                                 /*44*/ 0,
1437ef66eb69SBarry Smith                                        MatScale_Shell,
1438ef66eb69SBarry Smith                                        MatShift_Shell,
14396464bf51SAlex Fikl                                        MatDiagonalSet_Shell,
144045960306SStefano Zampini                                        MatZeroRowsColumns_Shell,
1441f73d5cc4SBarry Smith                                 /*49*/ 0,
144209dc0095SBarry Smith                                        0,
144309dc0095SBarry Smith                                        0,
144409dc0095SBarry Smith                                        0,
144509dc0095SBarry Smith                                        0,
1446d519adbfSMatthew Knepley                                 /*54*/ 0,
144709dc0095SBarry Smith                                        0,
144809dc0095SBarry Smith                                        0,
144909dc0095SBarry Smith                                        0,
145009dc0095SBarry Smith                                        0,
1451d519adbfSMatthew Knepley                                 /*59*/ 0,
1452b9b97703SBarry Smith                                        MatDestroy_Shell,
145309dc0095SBarry Smith                                        0,
1454251fad3fSStefano Zampini                                        MatConvertFrom_Shell,
1455273d9f13SBarry Smith                                        0,
1456d519adbfSMatthew Knepley                                 /*64*/ 0,
1457273d9f13SBarry Smith                                        0,
1458273d9f13SBarry Smith                                        0,
1459273d9f13SBarry Smith                                        0,
1460273d9f13SBarry Smith                                        0,
1461d519adbfSMatthew Knepley                                 /*69*/ 0,
1462273d9f13SBarry Smith                                        0,
1463c87e5d42SMatthew Knepley                                        MatConvert_Shell,
1464273d9f13SBarry Smith                                        0,
146597304618SKris Buschelman                                        0,
1466d519adbfSMatthew Knepley                                 /*74*/ 0,
146797304618SKris Buschelman                                        0,
146897304618SKris Buschelman                                        0,
146997304618SKris Buschelman                                        0,
147097304618SKris Buschelman                                        0,
1471d519adbfSMatthew Knepley                                 /*79*/ 0,
147297304618SKris Buschelman                                        0,
147397304618SKris Buschelman                                        0,
147497304618SKris Buschelman                                        0,
1475865e5f61SKris Buschelman                                        0,
1476d519adbfSMatthew Knepley                                 /*84*/ 0,
1477865e5f61SKris Buschelman                                        0,
1478865e5f61SKris Buschelman                                        0,
1479865e5f61SKris Buschelman                                        0,
1480865e5f61SKris Buschelman                                        0,
1481d519adbfSMatthew Knepley                                 /*89*/ 0,
1482865e5f61SKris Buschelman                                        0,
1483865e5f61SKris Buschelman                                        0,
1484865e5f61SKris Buschelman                                        0,
1485865e5f61SKris Buschelman                                        0,
1486d519adbfSMatthew Knepley                                 /*94*/ 0,
1487865e5f61SKris Buschelman                                        0,
1488865e5f61SKris Buschelman                                        0,
14893964eb88SJed Brown                                        0,
14903964eb88SJed Brown                                        0,
14913964eb88SJed Brown                                 /*99*/ 0,
14923964eb88SJed Brown                                        0,
14933964eb88SJed Brown                                        0,
14943964eb88SJed Brown                                        0,
14953964eb88SJed Brown                                        0,
14963964eb88SJed Brown                                /*104*/ 0,
14973964eb88SJed Brown                                        0,
14983964eb88SJed Brown                                        0,
14993964eb88SJed Brown                                        0,
15003964eb88SJed Brown                                        0,
15013964eb88SJed Brown                                /*109*/ 0,
15023964eb88SJed Brown                                        0,
15033964eb88SJed Brown                                        0,
15043964eb88SJed Brown                                        0,
15053b49f96aSBarry Smith                                        MatMissingDiagonal_Shell,
15063964eb88SJed Brown                                /*114*/ 0,
15073964eb88SJed Brown                                        0,
15083964eb88SJed Brown                                        0,
15093964eb88SJed Brown                                        0,
15103964eb88SJed Brown                                        0,
15113964eb88SJed Brown                                /*119*/ 0,
15123964eb88SJed Brown                                        0,
15133964eb88SJed Brown                                        0,
15143964eb88SJed Brown                                        0,
15153964eb88SJed Brown                                        0,
15163964eb88SJed Brown                                /*124*/ 0,
15173964eb88SJed Brown                                        0,
15183964eb88SJed Brown                                        0,
15193964eb88SJed Brown                                        0,
15203964eb88SJed Brown                                        0,
15213964eb88SJed Brown                                /*129*/ 0,
15223964eb88SJed Brown                                        0,
15233964eb88SJed Brown                                        0,
15243964eb88SJed Brown                                        0,
15253964eb88SJed Brown                                        0,
15263964eb88SJed Brown                                /*134*/ 0,
15273964eb88SJed Brown                                        0,
15283964eb88SJed Brown                                        0,
15293964eb88SJed Brown                                        0,
15303964eb88SJed Brown                                        0,
15313964eb88SJed Brown                                /*139*/ 0,
1532f9426fe0SMark Adams                                        0,
15333964eb88SJed Brown                                        0
15343964eb88SJed Brown };
1535273d9f13SBarry Smith 
1536789d8953SBarry Smith PetscErrorCode  MatShellSetContext_Shell(Mat mat,void *ctx)
1537789d8953SBarry Smith {
1538789d8953SBarry Smith   Mat_Shell *shell = (Mat_Shell*)mat->data;
1539789d8953SBarry Smith 
1540789d8953SBarry Smith   PetscFunctionBegin;
1541789d8953SBarry Smith   shell->ctx = ctx;
1542789d8953SBarry Smith   PetscFunctionReturn(0);
1543789d8953SBarry Smith }
1544789d8953SBarry Smith 
1545db77db73SJeremy L Thompson static PetscErrorCode MatShellSetVecType_Shell(Mat mat,VecType vtype)
1546db77db73SJeremy L Thompson {
1547db77db73SJeremy L Thompson   PetscErrorCode ierr;
1548db77db73SJeremy L Thompson 
1549db77db73SJeremy L Thompson   PetscFunctionBegin;
1550db77db73SJeremy L Thompson   ierr = PetscFree(mat->defaultvectype);CHKERRQ(ierr);
1551db77db73SJeremy L Thompson   ierr = PetscStrallocpy(vtype,(char**)&mat->defaultvectype);CHKERRQ(ierr);
1552db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1553db77db73SJeremy L Thompson }
1554db77db73SJeremy L Thompson 
1555789d8953SBarry Smith PetscErrorCode MatShellSetManageScalingShifts_Shell(Mat A)
1556789d8953SBarry Smith {
1557789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)A->data;
1558789d8953SBarry Smith 
1559789d8953SBarry Smith   PetscFunctionBegin;
1560789d8953SBarry Smith   shell->managescalingshifts = PETSC_FALSE;
1561789d8953SBarry Smith   A->ops->diagonalset   = NULL;
1562789d8953SBarry Smith   A->ops->diagonalscale = NULL;
1563789d8953SBarry Smith   A->ops->scale         = NULL;
1564789d8953SBarry Smith   A->ops->shift         = NULL;
1565789d8953SBarry Smith   A->ops->axpy          = NULL;
1566789d8953SBarry Smith   PetscFunctionReturn(0);
1567789d8953SBarry Smith }
1568789d8953SBarry Smith 
1569789d8953SBarry Smith PetscErrorCode MatShellSetOperation_Shell(Mat mat,MatOperation op,void (*f)(void))
1570789d8953SBarry Smith {
1571feb237baSPierre Jolivet   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1572789d8953SBarry Smith 
1573789d8953SBarry Smith   PetscFunctionBegin;
1574789d8953SBarry Smith   switch (op) {
1575789d8953SBarry Smith   case MATOP_DESTROY:
1576789d8953SBarry Smith     shell->ops->destroy = (PetscErrorCode (*)(Mat))f;
1577789d8953SBarry Smith     break;
1578789d8953SBarry Smith   case MATOP_VIEW:
1579789d8953SBarry Smith     if (!mat->ops->viewnative) {
1580789d8953SBarry Smith       mat->ops->viewnative = mat->ops->view;
1581789d8953SBarry Smith     }
1582789d8953SBarry Smith     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
1583789d8953SBarry Smith     break;
1584789d8953SBarry Smith   case MATOP_COPY:
1585789d8953SBarry Smith     shell->ops->copy = (PetscErrorCode (*)(Mat,Mat,MatStructure))f;
1586789d8953SBarry Smith     break;
1587789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1588789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1589789d8953SBarry Smith   case MATOP_SHIFT:
1590789d8953SBarry Smith   case MATOP_SCALE:
1591789d8953SBarry Smith   case MATOP_AXPY:
1592789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1593789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1594789d8953SBarry Smith     if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()");
1595789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1596789d8953SBarry Smith     break;
1597789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1598789d8953SBarry Smith     if (shell->managescalingshifts) {
1599789d8953SBarry Smith       shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f;
1600789d8953SBarry Smith       mat->ops->getdiagonal   = MatGetDiagonal_Shell;
1601789d8953SBarry Smith     } else {
1602789d8953SBarry Smith       shell->ops->getdiagonal = NULL;
1603789d8953SBarry Smith       mat->ops->getdiagonal   = (PetscErrorCode (*)(Mat,Vec))f;
1604789d8953SBarry Smith     }
1605789d8953SBarry Smith     break;
1606789d8953SBarry Smith   case MATOP_MULT:
1607789d8953SBarry Smith     if (shell->managescalingshifts) {
1608789d8953SBarry Smith       shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1609789d8953SBarry Smith       mat->ops->mult   = MatMult_Shell;
1610789d8953SBarry Smith     } else {
1611789d8953SBarry Smith       shell->ops->mult = NULL;
1612789d8953SBarry Smith       mat->ops->mult   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1613789d8953SBarry Smith     }
1614789d8953SBarry Smith     break;
1615789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1616789d8953SBarry Smith     if (shell->managescalingshifts) {
1617789d8953SBarry Smith       shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1618789d8953SBarry Smith       mat->ops->multtranspose   = MatMultTranspose_Shell;
1619789d8953SBarry Smith     } else {
1620789d8953SBarry Smith       shell->ops->multtranspose = NULL;
1621789d8953SBarry Smith       mat->ops->multtranspose   = (PetscErrorCode (*)(Mat,Vec,Vec))f;
1622789d8953SBarry Smith     }
1623789d8953SBarry Smith     break;
1624789d8953SBarry Smith   default:
1625789d8953SBarry Smith     (((void(**)(void))mat->ops)[op]) = f;
1626789d8953SBarry Smith     break;
1627789d8953SBarry Smith   }
1628789d8953SBarry Smith   PetscFunctionReturn(0);
1629789d8953SBarry Smith }
1630789d8953SBarry Smith 
1631789d8953SBarry Smith PetscErrorCode MatShellGetOperation_Shell(Mat mat,MatOperation op,void(**f)(void))
1632789d8953SBarry Smith {
1633789d8953SBarry Smith   Mat_Shell      *shell = (Mat_Shell*)mat->data;
1634789d8953SBarry Smith 
1635789d8953SBarry Smith   PetscFunctionBegin;
1636789d8953SBarry Smith   switch (op) {
1637789d8953SBarry Smith   case MATOP_DESTROY:
1638789d8953SBarry Smith     *f = (void (*)(void))shell->ops->destroy;
1639789d8953SBarry Smith     break;
1640789d8953SBarry Smith   case MATOP_VIEW:
1641789d8953SBarry Smith     *f = (void (*)(void))mat->ops->view;
1642789d8953SBarry Smith     break;
1643789d8953SBarry Smith   case MATOP_COPY:
1644789d8953SBarry Smith     *f = (void (*)(void))shell->ops->copy;
1645789d8953SBarry Smith     break;
1646789d8953SBarry Smith   case MATOP_DIAGONAL_SET:
1647789d8953SBarry Smith   case MATOP_DIAGONAL_SCALE:
1648789d8953SBarry Smith   case MATOP_SHIFT:
1649789d8953SBarry Smith   case MATOP_SCALE:
1650789d8953SBarry Smith   case MATOP_AXPY:
1651789d8953SBarry Smith   case MATOP_ZERO_ROWS:
1652789d8953SBarry Smith   case MATOP_ZERO_ROWS_COLUMNS:
1653789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1654789d8953SBarry Smith     break;
1655789d8953SBarry Smith   case MATOP_GET_DIAGONAL:
1656789d8953SBarry Smith     if (shell->ops->getdiagonal)
1657789d8953SBarry Smith       *f = (void (*)(void))shell->ops->getdiagonal;
1658789d8953SBarry Smith     else
1659789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1660789d8953SBarry Smith     break;
1661789d8953SBarry Smith   case MATOP_MULT:
1662789d8953SBarry Smith     if (shell->ops->mult)
1663789d8953SBarry Smith       *f = (void (*)(void))shell->ops->mult;
1664789d8953SBarry Smith     else
1665789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1666789d8953SBarry Smith     break;
1667789d8953SBarry Smith   case MATOP_MULT_TRANSPOSE:
1668789d8953SBarry Smith     if (shell->ops->multtranspose)
1669789d8953SBarry Smith       *f = (void (*)(void))shell->ops->multtranspose;
1670789d8953SBarry Smith     else
1671789d8953SBarry Smith       *f = (((void (**)(void))mat->ops)[op]);
1672789d8953SBarry Smith     break;
1673789d8953SBarry Smith   default:
1674789d8953SBarry Smith     *f = (((void (**)(void))mat->ops)[op]);
1675789d8953SBarry Smith   }
1676789d8953SBarry Smith   PetscFunctionReturn(0);
1677789d8953SBarry Smith }
1678789d8953SBarry Smith 
16790bad9183SKris Buschelman /*MC
1680fafad747SKris Buschelman    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
16810bad9183SKris Buschelman 
16820bad9183SKris Buschelman   Level: advanced
16830bad9183SKris Buschelman 
16840c0fd78eSBarry Smith .seealso: MatCreateShell()
16850bad9183SKris Buschelman M*/
16860bad9183SKris Buschelman 
16878cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
1688273d9f13SBarry Smith {
1689273d9f13SBarry Smith   Mat_Shell      *b;
1690dfbe8321SBarry Smith   PetscErrorCode ierr;
1691273d9f13SBarry Smith 
1692273d9f13SBarry Smith   PetscFunctionBegin;
1693273d9f13SBarry Smith   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
1694273d9f13SBarry Smith 
1695b00a9115SJed Brown   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
1696273d9f13SBarry Smith   A->data = (void*)b;
1697273d9f13SBarry Smith 
169826283091SBarry Smith   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
169926283091SBarry Smith   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1700273d9f13SBarry Smith 
1701273d9f13SBarry Smith   b->ctx                 = 0;
1702ef66eb69SBarry Smith   b->vshift              = 0.0;
1703ef66eb69SBarry Smith   b->vscale              = 1.0;
17040c0fd78eSBarry Smith   b->managescalingshifts = PETSC_TRUE;
1705273d9f13SBarry Smith   A->assembled           = PETSC_TRUE;
1706210f0121SBarry Smith   A->preallocated        = PETSC_FALSE;
17072205254eSKarl Rupp 
1708789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetContext_C",MatShellGetContext_Shell);CHKERRQ(ierr);
1709789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetContext_C",MatShellSetContext_Shell);CHKERRQ(ierr);
1710db77db73SJeremy L Thompson   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetVecType_C",MatShellSetVecType_Shell);CHKERRQ(ierr);
1711789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetManageScalingShifts_C",MatShellSetManageScalingShifts_Shell);CHKERRQ(ierr);
1712789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetOperation_C",MatShellSetOperation_Shell);CHKERRQ(ierr);
1713789d8953SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellGetOperation_C",MatShellGetOperation_Shell);CHKERRQ(ierr);
1714*b77ba244SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatShellSetMatProductOperation_C",MatShellSetMatProductOperation_Shell);CHKERRQ(ierr);
171517667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr);
1716273d9f13SBarry Smith   PetscFunctionReturn(0);
1717273d9f13SBarry Smith }
1718e51e0e81SBarry Smith 
17194b828684SBarry Smith /*@C
1720052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
1721ff756334SLois Curfman McInnes    private data storage format.
1722e51e0e81SBarry Smith 
1723d083f849SBarry Smith   Collective
1724c7fcc2eaSBarry Smith 
1725e51e0e81SBarry Smith    Input Parameters:
1726c7fcc2eaSBarry Smith +  comm - MPI communicator
1727c7fcc2eaSBarry Smith .  m - number of local rows (must be given)
1728c7fcc2eaSBarry Smith .  n - number of local columns (must be given)
1729c7fcc2eaSBarry Smith .  M - number of global rows (may be PETSC_DETERMINE)
1730c7fcc2eaSBarry Smith .  N - number of global columns (may be PETSC_DETERMINE)
1731c7fcc2eaSBarry Smith -  ctx - pointer to data needed by the shell matrix routines
1732e51e0e81SBarry Smith 
1733ff756334SLois Curfman McInnes    Output Parameter:
173444cd7ae7SLois Curfman McInnes .  A - the matrix
1735e51e0e81SBarry Smith 
1736ff2fd236SBarry Smith    Level: advanced
1737ff2fd236SBarry Smith 
1738f39d1f56SLois Curfman McInnes   Usage:
17395bd1e576SStefano Zampini $    extern PetscErrorCode mult(Mat,Vec,Vec);
1740f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
1741c134de8dSSatish Balay $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1742f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
1743f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
1744f39d1f56SLois Curfman McInnes 
1745ff756334SLois Curfman McInnes    Notes:
1746ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
1747ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
1748ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
1749e51e0e81SBarry Smith 
175095452b02SPatrick Sanan    Fortran Notes:
175195452b02SPatrick Sanan     To use this from Fortran with a ctx you must write an interface definition for this
1752daf670e6SBarry Smith     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
1753daf670e6SBarry Smith     in as the ctx argument.
1754f38a8d56SBarry Smith 
1755f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
1756f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
1757645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
1758645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
1759645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
1760645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
1761645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
1762645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
1763645985a0SLois Curfman McInnes    For example,
1764f39d1f56SLois Curfman McInnes 
1765f39d1f56SLois Curfman McInnes $
1766f39d1f56SLois Curfman McInnes $     Vec x, y
17675bd1e576SStefano Zampini $     extern PetscErrorCode mult(Mat,Vec,Vec);
1768645985a0SLois Curfman McInnes $     Mat A
1769f39d1f56SLois Curfman McInnes $
1770c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
1771c94f878dSBarry Smith $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
1772f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
1773c7fcc2eaSBarry Smith $     VecGetLocalSize(x,&n);
1774c7fcc2eaSBarry Smith $     MatCreateShell(comm,m,n,M,N,ctx,&A);
1775c134de8dSSatish Balay $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
1776645985a0SLois Curfman McInnes $     MatMult(A,x,y);
177745960306SStefano Zampini $     MatDestroy(&A);
177845960306SStefano Zampini $     VecDestroy(&y);
177945960306SStefano Zampini $     VecDestroy(&x);
1780645985a0SLois Curfman McInnes $
1781e51e0e81SBarry Smith 
17829b53d762SBarry 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 
17869b53d762SBarry Smith 
17870c0fd78eSBarry Smith     For rectangular matrices do all the scalings and shifts make sense?
17880c0fd78eSBarry Smith 
178995452b02SPatrick Sanan     Developers Notes:
179095452b02SPatrick Sanan     Regarding shifting and scaling. The general form is
17910c0fd78eSBarry Smith 
17920c0fd78eSBarry Smith           diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
17930c0fd78eSBarry Smith 
17940c0fd78eSBarry Smith       The order you apply the operations is important. For example if you have a dshift then
17950c0fd78eSBarry Smith       apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift
17960c0fd78eSBarry Smith       you get s*vscale*A + diag(shift)
17970c0fd78eSBarry Smith 
17980c0fd78eSBarry Smith           A is the user provided function.
17990c0fd78eSBarry Smith 
1800ad2f5c3fSBarry Smith    KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for
1801ad2f5c3fSBarry Smith    for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger
1802ad2f5c3fSBarry Smith    an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat);
1803ad2f5c3fSBarry Smith    each time the MATSHELL matrix has changed.
1804ad2f5c3fSBarry Smith 
1805*b77ba244SStefano Zampini    Matrix product operations (i.e. MatMat, MatTranposeMat etc) can be specified using MatShellSetMatProductOperation()
1806*b77ba244SStefano Zampini 
1807ad2f5c3fSBarry Smith    Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided
1808ad2f5c3fSBarry Smith    with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().
1809ad2f5c3fSBarry Smith 
1810*b77ba244SStefano Zampini .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts(), MatShellSetMatProductOperation()
1811e51e0e81SBarry Smith @*/
18127087cfbeSBarry Smith PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
1813e51e0e81SBarry Smith {
1814dfbe8321SBarry Smith   PetscErrorCode ierr;
1815ed3cc1f0SBarry Smith 
18163a40ed3dSBarry Smith   PetscFunctionBegin;
1817f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,A);CHKERRQ(ierr);
1818f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
1819273d9f13SBarry Smith   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
1820273d9f13SBarry Smith   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
18210fcd0fccSJed Brown   ierr = MatSetUp(*A);CHKERRQ(ierr);
1822273d9f13SBarry Smith   PetscFunctionReturn(0);
1823c7fcc2eaSBarry Smith }
1824c7fcc2eaSBarry Smith 
1825c6866cfdSSatish Balay /*@
1826273d9f13SBarry Smith     MatShellSetContext - sets the context for a shell matrix
1827c7fcc2eaSBarry Smith 
18283f9fe445SBarry Smith    Logically Collective on Mat
1829c7fcc2eaSBarry Smith 
1830273d9f13SBarry Smith     Input Parameters:
1831273d9f13SBarry Smith +   mat - the shell matrix
1832273d9f13SBarry Smith -   ctx - the context
1833273d9f13SBarry Smith 
1834273d9f13SBarry Smith    Level: advanced
1835273d9f13SBarry Smith 
183695452b02SPatrick Sanan    Fortran Notes:
183795452b02SPatrick Sanan     To use this from Fortran you must write a Fortran interface definition for this
1838daf670e6SBarry Smith     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.
1839273d9f13SBarry Smith 
1840273d9f13SBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
18410bc0a719SBarry Smith @*/
18427087cfbeSBarry Smith PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
1843273d9f13SBarry Smith {
1844dfbe8321SBarry Smith   PetscErrorCode ierr;
1845273d9f13SBarry Smith 
1846273d9f13SBarry Smith   PetscFunctionBegin;
18470700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1848ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(mat,"MatShellSetContext_C",(Mat,void*),(mat,ctx));CHKERRQ(ierr);
18493a40ed3dSBarry Smith   PetscFunctionReturn(0);
1850e51e0e81SBarry Smith }
1851e51e0e81SBarry Smith 
1852db77db73SJeremy L Thompson /*@C
1853db77db73SJeremy L Thompson  MatShellSetVecType - Sets the type of Vec returned by MatCreateVecs()
1854db77db73SJeremy L Thompson 
1855db77db73SJeremy L Thompson  Logically collective
1856db77db73SJeremy L Thompson 
1857db77db73SJeremy L Thompson     Input Parameters:
1858db77db73SJeremy L Thompson +   mat   - the shell matrix
1859db77db73SJeremy L Thompson -   vtype - type to use for creating vectors
1860db77db73SJeremy L Thompson 
1861db77db73SJeremy L Thompson  Notes:
1862db77db73SJeremy L Thompson 
1863db77db73SJeremy L Thompson  Level: advanced
1864db77db73SJeremy L Thompson 
1865db77db73SJeremy L Thompson .seealso: MatCreateVecs()
1866db77db73SJeremy L Thompson @*/
1867db77db73SJeremy L Thompson PetscErrorCode  MatShellSetVecType(Mat mat,VecType vtype)
1868db77db73SJeremy L Thompson {
1869db77db73SJeremy L Thompson   PetscErrorCode ierr;
1870db77db73SJeremy L Thompson 
1871db77db73SJeremy L Thompson   PetscFunctionBegin;
1872db77db73SJeremy L Thompson   ierr = PetscTryMethod(mat,"MatShellSetVecType_C",(Mat,VecType),(mat,vtype));CHKERRQ(ierr);
1873db77db73SJeremy L Thompson   PetscFunctionReturn(0);
1874db77db73SJeremy L Thompson }
1875db77db73SJeremy L Thompson 
18760c0fd78eSBarry Smith /*@
18770c0fd78eSBarry Smith     MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately
18780c0fd78eSBarry Smith           after MatCreateShell()
18790c0fd78eSBarry Smith 
18800c0fd78eSBarry Smith    Logically Collective on Mat
18810c0fd78eSBarry Smith 
18820c0fd78eSBarry Smith     Input Parameter:
18830c0fd78eSBarry Smith .   mat - the shell matrix
18840c0fd78eSBarry Smith 
18850c0fd78eSBarry Smith   Level: advanced
18860c0fd78eSBarry Smith 
18870c0fd78eSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation()
18880c0fd78eSBarry Smith @*/
18890c0fd78eSBarry Smith PetscErrorCode MatShellSetManageScalingShifts(Mat A)
18900c0fd78eSBarry Smith {
18910c0fd78eSBarry Smith   PetscErrorCode ierr;
18920c0fd78eSBarry Smith 
18930c0fd78eSBarry Smith   PetscFunctionBegin;
18940c0fd78eSBarry Smith   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1895ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(A,"MatShellSetManageScalingShifts_C",(Mat),(A));CHKERRQ(ierr);
18960c0fd78eSBarry Smith   PetscFunctionReturn(0);
18970c0fd78eSBarry Smith }
18980c0fd78eSBarry Smith 
1899c16cb8f2SBarry Smith /*@C
1900f3b1f45cSBarry Smith     MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function.
1901f3b1f45cSBarry Smith 
1902f3b1f45cSBarry Smith    Logically Collective on Mat
1903f3b1f45cSBarry Smith 
1904f3b1f45cSBarry Smith     Input Parameters:
1905f3b1f45cSBarry Smith +   mat - the shell matrix
1906f3b1f45cSBarry Smith .   f - the function
1907f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1908f3b1f45cSBarry Smith -   ctx - an optional context for the function
1909f3b1f45cSBarry Smith 
1910f3b1f45cSBarry Smith    Output Parameter:
1911f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1912f3b1f45cSBarry Smith 
1913f3b1f45cSBarry Smith    Options Database:
1914f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1915f3b1f45cSBarry Smith 
1916f3b1f45cSBarry Smith    Level: advanced
1917f3b1f45cSBarry Smith 
191895452b02SPatrick Sanan    Fortran Notes:
191995452b02SPatrick Sanan     Not supported from Fortran
1920f3b1f45cSBarry Smith 
1921f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose()
1922f3b1f45cSBarry Smith @*/
1923f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1924f3b1f45cSBarry Smith {
1925f3b1f45cSBarry Smith   PetscErrorCode ierr;
1926f3b1f45cSBarry Smith   PetscInt       m,n;
1927f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1928f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
192974e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1930f3b1f45cSBarry Smith 
1931f3b1f45cSBarry Smith   PetscFunctionBegin;
1932f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1933f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr);
1934f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
1935f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr);
1936f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
1937f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
1938f3b1f45cSBarry Smith 
19390bacdadaSStefano Zampini   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
19400bacdadaSStefano Zampini   ierr = MatComputeOperator(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
1941f3b1f45cSBarry Smith 
1942f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
1943f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
1944f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
1945f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
1946f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
1947f3b1f45cSBarry Smith     flag = PETSC_FALSE;
1948f3b1f45cSBarry Smith     if (v) {
1949fc7aafd1SBarry 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);
1950f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1951f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1952f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr);
1953f3b1f45cSBarry Smith     }
1954f3b1f45cSBarry Smith   } else if (v) {
1955fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
1956f3b1f45cSBarry Smith   }
1957f3b1f45cSBarry Smith   if (flg) *flg = flag;
1958f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
1959f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
1960f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
1961f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
1962f3b1f45cSBarry Smith   PetscFunctionReturn(0);
1963f3b1f45cSBarry Smith }
1964f3b1f45cSBarry Smith 
1965f3b1f45cSBarry Smith /*@C
1966f3b1f45cSBarry Smith     MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function.
1967f3b1f45cSBarry Smith 
1968f3b1f45cSBarry Smith    Logically Collective on Mat
1969f3b1f45cSBarry Smith 
1970f3b1f45cSBarry Smith     Input Parameters:
1971f3b1f45cSBarry Smith +   mat - the shell matrix
1972f3b1f45cSBarry Smith .   f - the function
1973f3b1f45cSBarry Smith .   base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated
1974f3b1f45cSBarry Smith -   ctx - an optional context for the function
1975f3b1f45cSBarry Smith 
1976f3b1f45cSBarry Smith    Output Parameter:
1977f3b1f45cSBarry Smith .   flg - PETSC_TRUE if the multiply is likely correct
1978f3b1f45cSBarry Smith 
1979f3b1f45cSBarry Smith    Options Database:
1980f3b1f45cSBarry Smith .   -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference
1981f3b1f45cSBarry Smith 
1982f3b1f45cSBarry Smith    Level: advanced
1983f3b1f45cSBarry Smith 
198495452b02SPatrick Sanan    Fortran Notes:
198595452b02SPatrick Sanan     Not supported from Fortran
1986f3b1f45cSBarry Smith 
1987f3b1f45cSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult()
1988f3b1f45cSBarry Smith @*/
1989f3b1f45cSBarry Smith PetscErrorCode  MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg)
1990f3b1f45cSBarry Smith {
1991f3b1f45cSBarry Smith   PetscErrorCode ierr;
1992f3b1f45cSBarry Smith   Vec            x,y,z;
1993f3b1f45cSBarry Smith   PetscInt       m,n,M,N;
1994f3b1f45cSBarry Smith   Mat            mf,Dmf,Dmat,Ddiff;
1995f3b1f45cSBarry Smith   PetscReal      Diffnorm,Dmfnorm;
199674e5cdcaSBarry Smith   PetscBool      v = PETSC_FALSE, flag = PETSC_TRUE;
1997f3b1f45cSBarry Smith 
1998f3b1f45cSBarry Smith   PetscFunctionBegin;
1999f3b1f45cSBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2000f3b1f45cSBarry Smith   ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr);
2001f3b1f45cSBarry Smith   ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr);
2002f3b1f45cSBarry Smith   ierr = VecDuplicate(y,&z);CHKERRQ(ierr);
2003f3b1f45cSBarry Smith   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
2004f3b1f45cSBarry Smith   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
2005f3b1f45cSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr);
2006f3b1f45cSBarry Smith   ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr);
2007f3b1f45cSBarry Smith   ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr);
20080bacdadaSStefano Zampini   ierr = MatComputeOperator(mf,MATAIJ,&Dmf);CHKERRQ(ierr);
2009f3b1f45cSBarry Smith   ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr);
20100bacdadaSStefano Zampini   ierr = MatComputeOperatorTranspose(mat,MATAIJ,&Dmat);CHKERRQ(ierr);
2011f3b1f45cSBarry Smith 
2012f3b1f45cSBarry Smith   ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr);
2013f3b1f45cSBarry Smith   ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
2014f3b1f45cSBarry Smith   ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr);
2015f3b1f45cSBarry Smith   ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr);
2016f3b1f45cSBarry Smith   if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) {
2017f3b1f45cSBarry Smith     flag = PETSC_FALSE;
2018f3b1f45cSBarry Smith     if (v) {
2019fc7aafd1SBarry 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);
2020f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2021f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2022f3b1f45cSBarry Smith       ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr);
2023f3b1f45cSBarry Smith     }
2024f3b1f45cSBarry Smith   } else if (v) {
2025fc7aafd1SBarry Smith     ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n");CHKERRQ(ierr);
2026f3b1f45cSBarry Smith   }
2027f3b1f45cSBarry Smith   if (flg) *flg = flag;
2028f3b1f45cSBarry Smith   ierr = MatDestroy(&mf);CHKERRQ(ierr);
2029f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmat);CHKERRQ(ierr);
2030f3b1f45cSBarry Smith   ierr = MatDestroy(&Ddiff);CHKERRQ(ierr);
2031f3b1f45cSBarry Smith   ierr = MatDestroy(&Dmf);CHKERRQ(ierr);
2032f3b1f45cSBarry Smith   ierr = VecDestroy(&x);CHKERRQ(ierr);
2033f3b1f45cSBarry Smith   ierr = VecDestroy(&y);CHKERRQ(ierr);
2034f3b1f45cSBarry Smith   ierr = VecDestroy(&z);CHKERRQ(ierr);
2035f3b1f45cSBarry Smith   PetscFunctionReturn(0);
2036f3b1f45cSBarry Smith }
2037f3b1f45cSBarry Smith 
2038f3b1f45cSBarry Smith /*@C
20390c0fd78eSBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for a shell matrix.
2040e51e0e81SBarry Smith 
20413f9fe445SBarry Smith    Logically Collective on Mat
2042fee21e36SBarry Smith 
2043c7fcc2eaSBarry Smith     Input Parameters:
2044c7fcc2eaSBarry Smith +   mat - the shell matrix
2045c7fcc2eaSBarry Smith .   op - the name of the operation
2046789d8953SBarry Smith -   g - the function that provides the operation.
2047c7fcc2eaSBarry Smith 
204815091d37SBarry Smith    Level: advanced
204915091d37SBarry Smith 
2050fae171e0SBarry Smith     Usage:
2051e93bc3c1Svictor $      extern PetscErrorCode usermult(Mat,Vec,Vec);
2052*b77ba244SStefano Zampini $      MatCreateShell(comm,m,n,M,N,ctx,&A);
2053*b77ba244SStefano Zampini $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
20540b627109SLois Curfman McInnes 
2055a62d957aSLois Curfman McInnes     Notes:
2056e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
20571c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
2058a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
20591c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
2060a62d957aSLois Curfman McInnes 
2061a4d85fd7SBarry Smith     All user-provided functions (except for MATOP_DESTROY) should have the same calling
2062deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
2063deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
2064deebb3c3SLois Curfman McInnes     routines, e.g.,
2065a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2066a62d957aSLois Curfman McInnes 
20674aa34b0aSBarry Smith     In particular each function MUST return an error code of 0 on success and
20684aa34b0aSBarry Smith     nonzero on failure.
20694aa34b0aSBarry Smith 
2070a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
2071a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
2072a62d957aSLois Curfman McInnes     set by MatCreateShell().
2073a62d957aSLois Curfman McInnes 
2074*b77ba244SStefano Zampini     Use MatSetOperation() to set an operation for any matrix type. For matrix product operations (i.e. MatMat, MatTransposeMat etc) use MatShellSetMatProductOperation()
2075*b77ba244SStefano Zampini 
207695452b02SPatrick Sanan     Fortran Notes:
207795452b02SPatrick Sanan     For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
2078c4762a1bSJed Brown        generate a matrix. See src/mat/tests/ex120f.F
2079501d9185SBarry Smith 
2080*b77ba244SStefano Zampini .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts(), MatShellSetMatProductOperation()
2081e51e0e81SBarry Smith @*/
2082789d8953SBarry Smith PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*g)(void))
2083e51e0e81SBarry Smith {
2084976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
2085273d9f13SBarry Smith 
20863a40ed3dSBarry Smith   PetscFunctionBegin;
20870700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2088ef5c7bd2SStefano Zampini   ierr = PetscTryMethod(mat,"MatShellSetOperation_C",(Mat,MatOperation,void (*)(void)),(mat,op,g));CHKERRQ(ierr);
20893a40ed3dSBarry Smith   PetscFunctionReturn(0);
2090e51e0e81SBarry Smith }
2091f0479e8cSBarry Smith 
2092d4bb536fSBarry Smith /*@C
2093d4bb536fSBarry Smith     MatShellGetOperation - Gets a matrix function for a shell matrix.
2094d4bb536fSBarry Smith 
2095c7fcc2eaSBarry Smith     Not Collective
2096c7fcc2eaSBarry Smith 
2097d4bb536fSBarry Smith     Input Parameters:
2098c7fcc2eaSBarry Smith +   mat - the shell matrix
2099c7fcc2eaSBarry Smith -   op - the name of the operation
2100d4bb536fSBarry Smith 
2101d4bb536fSBarry Smith     Output Parameter:
2102789d8953SBarry Smith .   g - the function that provides the operation.
2103d4bb536fSBarry Smith 
210415091d37SBarry Smith     Level: advanced
210515091d37SBarry Smith 
2106d4bb536fSBarry Smith     Notes:
2107e090d566SSatish Balay     See the file include/petscmat.h for a complete list of matrix
2108d4bb536fSBarry Smith     operations, which all have the form MATOP_<OPERATION>, where
2109d4bb536fSBarry Smith     <OPERATION> is the name (in all capital letters) of the
2110d4bb536fSBarry Smith     user interface routine (e.g., MatMult() -> MATOP_MULT).
2111d4bb536fSBarry Smith 
2112d4bb536fSBarry Smith     All user-provided functions have the same calling
2113d4bb536fSBarry Smith     sequence as the usual matrix interface routines, since they
2114d4bb536fSBarry Smith     are intended to be accessed via the usual matrix interface
2115d4bb536fSBarry Smith     routines, e.g.,
2116d4bb536fSBarry Smith $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
2117d4bb536fSBarry Smith 
2118d4bb536fSBarry Smith     Within each user-defined routine, the user should call
2119d4bb536fSBarry Smith     MatShellGetContext() to obtain the user-defined context that was
2120d4bb536fSBarry Smith     set by MatCreateShell().
2121d4bb536fSBarry Smith 
2122ab50ec6bSBarry Smith .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
2123d4bb536fSBarry Smith @*/
2124789d8953SBarry Smith PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**g)(void))
2125d4bb536fSBarry Smith {
2126976e8c5aSLisandro Dalcin   PetscErrorCode ierr;
2127273d9f13SBarry Smith 
21283a40ed3dSBarry Smith   PetscFunctionBegin;
21290700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2130789d8953SBarry Smith   ierr = PetscUseMethod(mat,"MatShellGetOperation_C",(Mat,MatOperation,void (**)(void)),(mat,op,g));CHKERRQ(ierr);
21313a40ed3dSBarry Smith   PetscFunctionReturn(0);
2132d4bb536fSBarry Smith }
2133*b77ba244SStefano Zampini 
2134*b77ba244SStefano Zampini /*@
2135*b77ba244SStefano Zampini     MatIsShell - Inquires if a matrix is derived from MATSHELL
2136*b77ba244SStefano Zampini 
2137*b77ba244SStefano Zampini     Input Parameter:
2138*b77ba244SStefano Zampini .   mat - the matrix
2139*b77ba244SStefano Zampini 
2140*b77ba244SStefano Zampini     Output Parameter:
2141*b77ba244SStefano Zampini .   flg - the boolean value
2142*b77ba244SStefano Zampini 
2143*b77ba244SStefano Zampini     Level: developer
2144*b77ba244SStefano Zampini 
2145*b77ba244SStefano 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)
2146*b77ba244SStefano Zampini 
2147*b77ba244SStefano Zampini .seealso: MatCreateShell()
2148*b77ba244SStefano Zampini @*/
2149*b77ba244SStefano Zampini PetscErrorCode MatIsShell(Mat mat, PetscBool *flg)
2150*b77ba244SStefano Zampini {
2151*b77ba244SStefano Zampini   PetscFunctionBegin;
2152*b77ba244SStefano Zampini   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2153*b77ba244SStefano Zampini   PetscValidPointer(flg,2);
2154*b77ba244SStefano Zampini   *flg = (PetscBool)(mat->ops->destroy == MatDestroy_Shell);
2155*b77ba244SStefano Zampini   PetscFunctionReturn(0);
2156*b77ba244SStefano Zampini }
2157