#include "petscmat.h" PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)Collective
comm | - MPI communicator | |
m | - number of local rows (must be given) | |
n | - number of local columns (must be given) | |
M | - number of global rows (may be PETSC_DETERMINE) | |
N | - number of global columns (may be PETSC_DETERMINE) | |
ctx | - pointer to data needed by the shell matrix routines |
extern PetscErrorCode mult(Mat,Vec,Vec);
MatCreateShell(comm,m,n,M,N,ctx,&mat);
MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
[ Use matrix for operations that have been set ]
MatDestroy(mat);
PETSc requires that matrices and vectors being used for certain operations are partitioned accordingly. For example, when creating a shell matrix, A, that supports parallel matrix-vector products using MatMult(A,x,y) the user should set the number of local matrix rows to be the number of local elements of the corresponding result vector, y. Note that this is information is required for use of the matrix interface routines, even though the shell matrix may not actually be physically partitioned. For example,
Vec x, y
extern PetscErrorCode mult(Mat,Vec,Vec);
Mat A
VecCreateMPI(comm,PETSC_DECIDE,M,&y);
VecCreateMPI(comm,PETSC_DECIDE,N,&x);
VecGetLocalSize(y,&m);
VecGetLocalSize(x,&n);
MatCreateShell(comm,m,n,M,N,ctx,&A);
MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
MatMult(A,x,y);
MatDestroy(&A);
VecDestroy(&y);
VecDestroy(&x);
MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), MatAXPY(), MatScale(), MatZeroRows() and MatZeroRowsColumns() internally, so these operations cannot be overwritten unless MatShellSetManageScalingShifts() is called.
For rectangular matrices do all the scalings and shifts make sense?
diag(left)(vscale*A + diag(dshift) + vshift I)diag(right)
The order you apply the operations is important. For example if you have a dshift then apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift you get s*vscale*A + diag(shift)
A is the user provided function.
KSP/PC uses changes in the Mat's "state" to decide if preconditioners need to be rebuilt: PCSetUp() only calls the setup() for for the PC implementation if the Mat state has increased from the previous call. Thus to get changes in a MATSHELL to trigger an update in the preconditioner you must call MatAssemblyBegin()/MatAssemblyEnd() or PetscObjectStateIncrease((PetscObject)mat); each time the MATSHELL matrix has changed.
Calling MatAssemblyBegin()/MatAssemblyEnd() on a MATSHELL removes any previously supplied shift and scales that were provided with MatDiagonalSet(), MatShift(), MatScale(), or MatDiagonalScale().