1 2 /* 3 This provides a simple shell for Fortran (and C programmers) to 4 create a very simple matrix class for use with KSP without coding 5 much of anything. 6 */ 7 8 #include <private/matimpl.h> /*I "petscmat.h" I*/ 9 #include <private/vecimpl.h> 10 11 typedef struct { 12 PetscErrorCode (*destroy)(Mat); 13 PetscErrorCode (*mult)(Mat,Vec,Vec); 14 PetscErrorCode (*multtranspose)(Mat,Vec,Vec); 15 PetscErrorCode (*getdiagonal)(Mat,Vec); 16 PetscScalar vscale,vshift; 17 Vec dshift; 18 Vec left,right; 19 Vec dshift_owned,left_owned,right_owned; 20 Vec left_work,right_work; 21 PetscBool usingscaled; 22 void *ctx; 23 } Mat_Shell; 24 /* 25 The most general expression for the matrix is 26 27 S = L (a A + B) R 28 29 where 30 A is the matrix defined by the user's function 31 a is a scalar multiple 32 L is left scaling 33 R is right scaling 34 B is a diagonal shift defined by 35 diag(dshift) if the vector dshift is non-NULL 36 vscale*identity otherwise 37 38 The following identities apply: 39 40 Scale by c: 41 c [L (a A + B) R] = L [(a c) A + c B] R 42 43 Shift by c: 44 [L (a A + B) R] + c = L [a A + (B + c Linv Rinv)] R 45 46 Diagonal scaling is achieved by simply multiplying with existing L and R vectors 47 48 In the data structure: 49 50 vscale=1.0 means no special scaling will be applied 51 dshift=NULL means a constant diagonal shift (fall back to vshift) 52 vshift=0.0 means no constant diagonal shift, note that vshift is only used if dshift is NULL 53 */ 54 55 static PetscErrorCode MatMult_Shell(Mat,Vec,Vec); 56 static PetscErrorCode MatMultTranspose_Shell(Mat,Vec,Vec); 57 static PetscErrorCode MatGetDiagonal_Shell(Mat,Vec); 58 59 #undef __FUNCT__ 60 #define __FUNCT__ "MatShellUseScaledMethods" 61 static PetscErrorCode MatShellUseScaledMethods(Mat Y) 62 { 63 Mat_Shell *shell = (Mat_Shell*)Y->data; 64 65 PetscFunctionBegin; 66 if (shell->usingscaled) PetscFunctionReturn(0); 67 shell->mult = Y->ops->mult; 68 Y->ops->mult = MatMult_Shell; 69 if (Y->ops->multtranspose) { 70 shell->multtranspose = Y->ops->multtranspose; 71 Y->ops->multtranspose = MatMultTranspose_Shell; 72 } 73 if (Y->ops->getdiagonal) { 74 shell->getdiagonal = Y->ops->getdiagonal; 75 Y->ops->getdiagonal = MatGetDiagonal_Shell; 76 } 77 shell->usingscaled = PETSC_TRUE; 78 PetscFunctionReturn(0); 79 } 80 81 #undef __FUNCT__ 82 #define __FUNCT__ "MatShellPreScaleLeft" 83 static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx) 84 { 85 Mat_Shell *shell = (Mat_Shell*)A->data; 86 PetscErrorCode ierr; 87 88 PetscFunctionBegin; 89 if (!shell->left) { 90 *xx = x; 91 } else { 92 if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);} 93 ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr); 94 *xx = shell->left_work; 95 } 96 PetscFunctionReturn(0); 97 } 98 99 #undef __FUNCT__ 100 #define __FUNCT__ "MatShellPreScaleRight" 101 static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx) 102 { 103 Mat_Shell *shell = (Mat_Shell*)A->data; 104 PetscErrorCode ierr; 105 106 PetscFunctionBegin; 107 if (!shell->right) { 108 *xx = x; 109 } else { 110 if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);} 111 ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr); 112 *xx = shell->right_work; 113 } 114 PetscFunctionReturn(0); 115 } 116 117 #undef __FUNCT__ 118 #define __FUNCT__ "MatShellPostScaleLeft" 119 static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x) 120 { 121 Mat_Shell *shell = (Mat_Shell*)A->data; 122 PetscErrorCode ierr; 123 124 PetscFunctionBegin; 125 if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);} 126 PetscFunctionReturn(0); 127 } 128 129 #undef __FUNCT__ 130 #define __FUNCT__ "MatShellPostScaleRight" 131 static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x) 132 { 133 Mat_Shell *shell = (Mat_Shell*)A->data; 134 PetscErrorCode ierr; 135 136 PetscFunctionBegin; 137 if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);} 138 PetscFunctionReturn(0); 139 } 140 141 #undef __FUNCT__ 142 #define __FUNCT__ "MatShellShiftAndScale" 143 static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y) 144 { 145 Mat_Shell *shell = (Mat_Shell*)A->data; 146 PetscErrorCode ierr; 147 148 PetscFunctionBegin; 149 if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 150 PetscInt i,m; 151 const PetscScalar *x,*d; 152 PetscScalar *y; 153 ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr); 154 ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr); 155 ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); 156 ierr = VecGetArray(Y,&y);CHKERRQ(ierr); 157 for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i]; 158 ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr); 159 ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); 160 ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr); 161 } else if (shell->vshift != 0) { 162 ierr = VecAXPBY(Y,shell->vshift,shell->vscale,X);CHKERRQ(ierr); 163 } else if (shell->vscale != 1.0) { 164 ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr); 165 } 166 PetscFunctionReturn(0); 167 } 168 169 #undef __FUNCT__ 170 #define __FUNCT__ "MatShellGetContext" 171 /*@C 172 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 173 174 Not Collective 175 176 Input Parameter: 177 . mat - the matrix, should have been created with MatCreateShell() 178 179 Output Parameter: 180 . ctx - the user provided context 181 182 Level: advanced 183 184 Notes: 185 This routine is intended for use within various shell matrix routines, 186 as set with MatShellSetOperation(). 187 188 .keywords: matrix, shell, get, context 189 190 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 191 @*/ 192 PetscErrorCode MatShellGetContext(Mat mat,void *ctx) 193 { 194 PetscErrorCode ierr; 195 PetscBool flg; 196 197 PetscFunctionBegin; 198 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 199 PetscValidPointer(ctx,2); 200 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 201 if (!flg) *(void**)ctx = 0; 202 else *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx; 203 PetscFunctionReturn(0); 204 } 205 206 #undef __FUNCT__ 207 #define __FUNCT__ "MatDestroy_Shell" 208 PetscErrorCode MatDestroy_Shell(Mat mat) 209 { 210 PetscErrorCode ierr; 211 Mat_Shell *shell = (Mat_Shell*)mat->data; 212 213 PetscFunctionBegin; 214 if (shell->destroy) { 215 ierr = (*shell->destroy)(mat);CHKERRQ(ierr); 216 } 217 ierr = VecDestroy(&shell->left_owned);CHKERRQ(ierr); 218 ierr = VecDestroy(&shell->right_owned);CHKERRQ(ierr); 219 ierr = VecDestroy(&shell->dshift_owned);CHKERRQ(ierr); 220 ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr); 221 ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr); 222 ierr = PetscFree(mat->data);CHKERRQ(ierr); 223 PetscFunctionReturn(0); 224 } 225 226 #undef __FUNCT__ 227 #define __FUNCT__ "MatMult_Shell" 228 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 229 { 230 Mat_Shell *shell = (Mat_Shell*)A->data; 231 PetscErrorCode ierr; 232 Vec xx; 233 234 PetscFunctionBegin; 235 ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr); 236 ierr = (*shell->mult)(A,xx,y);CHKERRQ(ierr); 237 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 238 ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr); 239 PetscFunctionReturn(0); 240 } 241 242 #undef __FUNCT__ 243 #define __FUNCT__ "MatMultTranspose_Shell" 244 PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y) 245 { 246 Mat_Shell *shell = (Mat_Shell*)A->data; 247 PetscErrorCode ierr; 248 Vec xx; 249 250 PetscFunctionBegin; 251 ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr); 252 ierr = (*shell->multtranspose)(A,xx,y);CHKERRQ(ierr); 253 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 254 ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr); 255 PetscFunctionReturn(0); 256 } 257 258 #undef __FUNCT__ 259 #define __FUNCT__ "MatGetDiagonal_Shell" 260 PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v) 261 { 262 Mat_Shell *shell = (Mat_Shell*)A->data; 263 PetscErrorCode ierr; 264 265 PetscFunctionBegin; 266 ierr = (*shell->getdiagonal)(A,v);CHKERRQ(ierr); 267 ierr = VecScale(v,shell->vscale);CHKERRQ(ierr); 268 if (shell->dshift) { 269 ierr = VecPointwiseMult(v,v,shell->dshift);CHKERRQ(ierr); 270 } else { 271 ierr = VecShift(v,shell->vshift);CHKERRQ(ierr); 272 } 273 if (shell->left) {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);} 274 if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);} 275 PetscFunctionReturn(0); 276 } 277 278 #undef __FUNCT__ 279 #define __FUNCT__ "MatShift_Shell" 280 PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a) 281 { 282 Mat_Shell *shell = (Mat_Shell*)Y->data; 283 PetscErrorCode ierr; 284 285 PetscFunctionBegin; 286 if (shell->left || shell->right || shell->dshift) { 287 if (!shell->dshift) { 288 if (!shell->dshift_owned) {ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift_owned);CHKERRQ(ierr);} 289 shell->dshift = shell->dshift_owned; 290 ierr = VecSet(shell->dshift,shell->vshift+a);CHKERRQ(ierr); 291 } else {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);} 292 if (shell->left) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 293 if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 294 } else shell->vshift += a; 295 ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr); 296 PetscFunctionReturn(0); 297 } 298 299 #undef __FUNCT__ 300 #define __FUNCT__ "MatScale_Shell" 301 PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a) 302 { 303 Mat_Shell *shell = (Mat_Shell*)Y->data; 304 PetscErrorCode ierr; 305 306 PetscFunctionBegin; 307 shell->vscale *= a; 308 if (shell->dshift) {ierr = VecScale(shell->dshift,a);CHKERRQ(ierr);} 309 else shell->vshift *= a; 310 ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr); 311 PetscFunctionReturn(0); 312 } 313 314 #undef __FUNCT__ 315 #define __FUNCT__ "MatDiagonalScale_Shell" 316 static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right) 317 { 318 Mat_Shell *shell = (Mat_Shell*)Y->data; 319 PetscErrorCode ierr; 320 321 PetscFunctionBegin; 322 if (left) { 323 if (!shell->left_owned) {ierr = VecDuplicate(left,&shell->left_owned);CHKERRQ(ierr);} 324 if (shell->left) {ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr);} 325 else { 326 shell->left = shell->left_owned; 327 ierr = VecCopy(left,shell->left);CHKERRQ(ierr); 328 } 329 } 330 if (right) { 331 if (!shell->right_owned) {ierr = VecDuplicate(right,&shell->right_owned);CHKERRQ(ierr);} 332 if (shell->right) {ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr);} 333 else { 334 shell->right = shell->right_owned; 335 ierr = VecCopy(right,shell->right);CHKERRQ(ierr); 336 } 337 } 338 ierr = MatShellUseScaledMethods(Y);CHKERRQ(ierr); 339 PetscFunctionReturn(0); 340 } 341 342 #undef __FUNCT__ 343 #define __FUNCT__ "MatAssemblyEnd_Shell" 344 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 345 { 346 Mat_Shell *shell = (Mat_Shell*)Y->data; 347 348 PetscFunctionBegin; 349 if (t == MAT_FINAL_ASSEMBLY) { 350 shell->vshift = 0.0; 351 shell->vscale = 1.0; 352 shell->dshift = PETSC_NULL; 353 shell->left = PETSC_NULL; 354 shell->right = PETSC_NULL; 355 if (shell->mult) { 356 Y->ops->mult = shell->mult; 357 shell->mult = PETSC_NULL; 358 } 359 if (shell->multtranspose) { 360 Y->ops->multtranspose = shell->multtranspose; 361 shell->multtranspose = PETSC_NULL; 362 } 363 if (shell->getdiagonal) { 364 Y->ops->getdiagonal = shell->getdiagonal; 365 shell->getdiagonal = PETSC_NULL; 366 } 367 shell->usingscaled = PETSC_FALSE; 368 } 369 PetscFunctionReturn(0); 370 } 371 372 extern PetscErrorCode MatConvert_Shell(Mat, const MatType,MatReuse,Mat*); 373 374 #undef __FUNCT__ 375 #define __FUNCT__ "MatSetBlockSize_Shell" 376 PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs) 377 { 378 PetscErrorCode ierr; 379 380 PetscFunctionBegin; 381 ierr = PetscLayoutSetBlockSize(A->rmap,bs);CHKERRQ(ierr); 382 ierr = PetscLayoutSetBlockSize(A->cmap,bs);CHKERRQ(ierr); 383 PetscFunctionReturn(0); 384 } 385 386 static struct _MatOps MatOps_Values = {0, 387 0, 388 0, 389 0, 390 /* 4*/ 0, 391 0, 392 0, 393 0, 394 0, 395 0, 396 /*10*/ 0, 397 0, 398 0, 399 0, 400 0, 401 /*15*/ 0, 402 0, 403 0, 404 MatDiagonalScale_Shell, 405 0, 406 /*20*/ 0, 407 MatAssemblyEnd_Shell, 408 0, 409 0, 410 /*24*/ 0, 411 0, 412 0, 413 0, 414 0, 415 /*29*/ 0, 416 0, 417 0, 418 0, 419 0, 420 /*34*/ 0, 421 0, 422 0, 423 0, 424 0, 425 /*39*/ 0, 426 0, 427 0, 428 0, 429 0, 430 /*44*/ 0, 431 MatScale_Shell, 432 MatShift_Shell, 433 0, 434 0, 435 /*49*/ MatSetBlockSize_Shell, 436 0, 437 0, 438 0, 439 0, 440 /*54*/ 0, 441 0, 442 0, 443 0, 444 0, 445 /*59*/ 0, 446 MatDestroy_Shell, 447 0, 448 0, 449 0, 450 /*64*/ 0, 451 0, 452 0, 453 0, 454 0, 455 /*69*/ 0, 456 0, 457 MatConvert_Shell, 458 0, 459 0, 460 /*74*/ 0, 461 0, 462 0, 463 0, 464 0, 465 /*79*/ 0, 466 0, 467 0, 468 0, 469 0, 470 /*84*/ 0, 471 0, 472 0, 473 0, 474 0, 475 /*89*/ 0, 476 0, 477 0, 478 0, 479 0, 480 /*94*/ 0, 481 0, 482 0, 483 0}; 484 485 /*MC 486 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 487 488 Level: advanced 489 490 .seealso: MatCreateShell 491 M*/ 492 493 EXTERN_C_BEGIN 494 #undef __FUNCT__ 495 #define __FUNCT__ "MatCreate_Shell" 496 PetscErrorCode MatCreate_Shell(Mat A) 497 { 498 Mat_Shell *b; 499 PetscErrorCode ierr; 500 501 PetscFunctionBegin; 502 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 503 504 ierr = PetscNewLog(A,Mat_Shell,&b);CHKERRQ(ierr); 505 A->data = (void*)b; 506 507 ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr); 508 ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr); 509 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 510 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 511 512 b->ctx = 0; 513 b->vshift = 0.0; 514 b->vscale = 1.0; 515 b->mult = 0; 516 b->multtranspose = 0; 517 b->getdiagonal = 0; 518 A->assembled = PETSC_TRUE; 519 A->preallocated = PETSC_FALSE; 520 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr); 521 PetscFunctionReturn(0); 522 } 523 EXTERN_C_END 524 525 #undef __FUNCT__ 526 #define __FUNCT__ "MatCreateShell" 527 /*@C 528 MatCreateShell - Creates a new matrix class for use with a user-defined 529 private data storage format. 530 531 Collective on MPI_Comm 532 533 Input Parameters: 534 + comm - MPI communicator 535 . m - number of local rows (must be given) 536 . n - number of local columns (must be given) 537 . M - number of global rows (may be PETSC_DETERMINE) 538 . N - number of global columns (may be PETSC_DETERMINE) 539 - ctx - pointer to data needed by the shell matrix routines 540 541 Output Parameter: 542 . A - the matrix 543 544 Level: advanced 545 546 Usage: 547 $ extern int mult(Mat,Vec,Vec); 548 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 549 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 550 $ [ Use matrix for operations that have been set ] 551 $ MatDestroy(mat); 552 553 Notes: 554 The shell matrix type is intended to provide a simple class to use 555 with KSP (such as, for use with matrix-free methods). You should not 556 use the shell type if you plan to define a complete matrix class. 557 558 Fortran Notes: The context can only be an integer or a PetscObject 559 unfortunately it cannot be a Fortran array or derived type. 560 561 PETSc requires that matrices and vectors being used for certain 562 operations are partitioned accordingly. For example, when 563 creating a shell matrix, A, that supports parallel matrix-vector 564 products using MatMult(A,x,y) the user should set the number 565 of local matrix rows to be the number of local elements of the 566 corresponding result vector, y. Note that this is information is 567 required for use of the matrix interface routines, even though 568 the shell matrix may not actually be physically partitioned. 569 For example, 570 571 $ 572 $ Vec x, y 573 $ extern int mult(Mat,Vec,Vec); 574 $ Mat A 575 $ 576 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 577 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 578 $ VecGetLocalSize(y,&m); 579 $ VecGetLocalSize(x,&n); 580 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 581 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 582 $ MatMult(A,x,y); 583 $ MatDestroy(A); 584 $ VecDestroy(y); VecDestroy(x); 585 $ 586 587 .keywords: matrix, shell, create 588 589 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() 590 @*/ 591 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 592 { 593 PetscErrorCode ierr; 594 595 PetscFunctionBegin; 596 ierr = MatCreate(comm,A);CHKERRQ(ierr); 597 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 598 599 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 600 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 601 PetscFunctionReturn(0); 602 } 603 604 #undef __FUNCT__ 605 #define __FUNCT__ "MatShellSetContext" 606 /*@ 607 MatShellSetContext - sets the context for a shell matrix 608 609 Logically Collective on Mat 610 611 Input Parameters: 612 + mat - the shell matrix 613 - ctx - the context 614 615 Level: advanced 616 617 Fortran Notes: The context can only be an integer or a PetscObject 618 unfortunately it cannot be a Fortran array or derived type. 619 620 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 621 @*/ 622 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 623 { 624 Mat_Shell *shell = (Mat_Shell*)mat->data; 625 PetscErrorCode ierr; 626 PetscBool flg; 627 628 PetscFunctionBegin; 629 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 630 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 631 if (flg) { 632 shell->ctx = ctx; 633 } 634 PetscFunctionReturn(0); 635 } 636 637 #undef __FUNCT__ 638 #define __FUNCT__ "MatShellSetOperation" 639 /*@C 640 MatShellSetOperation - Allows user to set a matrix operation for 641 a shell matrix. 642 643 Logically Collective on Mat 644 645 Input Parameters: 646 + mat - the shell matrix 647 . op - the name of the operation 648 - f - the function that provides the operation. 649 650 Level: advanced 651 652 Usage: 653 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 654 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 655 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 656 657 Notes: 658 See the file include/petscmat.h for a complete list of matrix 659 operations, which all have the form MATOP_<OPERATION>, where 660 <OPERATION> is the name (in all capital letters) of the 661 user interface routine (e.g., MatMult() -> MATOP_MULT). 662 663 All user-provided functions should have the same calling 664 sequence as the usual matrix interface routines, since they 665 are intended to be accessed via the usual matrix interface 666 routines, e.g., 667 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 668 669 In particular each function MUST return an error code of 0 on success and 670 nonzero on failure. 671 672 Within each user-defined routine, the user should call 673 MatShellGetContext() to obtain the user-defined context that was 674 set by MatCreateShell(). 675 676 Fortran Notes: For MatGetVecs() the user code should check if the input left or right matrix is -1 and in that case not 677 generate a matrix. See src/mat/examples/tests/ex120f.F 678 679 .keywords: matrix, shell, set, operation 680 681 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 682 @*/ 683 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 684 { 685 PetscErrorCode ierr; 686 PetscBool flg; 687 688 PetscFunctionBegin; 689 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 690 if (op == MATOP_DESTROY) { 691 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 692 if (flg) { 693 Mat_Shell *shell = (Mat_Shell*)mat->data; 694 shell->destroy = (PetscErrorCode (*)(Mat)) f; 695 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 696 } 697 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 698 else (((void(**)(void))mat->ops)[op]) = f; 699 700 PetscFunctionReturn(0); 701 } 702 703 #undef __FUNCT__ 704 #define __FUNCT__ "MatShellGetOperation" 705 /*@C 706 MatShellGetOperation - Gets a matrix function for a shell matrix. 707 708 Not Collective 709 710 Input Parameters: 711 + mat - the shell matrix 712 - op - the name of the operation 713 714 Output Parameter: 715 . f - the function that provides the operation. 716 717 Level: advanced 718 719 Notes: 720 See the file include/petscmat.h for a complete list of matrix 721 operations, which all have the form MATOP_<OPERATION>, where 722 <OPERATION> is the name (in all capital letters) of the 723 user interface routine (e.g., MatMult() -> MATOP_MULT). 724 725 All user-provided functions have the same calling 726 sequence as the usual matrix interface routines, since they 727 are intended to be accessed via the usual matrix interface 728 routines, e.g., 729 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 730 731 Within each user-defined routine, the user should call 732 MatShellGetContext() to obtain the user-defined context that was 733 set by MatCreateShell(). 734 735 .keywords: matrix, shell, set, operation 736 737 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 738 @*/ 739 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 740 { 741 PetscErrorCode ierr; 742 PetscBool flg; 743 744 PetscFunctionBegin; 745 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 746 if (op == MATOP_DESTROY) { 747 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 748 if (flg) { 749 Mat_Shell *shell = (Mat_Shell*)mat->data; 750 *f = (void(*)(void))shell->destroy; 751 } else { 752 *f = (void(*)(void))mat->ops->destroy; 753 } 754 } else if (op == MATOP_VIEW) { 755 *f = (void(*)(void))mat->ops->view; 756 } else { 757 *f = (((void(**)(void))mat->ops)[op]); 758 } 759 760 PetscFunctionReturn(0); 761 } 762 763