1 /*$Id: shell.c,v 1.88 2001/09/07 20:09:41 bsmith Exp $*/ 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 (*destroy)(Mat); 14 int (*mult)(Mat,Vec,Vec); 15 PetscTruth scale,shift; 16 PetscScalar vscale,vshift; 17 void *ctx; 18 } Mat_Shell; 19 20 #undef __FUNCT__ 21 #define __FUNCT__ "MatShellGetContext" 22 /*@ 23 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 24 25 Not Collective 26 27 Input Parameter: 28 . mat - the matrix, should have been created with MatCreateShell() 29 30 Output Parameter: 31 . ctx - the user provided context 32 33 Level: advanced 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 int ierr; 46 PetscTruth flg; 47 48 PetscFunctionBegin; 49 PetscValidHeaderSpecific(mat,MAT_COOKIE); 50 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 51 if (!flg) *ctx = 0; 52 else *ctx = ((Mat_Shell*)(mat->data))->ctx; 53 PetscFunctionReturn(0); 54 } 55 56 #undef __FUNCT__ 57 #define __FUNCT__ "MatDestroy_Shell" 58 int MatDestroy_Shell(Mat mat) 59 { 60 int ierr; 61 Mat_Shell *shell; 62 63 PetscFunctionBegin; 64 shell = (Mat_Shell*)mat->data; 65 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 66 ierr = PetscFree(shell);CHKERRQ(ierr); 67 PetscFunctionReturn(0); 68 } 69 70 #undef __FUNCT__ 71 #define __FUNCT__ "MatGetOwnershipRange_Shell" 72 int MatGetOwnershipRange_Shell(Mat mat,int *rstart,int *rend) 73 { 74 int ierr,tmp; 75 76 PetscFunctionBegin; 77 ierr = MPI_Scan(&mat->m,&tmp,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr); 78 if (rstart) *rstart = tmp - mat->m; 79 if (rend) *rend = tmp; 80 PetscFunctionReturn(0); 81 } 82 83 #undef __FUNCT__ 84 #define __FUNCT__ "MatMult_Shell" 85 int MatMult_Shell(Mat A,Vec x,Vec y) 86 { 87 Mat_Shell *shell = (Mat_Shell*)A->data; 88 int ierr; 89 90 PetscFunctionBegin; 91 ierr = (*shell->mult)(A,x,y);CHKERRQ(ierr); 92 if (shell->shift && shell->scale) { 93 ierr = VecAXPBY(&shell->vshift,&shell->vscale,x,y);CHKERRQ(ierr); 94 } else if (shell->scale) { 95 ierr = VecScale(&shell->vscale,y);CHKERRQ(ierr); 96 } else { 97 ierr = VecAXPY(&shell->vshift,x,y);CHKERRQ(ierr); 98 } 99 PetscFunctionReturn(0); 100 } 101 102 #undef __FUNCT__ 103 #define __FUNCT__ "MatShift_Shell" 104 int MatShift_Shell(PetscScalar *a,Mat Y) 105 { 106 Mat_Shell *shell = (Mat_Shell*)Y->data; 107 PetscFunctionBegin; 108 if (shell->scale || shell->shift) { 109 shell->vshift += *a; 110 } else { 111 shell->mult = Y->ops->mult; 112 Y->ops->mult = MatMult_Shell; 113 shell->vshift = *a; 114 } 115 shell->shift = PETSC_TRUE; 116 PetscFunctionReturn(0); 117 } 118 119 #undef __FUNCT__ 120 #define __FUNCT__ "MatScale_Shell" 121 int MatScale_Shell(PetscScalar *a,Mat Y) 122 { 123 Mat_Shell *shell = (Mat_Shell*)Y->data; 124 PetscFunctionBegin; 125 if (shell->scale || shell->shift) { 126 shell->vscale *= *a; 127 } else { 128 shell->mult = Y->ops->mult; 129 Y->ops->mult = MatMult_Shell; 130 shell->vscale = *a; 131 } 132 shell->scale = PETSC_TRUE; 133 PetscFunctionReturn(0); 134 } 135 136 #undef __FUNCT__ 137 #define __FUNCT__ "MatAssemblyEnd_Shell" 138 int MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 139 { 140 Mat_Shell *shell = (Mat_Shell*)Y->data; 141 142 PetscFunctionBegin; 143 if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) { 144 shell->scale = PETSC_FALSE; 145 shell->shift = PETSC_FALSE; 146 shell->vshift = 0.0; 147 shell->vscale = 1.0; 148 Y->ops->mult = shell->mult; 149 } 150 PetscFunctionReturn(0); 151 } 152 153 extern int MatConvert_Shell(Mat,MatType,Mat*); 154 155 static struct _MatOps MatOps_Values = {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 MatAssemblyEnd_Shell, 177 0, 178 0, 179 0, 180 0, 181 0, 182 0, 183 0, 184 0, 185 0, 186 MatGetOwnershipRange_Shell, 187 0, 188 0, 189 0, 190 0, 191 0, 192 0, 193 0, 194 0, 195 0, 196 0, 197 0, 198 0, 199 0, 200 0, 201 0, 202 0, 203 MatScale_Shell, 204 MatShift_Shell, 205 0, 206 0, 207 0, 208 0, 209 0, 210 0, 211 0, 212 0, 213 0, 214 0, 215 0, 216 0, 217 0, 218 MatDestroy_Shell, 219 0, 220 MatGetPetscMaps_Petsc, 221 0, 222 0, 223 0, 224 0, 225 0, 226 0, 227 0, 228 MatConvert_Shell}; 229 230 EXTERN_C_BEGIN 231 #undef __FUNCT__ 232 #define __FUNCT__ "MatCreate_Shell" 233 int MatCreate_Shell(Mat A) 234 { 235 Mat_Shell *b; 236 int ierr; 237 238 PetscFunctionBegin; 239 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 240 241 ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr); 242 PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 243 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 244 A->data = (void*)b; 245 246 if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) { 247 SETERRQ(1,"Must give local row and column count for matrix"); 248 } 249 250 ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr); 251 ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr); 252 253 ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr); 254 ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr); 255 256 b->ctx = 0; 257 b->scale = PETSC_FALSE; 258 b->shift = PETSC_FALSE; 259 b->vshift = 0.0; 260 b->vscale = 1.0; 261 b->mult = 0; 262 A->assembled = PETSC_TRUE; 263 A->preallocated = PETSC_TRUE; 264 PetscFunctionReturn(0); 265 } 266 EXTERN_C_END 267 268 #undef __FUNCT__ 269 #define __FUNCT__ "MatCreateShell" 270 /*@C 271 MatCreateShell - Creates a new matrix class for use with a user-defined 272 private data storage format. 273 274 Collective on MPI_Comm 275 276 Input Parameters: 277 + comm - MPI communicator 278 . m - number of local rows (must be given) 279 . n - number of local columns (must be given) 280 . M - number of global rows (may be PETSC_DETERMINE) 281 . N - number of global columns (may be PETSC_DETERMINE) 282 - ctx - pointer to data needed by the shell matrix routines 283 284 Output Parameter: 285 . A - the matrix 286 287 Level: advanced 288 289 Usage: 290 $ extern int mult(Mat,Vec,Vec); 291 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 292 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)())mult); 293 $ [ Use matrix for operations that have been set ] 294 $ MatDestroy(mat); 295 296 Notes: 297 The shell matrix type is intended to provide a simple class to use 298 with KSP (such as, for use with matrix-free methods). You should not 299 use the shell type if you plan to define a complete matrix class. 300 301 PETSc requires that matrices and vectors being used for certain 302 operations are partitioned accordingly. For example, when 303 creating a shell matrix, A, that supports parallel matrix-vector 304 products using MatMult(A,x,y) the user should set the number 305 of local matrix rows to be the number of local elements of the 306 corresponding result vector, y. Note that this is information is 307 required for use of the matrix interface routines, even though 308 the shell matrix may not actually be physically partitioned. 309 For example, 310 311 $ 312 $ Vec x, y 313 $ extern int mult(Mat,Vec,Vec); 314 $ Mat A 315 $ 316 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 317 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 318 $ VecGetLocalSize(y,&m); 319 $ VecGetLocalSize(x,&n); 320 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 321 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)())mult); 322 $ MatMult(A,x,y); 323 $ MatDestroy(A); 324 $ VecDestroy(y); VecDestroy(x); 325 $ 326 327 .keywords: matrix, shell, create 328 329 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext() 330 @*/ 331 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A) 332 { 333 int ierr; 334 335 PetscFunctionBegin; 336 ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr); 337 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 338 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 339 PetscFunctionReturn(0); 340 } 341 342 #undef __FUNCT__ 343 #define __FUNCT__ "MatShellSetContext" 344 /*@C 345 MatShellSetContext - sets the context for a shell matrix 346 347 Collective on Mat 348 349 Input Parameters: 350 + mat - the shell matrix 351 - ctx - the context 352 353 Level: advanced 354 355 356 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 357 @*/ 358 int MatShellSetContext(Mat mat,void *ctx) 359 { 360 Mat_Shell *shell = (Mat_Shell*)mat->data; 361 int ierr; 362 PetscTruth flg; 363 364 PetscFunctionBegin; 365 PetscValidHeaderSpecific(mat,MAT_COOKIE); 366 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 367 if (flg) { 368 shell->ctx = ctx; 369 } 370 PetscFunctionReturn(0); 371 } 372 373 #undef __FUNCT__ 374 #define __FUNCT__ "MatShellSetOperation" 375 /*@C 376 MatShellSetOperation - Allows user to set a matrix operation for 377 a shell matrix. 378 379 Collective on Mat 380 381 Input Parameters: 382 + mat - the shell matrix 383 . op - the name of the operation 384 - f - the function that provides the operation. 385 386 Level: advanced 387 388 Usage: 389 $ extern int usermult(Mat,Vec,Vec); 390 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 391 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)())usermult); 392 393 Notes: 394 See the file include/petscmat.h for a complete list of matrix 395 operations, which all have the form MATOP_<OPERATION>, where 396 <OPERATION> is the name (in all capital letters) of the 397 user interface routine (e.g., MatMult() -> MATOP_MULT). 398 399 All user-provided functions should have the same calling 400 sequence as the usual matrix interface routines, since they 401 are intended to be accessed via the usual matrix interface 402 routines, e.g., 403 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 404 405 Within each user-defined routine, the user should call 406 MatShellGetContext() to obtain the user-defined context that was 407 set by MatCreateShell(). 408 409 .keywords: matrix, shell, set, operation 410 411 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 412 @*/ 413 int MatShellSetOperation(Mat mat,MatOperation op,void (*f)()) 414 { 415 int ierr; 416 PetscTruth flg; 417 418 PetscFunctionBegin; 419 PetscValidHeaderSpecific(mat,MAT_COOKIE); 420 if (op == MATOP_DESTROY) { 421 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 422 if (flg) { 423 Mat_Shell *shell = (Mat_Shell*)mat->data; 424 shell->destroy = (int (*)(Mat)) f; 425 } else mat->ops->destroy = (int (*)(Mat)) f; 426 } 427 else if (op == MATOP_VIEW) mat->ops->view = (int (*)(Mat,PetscViewer)) f; 428 else (((void(**)())mat->ops)[op]) = f; 429 430 PetscFunctionReturn(0); 431 } 432 433 #undef __FUNCT__ 434 #define __FUNCT__ "MatShellGetOperation" 435 /*@C 436 MatShellGetOperation - Gets a matrix function for a shell matrix. 437 438 Not Collective 439 440 Input Parameters: 441 + mat - the shell matrix 442 - op - the name of the operation 443 444 Output Parameter: 445 . f - the function that provides the operation. 446 447 Level: advanced 448 449 Notes: 450 See the file include/petscmat.h for a complete list of matrix 451 operations, which all have the form MATOP_<OPERATION>, where 452 <OPERATION> is the name (in all capital letters) of the 453 user interface routine (e.g., MatMult() -> MATOP_MULT). 454 455 All user-provided functions have the same calling 456 sequence as the usual matrix interface routines, since they 457 are intended to be accessed via the usual matrix interface 458 routines, e.g., 459 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 460 461 Within each user-defined routine, the user should call 462 MatShellGetContext() to obtain the user-defined context that was 463 set by MatCreateShell(). 464 465 .keywords: matrix, shell, set, operation 466 467 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation() 468 @*/ 469 int MatShellGetOperation(Mat mat,MatOperation op,void(**f)()) 470 { 471 int ierr; 472 PetscTruth flg; 473 474 PetscFunctionBegin; 475 PetscValidHeaderSpecific(mat,MAT_COOKIE); 476 if (op == MATOP_DESTROY) { 477 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 478 if (flg) { 479 Mat_Shell *shell = (Mat_Shell*)mat->data; 480 *f = (void(*)())shell->destroy; 481 } else { 482 *f = (void(*)())mat->ops->destroy; 483 } 484 } else if (op == MATOP_VIEW) { 485 *f = (void(*)())mat->ops->view; 486 } else { 487 *f = (((void(**)())mat->ops)[op]); 488 } 489 490 PetscFunctionReturn(0); 491 } 492 493