1 #ifndef lint 2 static char vcid[] = "$Id: shell.c,v 1.41 1996/12/17 16:54:19 balay Exp balay $"; 3 #endif 4 5 /* 6 This provides a simple shell for Fortran (and C programmers) to 7 create a very simple matrix class for use with KSP without coding 8 much of anything. 9 */ 10 11 #include "petsc.h" 12 #include "src/mat/matimpl.h" /*I "mat.h" I*/ 13 #include "src/vec/vecimpl.h" 14 15 typedef struct { 16 int M, N; /* number of global rows, columns */ 17 int m, n; /* number of local rows, columns */ 18 int (*destroy)(Mat); 19 void *ctx; 20 } Mat_Shell; 21 22 #undef __FUNC__ 23 #define __FUNC__ "MatShellGetContext" 24 /*@ 25 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 26 27 Input Parameter: 28 . mat - the matrix, should have been created with MatCreateShell() 29 30 Output Parameter: 31 . ctx - the user provided context 32 33 Notes: 34 This routine is intended for use within various shell matrix routines, 35 as set with MatShellSetOperation(). 36 37 .keywords: matrix, shell, get, context 38 39 .seealso: MatCreateShell(), MatShellSetOperation() 40 @*/ 41 int MatShellGetContext(Mat mat,void **ctx) 42 { 43 PetscValidHeaderSpecific(mat,MAT_COOKIE); 44 if (mat->type != MATSHELL) *ctx = 0; 45 else *ctx = ((Mat_Shell *) (mat->data))->ctx; 46 return 0; 47 } 48 49 #undef __FUNC__ 50 #define __FUNC__ "MatGetSize_Shell" 51 static int MatGetSize_Shell(Mat mat,int *M,int *N) 52 { 53 Mat_Shell *shell = (Mat_Shell *) mat->data; 54 *M = shell->M; *N = shell->N; 55 return 0; 56 } 57 58 #undef __FUNC__ 59 #define __FUNC__ "MatGetLocalSize_Shell" 60 static int MatGetLocalSize_Shell(Mat mat,int *m,int *n) 61 { 62 Mat_Shell *shell = (Mat_Shell *) mat->data; 63 *m = shell->n; *n = shell->n; 64 return 0; 65 } 66 67 #undef __FUNC__ 68 #define __FUNC__ "MatDestroy_Shell" 69 static int MatDestroy_Shell(PetscObject obj) 70 { 71 int ierr; 72 Mat mat = (Mat) obj; 73 Mat_Shell *shell; 74 75 shell = (Mat_Shell *) mat->data; 76 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 77 PetscFree(shell); 78 PLogObjectDestroy(mat); 79 PetscHeaderDestroy(mat); 80 return 0; 81 } 82 83 static struct _MatOps MatOps = {0,0, 84 0, 85 0,0,0,0, 86 0,0,0,0, 87 0,0, 88 0, 89 0, 90 0,0,0, 91 0, 92 0,0,0, 93 0,0, 94 0, 95 0,0,0,0, 96 0,MatGetSize_Shell,MatGetLocalSize_Shell, 97 0,0,0, 98 0,0,0,0 }; 99 100 #undef __FUNC__ 101 #define __FUNC__ "MatCreateShell" 102 /*@C 103 MatCreateShell - Creates a new matrix class for use with a user-defined 104 private data storage format. 105 106 Input Parameters: 107 . comm - MPI communicator 108 . m - number of local rows 109 . n - number of local columns 110 . M - number of global rows 111 . N - number of global columns 112 . ctx - pointer to data needed by the shell matrix routines 113 114 Output Parameter: 115 . A - the matrix 116 117 Usage: 118 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 119 $ MatShellSetOperation(mat,MATOP_MULT,mult); 120 $ [ Use matrix for operations that have been set ] 121 $ MatDestroy(mat); 122 123 Notes: 124 The shell matrix type is intended to provide a simple class to use 125 with KSP (such as, for use with matrix-free methods). You should not 126 use the shell type if you plan to define a complete matrix class. 127 128 PETSc requires that matrices and vectors being used for certain 129 operations are partitioned accordingly. For example, when 130 creating a shell matrix, A, that supports parallel matrix-vector 131 products using MatMult(A,x,y) the user should set the number 132 of local matrix rows to be the number of local elements of the 133 corresponding result vector, y. Note that this is information is 134 required for use of the matrix interface routines, even though 135 the shell matrix may not actually be physically partitioned. 136 For example, 137 138 $ 139 $ Vec x, y 140 $ Mat A 141 $ 142 $ VecCreate(comm,M,&y); 143 $ VecCreate(comm,N,&x); 144 $ VecGetLocalSize(y,&m); 145 $ MatCreateShell(comm,m,N,M,N,ctx,&A); 146 $ MatShellSetOperation(mat,MATOP_MULT,mult); 147 $ MatMult(A,x,y); 148 $ MatDestroy(A); 149 $ VecDestroy(y); VecDestroy(x); 150 $ 151 152 .keywords: matrix, shell, create 153 154 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 155 @*/ 156 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 157 { 158 Mat B; 159 Mat_Shell *b; 160 161 PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSHELL,comm); 162 PLogObjectCreate(B); 163 B->factor = 0; 164 B->destroy = MatDestroy_Shell; 165 B->assembled = PETSC_TRUE; 166 PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps)); 167 168 b = PetscNew(Mat_Shell); CHKPTRQ(b); 169 PetscMemzero(b,sizeof(Mat_Shell)); 170 B->data = (void *) b; 171 b->M = M; B->M = M; 172 b->N = N; B->N = N; 173 b->m = m; B->m = m; 174 b->n = n; B->n = n; 175 b->ctx = ctx; 176 *A = B; 177 return 0; 178 } 179 180 #undef __FUNC__ 181 #define __FUNC__ "MatShellSetOperation" 182 /*@C 183 MatShellSetOperation - Allows user to set a matrix operation for 184 a shell matrix. 185 186 Input Parameters: 187 . mat - the shell matrix 188 . op - the name of the operation 189 . f - the function that provides the operation. 190 191 Usage: 192 $ extern int usermult(Mat,Vec,Vec); 193 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 194 $ ierr = MatShellSetOperation(A,MATOP_MULT,usermult); 195 196 Notes: 197 See the file petsc/include/mat.h for a complete list of matrix 198 operations, which all have the form MATOP_<OPERATION>, where 199 <OPERATION> is the name (in all capital letters) of the 200 user interface routine (e.g., MatMult() -> MATOP_MULT). 201 202 All user-provided functions should have the same calling 203 sequence as the usual matrix interface routines, since they 204 are intended to be accessed via the usual matrix interface 205 routines, e.g., 206 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 207 208 Within each user-defined routine, the user should call 209 MatShellGetContext() to obtain the user-defined context that was 210 set by MatCreateShell(). 211 212 .keywords: matrix, shell, set, operation 213 214 .seealso: MatCreateShell(), MatShellGetContext() 215 @*/ 216 int MatShellSetOperation(Mat mat,MatOperation op, void *f) 217 { 218 PetscValidHeaderSpecific(mat,MAT_COOKIE); 219 220 if (op == MATOP_DESTROY) { 221 if (mat->type == MATSHELL) { 222 Mat_Shell *shell = (Mat_Shell *) mat->data; 223 shell->destroy = (int (*)(Mat)) f; 224 } 225 else mat->destroy = (int (*)(PetscObject)) f; 226 } 227 else if (op == MATOP_VIEW) mat->view = (int (*)(PetscObject,Viewer)) f; 228 else (((void**)&mat->ops)[op]) = f; 229 230 return 0; 231 } 232 233 234 235 236 237 238