1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: shell.c,v 1.59 1998/07/14 02:34:52 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 Notes: 36 This routine is intended for use within various shell matrix routines, 37 as set with MatShellSetOperation(). 38 39 .keywords: matrix, shell, get, context 40 41 .seealso: MatCreateShell(), MatShellSetOperation() 42 @*/ 43 int MatShellGetContext(Mat mat,void **ctx) 44 { 45 PetscFunctionBegin; 46 PetscValidHeaderSpecific(mat,MAT_COOKIE); 47 if (mat->type != MATSHELL) *ctx = 0; 48 else *ctx = ((Mat_Shell *) (mat->data))->ctx; 49 PetscFunctionReturn(0); 50 } 51 52 #undef __FUNC__ 53 #define __FUNC__ "MatGetSize_Shell" 54 int MatGetSize_Shell(Mat mat,int *M,int *N) 55 { 56 Mat_Shell *shell = (Mat_Shell *) mat->data; 57 58 PetscFunctionBegin; 59 if (M) *M = shell->M; 60 if (N) *N = shell->N; 61 PetscFunctionReturn(0); 62 } 63 64 #undef __FUNC__ 65 #define __FUNC__ "MatGetLocalSize_Shell" 66 int MatGetLocalSize_Shell(Mat mat,int *m,int *n) 67 { 68 Mat_Shell *shell = (Mat_Shell *) mat->data; 69 70 PetscFunctionBegin; 71 if (m) *m = shell->m; 72 if (n) *n = shell->n; 73 PetscFunctionReturn(0); 74 } 75 76 #undef __FUNC__ 77 #define __FUNC__ "MatDestroy_Shell" 78 int MatDestroy_Shell(Mat mat) 79 { 80 int ierr; 81 Mat_Shell *shell; 82 83 PetscFunctionBegin; 84 if (--mat->refct > 0) PetscFunctionReturn(0); 85 86 if (mat->mapping) { 87 ierr = ISLocalToGlobalMappingDestroy(mat->mapping); CHKERRQ(ierr); 88 } 89 if (mat->bmapping) { 90 ierr = ISLocalToGlobalMappingDestroy(mat->bmapping); CHKERRQ(ierr); 91 } 92 if (mat->rmap) { 93 ierr = MapDestroy(mat->rmap);CHKERRQ(ierr); 94 } 95 if (mat->cmap) { 96 ierr = MapDestroy(mat->cmap);CHKERRQ(ierr); 97 } 98 shell = (Mat_Shell *) mat->data; 99 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 100 PetscFree(shell); 101 PLogObjectDestroy(mat); 102 PetscHeaderDestroy(mat); 103 PetscFunctionReturn(0); 104 } 105 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 Usage: 203 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 204 $ MatShellSetOperation(mat,MATOP_MULT,mult); 205 $ [ Use matrix for operations that have been set ] 206 $ MatDestroy(mat); 207 208 Notes: 209 The shell matrix type is intended to provide a simple class to use 210 with KSP (such as, for use with matrix-free methods). You should not 211 use the shell type if you plan to define a complete matrix class. 212 213 PETSc requires that matrices and vectors being used for certain 214 operations are partitioned accordingly. For example, when 215 creating a shell matrix, A, that supports parallel matrix-vector 216 products using MatMult(A,x,y) the user should set the number 217 of local matrix rows to be the number of local elements of the 218 corresponding result vector, y. Note that this is information is 219 required for use of the matrix interface routines, even though 220 the shell matrix may not actually be physically partitioned. 221 For example, 222 223 $ 224 $ Vec x, y 225 $ Mat A 226 $ 227 $ VecCreate(comm,PETSC_DECIDE,M,&y); 228 $ VecCreate(comm,PETSC_DECIDE,N,&x); 229 $ VecGetLocalSize(y,&m); 230 $ VecGetLocalSize(x,&n); 231 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 232 $ MatShellSetOperation(mat,MATOP_MULT,mult); 233 $ MatMult(A,x,y); 234 $ MatDestroy(A); 235 $ VecDestroy(y); VecDestroy(x); 236 $ 237 238 .keywords: matrix, shell, create 239 240 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 241 @*/ 242 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 243 { 244 Mat B; 245 Mat_Shell *b; 246 int ierr; 247 248 PetscFunctionBegin; 249 PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,comm,MatDestroy,MatView); 250 PLogObjectCreate(B); 251 B->factor = 0; 252 B->assembled = PETSC_TRUE; 253 PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps)); 254 B->ops->destroy = MatDestroy_Shell; 255 256 b = PetscNew(Mat_Shell); CHKPTRQ(b); 257 PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 258 PetscMemzero(b,sizeof(Mat_Shell)); 259 B->data = (void *) b; 260 261 if (m == PETSC_DECIDE || n == PETSC_DECIDE) { 262 SETERRQ(1,1,"Must give local row and column count for matrix"); 263 } 264 265 if (M == PETSC_DETERMINE || N == PETSC_DETERMINE) { 266 int work[2], sum[2]; 267 268 work[0] = m; work[1] = n; 269 ierr = MPI_Allreduce( work, sum,2,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr); 270 if (M == PETSC_DECIDE) M = sum[0]; 271 if (N == PETSC_DECIDE) N = sum[1]; 272 } 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 = MapCreate(comm,m,M,B->rmap);CHKERRQ(ierr); 279 ierr = MapCreate(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 Usage: 300 $ extern int usermult(Mat,Vec,Vec); 301 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 302 $ ierr = MatShellSetOperation(A,MATOP_MULT,usermult); 303 304 Notes: 305 See the file petsc/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 } 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__ "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 Notes: 357 See the file petsc/include/mat.h for a complete list of matrix 358 operations, which all have the form MATOP_<OPERATION>, where 359 <OPERATION> is the name (in all capital letters) of the 360 user interface routine (e.g., MatMult() -> MATOP_MULT). 361 362 All user-provided functions have the same calling 363 sequence as the usual matrix interface routines, since they 364 are intended to be accessed via the usual matrix interface 365 routines, e.g., 366 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 367 368 Within each user-defined routine, the user should call 369 MatShellGetContext() to obtain the user-defined context that was 370 set by MatCreateShell(). 371 372 .keywords: matrix, shell, set, operation 373 374 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation() 375 @*/ 376 int MatShellGetOperation(Mat mat,MatOperation op, void **f) 377 { 378 PetscFunctionBegin; 379 PetscValidHeaderSpecific(mat,MAT_COOKIE); 380 381 if (op == MATOP_DESTROY) { 382 if (mat->type == MATSHELL) { 383 Mat_Shell *shell = (Mat_Shell *) mat->data; 384 *f = (void *) shell->destroy; 385 } else { 386 *f = (void *) mat->ops->destroy; 387 } 388 } else if (op == MATOP_VIEW) { 389 *f = (void *) mat->ops->view; 390 } else { 391 *f = (((void**)&mat->ops)[op]); 392 } 393 394 PetscFunctionReturn(0); 395 } 396 397