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