1 /*$Id: shell.c,v 1.75 1999/10/24 14:02:18 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 "mat.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__ "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__ "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__ "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__ "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__ "MatGetOwnershipRange_Shell" 106 int MatGetOwnershipRange_Shell(Mat mat,int *rstart,int *rend) 107 { 108 int ierr; 109 110 PetscFunctionBegin; 111 ierr = MPI_Scan(&mat->m,rend,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr); 112 *rstart = *rend - mat->m; 113 PetscFunctionReturn(0); 114 } 115 116 static struct _MatOps MatOps_Values = {0, 117 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 MatGetSize_Shell, 147 MatGetLocalSize_Shell, 148 MatGetOwnershipRange_Shell, 149 0, 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 0, 181 MatGetMaps_Petsc}; 182 183 #undef __FUNC__ 184 #define __FUNC__ "MatCreateShell" 185 /*@C 186 MatCreateShell - Creates a new matrix class for use with a user-defined 187 private data storage format. 188 189 Collective on MPI_Comm 190 191 Input Parameters: 192 + comm - MPI communicator 193 . m - number of local rows (must be given) 194 . n - number of local columns (must be given) 195 . M - number of global rows (may be PETSC_DETERMINE) 196 . N - number of global columns (may be PETSC_DETERMINE) 197 - ctx - pointer to data needed by the shell matrix routines 198 199 Output Parameter: 200 . A - the matrix 201 202 Level: advanced 203 204 Usage: 205 $ extern int mult(Mat,Vec,Vec); 206 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 207 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 208 $ [ Use matrix for operations that have been set ] 209 $ MatDestroy(mat); 210 211 Notes: 212 The shell matrix type is intended to provide a simple class to use 213 with KSP (such as, for use with matrix-free methods). You should not 214 use the shell type if you plan to define a complete matrix class. 215 216 PETSc requires that matrices and vectors being used for certain 217 operations are partitioned accordingly. For example, when 218 creating a shell matrix, A, that supports parallel matrix-vector 219 products using MatMult(A,x,y) the user should set the number 220 of local matrix rows to be the number of local elements of the 221 corresponding result vector, y. Note that this is information is 222 required for use of the matrix interface routines, even though 223 the shell matrix may not actually be physically partitioned. 224 For example, 225 226 $ 227 $ Vec x, y 228 $ extern int mult(Mat,Vec,Vec); 229 $ Mat A 230 $ 231 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 232 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 233 $ VecGetLocalSize(y,&m); 234 $ VecGetLocalSize(x,&n); 235 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 236 $ MatShellSetOperation(mat,MATOP_MULT,(void *)mult); 237 $ MatMult(A,x,y); 238 $ MatDestroy(A); 239 $ VecDestroy(y); VecDestroy(x); 240 $ 241 242 .keywords: matrix, shell, create 243 244 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 245 @*/ 246 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 247 { 248 Mat B; 249 Mat_Shell *b; 250 int ierr; 251 252 PetscFunctionBegin; 253 PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,"Mat",comm,MatDestroy,MatView); 254 PLogObjectCreate(B); 255 B->factor = 0; 256 B->assembled = PETSC_TRUE; 257 ierr = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 258 B->ops->destroy = MatDestroy_Shell; 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,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__ "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/mat.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__ "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/mat.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