1 /*$Id: shell.c,v 1.81 2000/07/10 03:39:36 bsmith Exp bsmith $*/ 2 3 /* 4 This provides a simple shell for Fortran (and C programmers) to 5 create a very simple matrix class for use with KSP without coding 6 much of anything. 7 */ 8 9 #include "src/mat/matimpl.h" /*I "petscmat.h" I*/ 10 #include "src/vec/vecimpl.h" 11 12 typedef struct { 13 int M,N; /* number of global rows, columns */ 14 int m,n; /* number of local rows, columns */ 15 int (*destroy)(Mat); 16 void *ctx; 17 } Mat_Shell; 18 19 #undef __FUNC__ 20 #define __FUNC__ /*<a name=""></a>*/"MatShellGetContext" 21 /*@ 22 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 23 24 Not Collective 25 26 Input Parameter: 27 . mat - the matrix, should have been created with MatCreateShell() 28 29 Output Parameter: 30 . ctx - the user provided context 31 32 Level: advanced 33 34 Notes: 35 This routine is intended for use within various shell matrix routines, 36 as set with MatShellSetOperation(). 37 38 .keywords: matrix, shell, get, context 39 40 .seealso: MatCreateShell(), MatShellSetOperation() 41 @*/ 42 int MatShellGetContext(Mat mat,void **ctx) 43 { 44 PetscFunctionBegin; 45 PetscValidHeaderSpecific(mat,MAT_COOKIE); 46 if (mat->type != MATSHELL) *ctx = 0; 47 else *ctx = ((Mat_Shell*)(mat->data))->ctx; 48 PetscFunctionReturn(0); 49 } 50 51 #undef __FUNC__ 52 #define __FUNC__ /*<a name=""></a>*/"MatGetSize_Shell" 53 int MatGetSize_Shell(Mat mat,int *M,int *N) 54 { 55 Mat_Shell *shell = (Mat_Shell*)mat->data; 56 57 PetscFunctionBegin; 58 if (M) *M = shell->M; 59 if (N) *N = shell->N; 60 PetscFunctionReturn(0); 61 } 62 63 #undef __FUNC__ 64 #define __FUNC__ /*<a name=""></a>*/"MatGetLocalSize_Shell" 65 int MatGetLocalSize_Shell(Mat mat,int *m,int *n) 66 { 67 Mat_Shell *shell = (Mat_Shell*)mat->data; 68 69 PetscFunctionBegin; 70 if (m) *m = shell->m; 71 if (n) *n = shell->n; 72 PetscFunctionReturn(0); 73 } 74 75 #undef __FUNC__ 76 #define __FUNC__ /*<a name=""></a>*/"MatDestroy_Shell" 77 int MatDestroy_Shell(Mat mat) 78 { 79 int ierr; 80 Mat_Shell *shell; 81 82 PetscFunctionBegin; 83 84 if (mat->mapping) { 85 ierr = ISLocalToGlobalMappingDestroy(mat->mapping);CHKERRQ(ierr); 86 } 87 if (mat->bmapping) { 88 ierr = ISLocalToGlobalMappingDestroy(mat->bmapping);CHKERRQ(ierr); 89 } 90 if (mat->rmap) { 91 ierr = MapDestroy(mat->rmap);CHKERRQ(ierr); 92 } 93 if (mat->cmap) { 94 ierr = MapDestroy(mat->cmap);CHKERRQ(ierr); 95 } 96 shell = (Mat_Shell*)mat->data; 97 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 98 ierr = PetscFree(shell);CHKERRQ(ierr); 99 PLogObjectDestroy(mat); 100 PetscHeaderDestroy(mat); 101 PetscFunctionReturn(0); 102 } 103 104 #undef __FUNC__ 105 #define __FUNC__ /*<a name=""></a>*/"MatGetOwnershipRange_Shell" 106 int MatGetOwnershipRange_Shell(Mat mat,int *rstart,int *rend) 107 { 108 int ierr,tmp; 109 110 PetscFunctionBegin; 111 ierr = MPI_Scan(&mat->m,&tmp,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr); 112 if (rstart) *rstart = tmp - mat->m; 113 if (rend) *rend = tmp; 114 PetscFunctionReturn(0); 115 } 116 117 static struct _MatOps MatOps_Values = {0, 118 0, 119 0, 120 0, 121 0, 122 0, 123 0, 124 0, 125 0, 126 0, 127 0, 128 0, 129 0, 130 0, 131 0, 132 0, 133 0, 134 0, 135 0, 136 0, 137 0, 138 0, 139 0, 140 0, 141 0, 142 0, 143 0, 144 0, 145 0, 146 0, 147 MatGetSize_Shell, 148 MatGetLocalSize_Shell, 149 MatGetOwnershipRange_Shell, 150 0, 151 0, 152 0, 153 0, 154 0, 155 0, 156 0, 157 0, 158 0, 159 0, 160 0, 161 0, 162 0, 163 0, 164 0, 165 0, 166 0, 167 0, 168 0, 169 0, 170 0, 171 0, 172 0, 173 0, 174 0, 175 0, 176 0, 177 0, 178 0, 179 0, 180 MatDestroy_Shell, 181 0, 182 MatGetMaps_Petsc}; 183 184 #undef __FUNC__ 185 #define __FUNC__ /*<a name=""></a>*/"MatCreateShell" 186 /*@C 187 MatCreateShell - Creates a new matrix class for use with a user-defined 188 private data storage format. 189 190 Collective on MPI_Comm 191 192 Input Parameters: 193 + comm - MPI communicator 194 . m - number of local rows (must be given) 195 . n - number of local columns (must be given) 196 . M - number of global rows (may be PETSC_DETERMINE) 197 . N - number of global columns (may be PETSC_DETERMINE) 198 - ctx - pointer to data needed by the shell matrix routines 199 200 Output Parameter: 201 . A - the matrix 202 203 Level: advanced 204 205 Usage: 206 $ extern int mult(Mat,Vec,Vec); 207 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 208 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 209 $ [ Use matrix for operations that have been set ] 210 $ MatDestroy(mat); 211 212 Notes: 213 The shell matrix type is intended to provide a simple class to use 214 with KSP (such as, for use with matrix-free methods). You should not 215 use the shell type if you plan to define a complete matrix class. 216 217 PETSc requires that matrices and vectors being used for certain 218 operations are partitioned accordingly. For example, when 219 creating a shell matrix, A, that supports parallel matrix-vector 220 products using MatMult(A,x,y) the user should set the number 221 of local matrix rows to be the number of local elements of the 222 corresponding result vector, y. Note that this is information is 223 required for use of the matrix interface routines, even though 224 the shell matrix may not actually be physically partitioned. 225 For example, 226 227 $ 228 $ Vec x, y 229 $ extern int mult(Mat,Vec,Vec); 230 $ Mat A 231 $ 232 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 233 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 234 $ VecGetLocalSize(y,&m); 235 $ VecGetLocalSize(x,&n); 236 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 237 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 238 $ MatMult(A,x,y); 239 $ MatDestroy(A); 240 $ VecDestroy(y); VecDestroy(x); 241 $ 242 243 .keywords: matrix, shell, create 244 245 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 246 @*/ 247 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 248 { 249 Mat B; 250 Mat_Shell *b; 251 int ierr; 252 253 PetscFunctionBegin; 254 PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,"Mat",comm,MatDestroy,MatView); 255 PLogObjectCreate(B); 256 B->factor = 0; 257 B->assembled = PETSC_TRUE; 258 ierr = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 259 260 b = PetscNew(Mat_Shell);CHKPTRQ(b); 261 PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 262 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 263 B->data = (void*)b; 264 265 if (m == PETSC_DECIDE || n == PETSC_DECIDE) { 266 SETERRQ(1,"Must give local row and column count for matrix"); 267 } 268 269 ierr = PetscSplitOwnership(comm,&m,&M);CHKERRQ(ierr); 270 ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); 271 b->M = M; B->M = M; 272 b->N = N; B->N = N; 273 b->m = m; B->m = m; 274 b->n = n; B->n = n; 275 276 ierr = MapCreateMPI(comm,m,M,&B->rmap);CHKERRQ(ierr); 277 ierr = MapCreateMPI(comm,n,N,&B->cmap);CHKERRQ(ierr); 278 279 b->ctx = ctx; 280 *A = B; 281 PetscFunctionReturn(0); 282 } 283 284 #undef __FUNC__ 285 #define __FUNC__ /*<a name=""></a>*/"MatShellSetOperation" 286 /*@C 287 MatShellSetOperation - Allows user to set a matrix operation for 288 a shell matrix. 289 290 Collective on Mat 291 292 Input Parameters: 293 + mat - the shell matrix 294 . op - the name of the operation 295 - f - the function that provides the operation. 296 297 Level: advanced 298 299 Usage: 300 $ extern int usermult(Mat,Vec,Vec); 301 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 302 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void*) usermult); 303 304 Notes: 305 See the file include/petscmat.h for a complete list of matrix 306 operations, which all have the form MATOP_<OPERATION>, where 307 <OPERATION> is the name (in all capital letters) of the 308 user interface routine (e.g., MatMult() -> MATOP_MULT). 309 310 All user-provided functions should have the same calling 311 sequence as the usual matrix interface routines, since they 312 are intended to be accessed via the usual matrix interface 313 routines, e.g., 314 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 315 316 Within each user-defined routine, the user should call 317 MatShellGetContext() to obtain the user-defined context that was 318 set by MatCreateShell(). 319 320 .keywords: matrix, shell, set, operation 321 322 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 323 @*/ 324 int MatShellSetOperation(Mat mat,MatOperation op,void *f) 325 { 326 PetscFunctionBegin; 327 PetscValidHeaderSpecific(mat,MAT_COOKIE); 328 329 if (op == MATOP_DESTROY) { 330 if (mat->type == MATSHELL) { 331 Mat_Shell *shell = (Mat_Shell*)mat->data; 332 shell->destroy = (int (*)(Mat)) f; 333 } else mat->ops->destroy = (int (*)(Mat)) f; 334 } 335 else if (op == MATOP_VIEW) mat->ops->view = (int (*)(Mat,Viewer)) f; 336 else (((void**)mat->ops)[op]) = f; 337 338 PetscFunctionReturn(0); 339 } 340 341 #undef __FUNC__ 342 #define __FUNC__ /*<a name=""></a>*/"MatShellGetOperation" 343 /*@C 344 MatShellGetOperation - Gets a matrix function for a shell matrix. 345 346 Not Collective 347 348 Input Parameters: 349 + mat - the shell matrix 350 - op - the name of the operation 351 352 Output Parameter: 353 . f - the function that provides the operation. 354 355 Level: advanced 356 357 Notes: 358 See the file include/petscmat.h for a complete list of matrix 359 operations, which all have the form MATOP_<OPERATION>, where 360 <OPERATION> is the name (in all capital letters) of the 361 user interface routine (e.g., MatMult() -> MATOP_MULT). 362 363 All user-provided functions have the same calling 364 sequence as the usual matrix interface routines, since they 365 are intended to be accessed via the usual matrix interface 366 routines, e.g., 367 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 368 369 Within each user-defined routine, the user should call 370 MatShellGetContext() to obtain the user-defined context that was 371 set by MatCreateShell(). 372 373 .keywords: matrix, shell, set, operation 374 375 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation() 376 @*/ 377 int MatShellGetOperation(Mat mat,MatOperation op,void **f) 378 { 379 PetscFunctionBegin; 380 PetscValidHeaderSpecific(mat,MAT_COOKIE); 381 382 if (op == MATOP_DESTROY) { 383 if (mat->type == MATSHELL) { 384 Mat_Shell *shell = (Mat_Shell*)mat->data; 385 *f = (void*)shell->destroy; 386 } else { 387 *f = (void*)mat->ops->destroy; 388 } 389 } else if (op == MATOP_VIEW) { 390 *f = (void*)mat->ops->view; 391 } else { 392 *f = (((void**)mat->ops)[op]); 393 } 394 395 PetscFunctionReturn(0); 396 } 397 398