1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: shell.c,v 1.68 1999/03/31 18:41:23 bsmith 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 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 if (--mat->refct > 0) PetscFunctionReturn(0); 87 88 if (mat->mapping) { 89 ierr = ISLocalToGlobalMappingDestroy(mat->mapping);CHKERRQ(ierr); 90 } 91 if (mat->bmapping) { 92 ierr = ISLocalToGlobalMappingDestroy(mat->bmapping);CHKERRQ(ierr); 93 } 94 if (mat->rmap) { 95 ierr = MapDestroy(mat->rmap);CHKERRQ(ierr); 96 } 97 if (mat->cmap) { 98 ierr = MapDestroy(mat->cmap);CHKERRQ(ierr); 99 } 100 shell = (Mat_Shell *) mat->data; 101 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 102 PetscFree(shell); 103 PLogObjectDestroy(mat); 104 PetscHeaderDestroy(mat); 105 PetscFunctionReturn(0); 106 } 107 108 int MatGetOwnershipRange_Shell(Mat mat, int *rstart,int *rend) 109 { 110 int ierr; 111 112 PetscFunctionBegin; 113 ierr = MPI_Scan(&mat->m,rend,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr); 114 *rstart = *rend - mat->m; 115 PetscFunctionReturn(0); 116 } 117 118 static struct _MatOps MatOps_Values = {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 0, 148 MatGetSize_Shell, 149 MatGetLocalSize_Shell, 150 MatGetOwnershipRange_Shell, 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 0, 181 0, 182 0, 183 MatGetMaps_Petsc}; 184 185 #undef __FUNC__ 186 #define __FUNC__ "MatCreateShell" 187 /*@C 188 MatCreateShell - Creates a new matrix class for use with a user-defined 189 private data storage format. 190 191 Collective on MPI_Comm 192 193 Input Parameters: 194 + comm - MPI communicator 195 . m - number of local rows (must be given) 196 . n - number of local columns (must be given) 197 . M - number of global rows (may be PETSC_DETERMINE) 198 . N - number of global columns (may be PETSC_DETERMINE) 199 - ctx - pointer to data needed by the shell matrix routines 200 201 Output Parameter: 202 . A - the matrix 203 204 Level: advanced 205 206 Usage: 207 $ extern int mult(Mat,Vec,Vec); 208 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 209 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 210 $ [ Use matrix for operations that have been set ] 211 $ MatDestroy(mat); 212 213 Notes: 214 The shell matrix type is intended to provide a simple class to use 215 with KSP (such as, for use with matrix-free methods). You should not 216 use the shell type if you plan to define a complete matrix class. 217 218 PETSc requires that matrices and vectors being used for certain 219 operations are partitioned accordingly. For example, when 220 creating a shell matrix, A, that supports parallel matrix-vector 221 products using MatMult(A,x,y) the user should set the number 222 of local matrix rows to be the number of local elements of the 223 corresponding result vector, y. Note that this is information is 224 required for use of the matrix interface routines, even though 225 the shell matrix may not actually be physically partitioned. 226 For example, 227 228 $ 229 $ Vec x, y 230 $ extern int mult(Mat,Vec,Vec); 231 $ Mat A 232 $ 233 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 234 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 235 $ VecGetLocalSize(y,&m); 236 $ VecGetLocalSize(x,&n); 237 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 238 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 239 $ MatMult(A,x,y); 240 $ MatDestroy(A); 241 $ VecDestroy(y); VecDestroy(x); 242 $ 243 244 .keywords: matrix, shell, create 245 246 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 247 @*/ 248 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 249 { 250 Mat B; 251 Mat_Shell *b; 252 int ierr; 253 254 PetscFunctionBegin; 255 PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,"Mat",comm,MatDestroy,MatView); 256 PLogObjectCreate(B); 257 B->factor = 0; 258 B->assembled = PETSC_TRUE; 259 ierr = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 260 B->ops->destroy = MatDestroy_Shell; 261 262 b = PetscNew(Mat_Shell);CHKPTRQ(b); 263 PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 264 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 265 B->data = (void *) b; 266 267 if (m == PETSC_DECIDE || n == PETSC_DECIDE) { 268 SETERRQ(1,1,"Must give local row and column count for matrix"); 269 } 270 271 ierr = PetscSplitOwnership(comm,&m,&M);CHKERRQ(ierr); 272 ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); 273 b->M = M; B->M = M; 274 b->N = N; B->N = N; 275 b->m = m; B->m = m; 276 b->n = n; B->n = n; 277 278 ierr = MapCreateMPI(comm,m,M,&B->rmap);CHKERRQ(ierr); 279 ierr = MapCreateMPI(comm,n,N,&B->cmap);CHKERRQ(ierr); 280 281 b->ctx = ctx; 282 *A = B; 283 PetscFunctionReturn(0); 284 } 285 286 #undef __FUNC__ 287 #define __FUNC__ "MatShellSetOperation" 288 /*@C 289 MatShellSetOperation - Allows user to set a matrix operation for 290 a shell matrix. 291 292 Collective on Mat 293 294 Input Parameters: 295 + mat - the shell matrix 296 . op - the name of the operation 297 - f - the function that provides the operation. 298 299 Level: advanced 300 301 Usage: 302 $ extern int usermult(Mat,Vec,Vec); 303 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 304 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void*) usermult); 305 306 Notes: 307 See the file include/mat.h for a complete list of matrix 308 operations, which all have the form MATOP_<OPERATION>, where 309 <OPERATION> is the name (in all capital letters) of the 310 user interface routine (e.g., MatMult() -> MATOP_MULT). 311 312 All user-provided functions should have the same calling 313 sequence as the usual matrix interface routines, since they 314 are intended to be accessed via the usual matrix interface 315 routines, e.g., 316 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 317 318 Within each user-defined routine, the user should call 319 MatShellGetContext() to obtain the user-defined context that was 320 set by MatCreateShell(). 321 322 .keywords: matrix, shell, set, operation 323 324 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 325 @*/ 326 int MatShellSetOperation(Mat mat,MatOperation op, void *f) 327 { 328 PetscFunctionBegin; 329 PetscValidHeaderSpecific(mat,MAT_COOKIE); 330 331 if (op == MATOP_DESTROY) { 332 if (mat->type == MATSHELL) { 333 Mat_Shell *shell = (Mat_Shell *) mat->data; 334 shell->destroy = (int (*)(Mat)) f; 335 } 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