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