1 /*$Id: shell.c,v 1.79 2000/04/12 04:23:17 bsmith Exp balay $*/ 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 0, 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 B->ops->destroy = MatDestroy_Shell; 260 261 b = PetscNew(Mat_Shell);CHKPTRQ(b); 262 PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 263 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 264 B->data = (void*)b; 265 266 if (m == PETSC_DECIDE || n == PETSC_DECIDE) { 267 SETERRQ(1,1,"Must give local row and column count for matrix"); 268 } 269 270 ierr = PetscSplitOwnership(comm,&m,&M);CHKERRQ(ierr); 271 ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr); 272 b->M = M; B->M = M; 273 b->N = N; B->N = N; 274 b->m = m; B->m = m; 275 b->n = n; B->n = n; 276 277 ierr = MapCreateMPI(comm,m,M,&B->rmap);CHKERRQ(ierr); 278 ierr = MapCreateMPI(comm,n,N,&B->cmap);CHKERRQ(ierr); 279 280 b->ctx = ctx; 281 *A = B; 282 PetscFunctionReturn(0); 283 } 284 285 #undef __FUNC__ 286 #define __FUNC__ /*<a name=""></a>*/"MatShellSetOperation" 287 /*@C 288 MatShellSetOperation - Allows user to set a matrix operation for 289 a shell matrix. 290 291 Collective on Mat 292 293 Input Parameters: 294 + mat - the shell matrix 295 . op - the name of the operation 296 - f - the function that provides the operation. 297 298 Level: advanced 299 300 Usage: 301 $ extern int usermult(Mat,Vec,Vec); 302 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 303 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void*) usermult); 304 305 Notes: 306 See the file include/petscmat.h for a complete list of matrix 307 operations, which all have the form MATOP_<OPERATION>, where 308 <OPERATION> is the name (in all capital letters) of the 309 user interface routine (e.g., MatMult() -> MATOP_MULT). 310 311 All user-provided functions should have the same calling 312 sequence as the usual matrix interface routines, since they 313 are intended to be accessed via the usual matrix interface 314 routines, e.g., 315 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 316 317 Within each user-defined routine, the user should call 318 MatShellGetContext() to obtain the user-defined context that was 319 set by MatCreateShell(). 320 321 .keywords: matrix, shell, set, operation 322 323 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 324 @*/ 325 int MatShellSetOperation(Mat mat,MatOperation op,void *f) 326 { 327 PetscFunctionBegin; 328 PetscValidHeaderSpecific(mat,MAT_COOKIE); 329 330 if (op == MATOP_DESTROY) { 331 if (mat->type == MATSHELL) { 332 Mat_Shell *shell = (Mat_Shell*)mat->data; 333 shell->destroy = (int (*)(Mat)) f; 334 } else mat->ops->destroy = (int (*)(Mat)) f; 335 } 336 else if (op == MATOP_VIEW) mat->ops->view = (int (*)(Mat,Viewer)) f; 337 else (((void**)mat->ops)[op]) = f; 338 339 PetscFunctionReturn(0); 340 } 341 342 #undef __FUNC__ 343 #define __FUNC__ /*<a name=""></a>*/"MatShellGetOperation" 344 /*@C 345 MatShellGetOperation - Gets a matrix function for a shell matrix. 346 347 Not Collective 348 349 Input Parameters: 350 + mat - the shell matrix 351 - op - the name of the operation 352 353 Output Parameter: 354 . f - the function that provides the operation. 355 356 Level: advanced 357 358 Notes: 359 See the file include/petscmat.h for a complete list of matrix 360 operations, which all have the form MATOP_<OPERATION>, where 361 <OPERATION> is the name (in all capital letters) of the 362 user interface routine (e.g., MatMult() -> MATOP_MULT). 363 364 All user-provided functions have the same calling 365 sequence as the usual matrix interface routines, since they 366 are intended to be accessed via the usual matrix interface 367 routines, e.g., 368 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 369 370 Within each user-defined routine, the user should call 371 MatShellGetContext() to obtain the user-defined context that was 372 set by MatCreateShell(). 373 374 .keywords: matrix, shell, set, operation 375 376 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation() 377 @*/ 378 int MatShellGetOperation(Mat mat,MatOperation op,void **f) 379 { 380 PetscFunctionBegin; 381 PetscValidHeaderSpecific(mat,MAT_COOKIE); 382 383 if (op == MATOP_DESTROY) { 384 if (mat->type == MATSHELL) { 385 Mat_Shell *shell = (Mat_Shell*)mat->data; 386 *f = (void*)shell->destroy; 387 } else { 388 *f = (void*)mat->ops->destroy; 389 } 390 } else if (op == MATOP_VIEW) { 391 *f = (void*)mat->ops->view; 392 } else { 393 *f = (((void**)mat->ops)[op]); 394 } 395 396 PetscFunctionReturn(0); 397 } 398 399