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 shell->usingscaled = PETSC_FALSE; 354 Y->ops->mult = shell->mult; 355 Y->ops->multtranspose = shell->multtranspose; 356 Y->ops->getdiagonal = shell->getdiagonal; 357 } 358 PetscFunctionReturn(0); 359 } 360 361 extern PetscErrorCode MatConvert_Shell(Mat, const MatType,MatReuse,Mat*); 362 363 #undef __FUNCT__ 364 #define __FUNCT__ "MatSetBlockSize_Shell" 365 PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs) 366 { 367 PetscErrorCode ierr; 368 369 PetscFunctionBegin; 370 ierr = PetscLayoutSetBlockSize(A->rmap,bs);CHKERRQ(ierr); 371 ierr = PetscLayoutSetBlockSize(A->cmap,bs);CHKERRQ(ierr); 372 PetscFunctionReturn(0); 373 } 374 375 static struct _MatOps MatOps_Values = {0, 376 0, 377 0, 378 0, 379 /* 4*/ 0, 380 0, 381 0, 382 0, 383 0, 384 0, 385 /*10*/ 0, 386 0, 387 0, 388 0, 389 0, 390 /*15*/ 0, 391 0, 392 0, 393 MatDiagonalScale_Shell, 394 0, 395 /*20*/ 0, 396 MatAssemblyEnd_Shell, 397 0, 398 0, 399 /*24*/ 0, 400 0, 401 0, 402 0, 403 0, 404 /*29*/ 0, 405 0, 406 0, 407 0, 408 0, 409 /*34*/ 0, 410 0, 411 0, 412 0, 413 0, 414 /*39*/ 0, 415 0, 416 0, 417 0, 418 0, 419 /*44*/ 0, 420 MatScale_Shell, 421 MatShift_Shell, 422 0, 423 0, 424 /*49*/ MatSetBlockSize_Shell, 425 0, 426 0, 427 0, 428 0, 429 /*54*/ 0, 430 0, 431 0, 432 0, 433 0, 434 /*59*/ 0, 435 MatDestroy_Shell, 436 0, 437 0, 438 0, 439 /*64*/ 0, 440 0, 441 0, 442 0, 443 0, 444 /*69*/ 0, 445 0, 446 MatConvert_Shell, 447 0, 448 0, 449 /*74*/ 0, 450 0, 451 0, 452 0, 453 0, 454 /*79*/ 0, 455 0, 456 0, 457 0, 458 0, 459 /*84*/ 0, 460 0, 461 0, 462 0, 463 0, 464 /*89*/ 0, 465 0, 466 0, 467 0, 468 0, 469 /*94*/ 0, 470 0, 471 0, 472 0}; 473 474 /*MC 475 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 476 477 Level: advanced 478 479 .seealso: MatCreateShell 480 M*/ 481 482 EXTERN_C_BEGIN 483 #undef __FUNCT__ 484 #define __FUNCT__ "MatCreate_Shell" 485 PetscErrorCode MatCreate_Shell(Mat A) 486 { 487 Mat_Shell *b; 488 PetscErrorCode ierr; 489 490 PetscFunctionBegin; 491 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 492 493 ierr = PetscNewLog(A,Mat_Shell,&b);CHKERRQ(ierr); 494 A->data = (void*)b; 495 496 ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr); 497 ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr); 498 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 499 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 500 501 b->ctx = 0; 502 b->vshift = 0.0; 503 b->vscale = 1.0; 504 b->mult = 0; 505 b->multtranspose = 0; 506 b->getdiagonal = 0; 507 A->assembled = PETSC_TRUE; 508 A->preallocated = PETSC_FALSE; 509 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr); 510 PetscFunctionReturn(0); 511 } 512 EXTERN_C_END 513 514 #undef __FUNCT__ 515 #define __FUNCT__ "MatCreateShell" 516 /*@C 517 MatCreateShell - Creates a new matrix class for use with a user-defined 518 private data storage format. 519 520 Collective on MPI_Comm 521 522 Input Parameters: 523 + comm - MPI communicator 524 . m - number of local rows (must be given) 525 . n - number of local columns (must be given) 526 . M - number of global rows (may be PETSC_DETERMINE) 527 . N - number of global columns (may be PETSC_DETERMINE) 528 - ctx - pointer to data needed by the shell matrix routines 529 530 Output Parameter: 531 . A - the matrix 532 533 Level: advanced 534 535 Usage: 536 $ extern int mult(Mat,Vec,Vec); 537 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 538 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 539 $ [ Use matrix for operations that have been set ] 540 $ MatDestroy(mat); 541 542 Notes: 543 The shell matrix type is intended to provide a simple class to use 544 with KSP (such as, for use with matrix-free methods). You should not 545 use the shell type if you plan to define a complete matrix class. 546 547 Fortran Notes: The context can only be an integer or a PetscObject 548 unfortunately it cannot be a Fortran array or derived type. 549 550 PETSc requires that matrices and vectors being used for certain 551 operations are partitioned accordingly. For example, when 552 creating a shell matrix, A, that supports parallel matrix-vector 553 products using MatMult(A,x,y) the user should set the number 554 of local matrix rows to be the number of local elements of the 555 corresponding result vector, y. Note that this is information is 556 required for use of the matrix interface routines, even though 557 the shell matrix may not actually be physically partitioned. 558 For example, 559 560 $ 561 $ Vec x, y 562 $ extern int mult(Mat,Vec,Vec); 563 $ Mat A 564 $ 565 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 566 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 567 $ VecGetLocalSize(y,&m); 568 $ VecGetLocalSize(x,&n); 569 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 570 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 571 $ MatMult(A,x,y); 572 $ MatDestroy(A); 573 $ VecDestroy(y); VecDestroy(x); 574 $ 575 576 .keywords: matrix, shell, create 577 578 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() 579 @*/ 580 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 581 { 582 PetscErrorCode ierr; 583 584 PetscFunctionBegin; 585 ierr = MatCreate(comm,A);CHKERRQ(ierr); 586 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 587 588 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 589 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 590 PetscFunctionReturn(0); 591 } 592 593 #undef __FUNCT__ 594 #define __FUNCT__ "MatShellSetContext" 595 /*@ 596 MatShellSetContext - sets the context for a shell matrix 597 598 Logically Collective on Mat 599 600 Input Parameters: 601 + mat - the shell matrix 602 - ctx - the context 603 604 Level: advanced 605 606 Fortran Notes: The context can only be an integer or a PetscObject 607 unfortunately it cannot be a Fortran array or derived type. 608 609 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 610 @*/ 611 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 612 { 613 Mat_Shell *shell = (Mat_Shell*)mat->data; 614 PetscErrorCode ierr; 615 PetscBool flg; 616 617 PetscFunctionBegin; 618 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 619 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 620 if (flg) { 621 shell->ctx = ctx; 622 } 623 PetscFunctionReturn(0); 624 } 625 626 #undef __FUNCT__ 627 #define __FUNCT__ "MatShellSetOperation" 628 /*@C 629 MatShellSetOperation - Allows user to set a matrix operation for 630 a shell matrix. 631 632 Logically Collective on Mat 633 634 Input Parameters: 635 + mat - the shell matrix 636 . op - the name of the operation 637 - f - the function that provides the operation. 638 639 Level: advanced 640 641 Usage: 642 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 643 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 644 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 645 646 Notes: 647 See the file include/petscmat.h for a complete list of matrix 648 operations, which all have the form MATOP_<OPERATION>, where 649 <OPERATION> is the name (in all capital letters) of the 650 user interface routine (e.g., MatMult() -> MATOP_MULT). 651 652 All user-provided functions should have the same calling 653 sequence as the usual matrix interface routines, since they 654 are intended to be accessed via the usual matrix interface 655 routines, e.g., 656 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 657 658 In particular each function MUST return an error code of 0 on success and 659 nonzero on failure. 660 661 Within each user-defined routine, the user should call 662 MatShellGetContext() to obtain the user-defined context that was 663 set by MatCreateShell(). 664 665 Fortran Notes: For MatGetVecs() the user code should check if the input left or right matrix is -1 and in that case not 666 generate a matrix. See src/mat/examples/tests/ex120f.F 667 668 .keywords: matrix, shell, set, operation 669 670 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 671 @*/ 672 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 673 { 674 PetscErrorCode ierr; 675 PetscBool flg; 676 677 PetscFunctionBegin; 678 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 679 if (op == MATOP_DESTROY) { 680 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 681 if (flg) { 682 Mat_Shell *shell = (Mat_Shell*)mat->data; 683 shell->destroy = (PetscErrorCode (*)(Mat)) f; 684 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 685 } 686 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 687 else (((void(**)(void))mat->ops)[op]) = f; 688 689 PetscFunctionReturn(0); 690 } 691 692 #undef __FUNCT__ 693 #define __FUNCT__ "MatShellGetOperation" 694 /*@C 695 MatShellGetOperation - Gets a matrix function for a shell matrix. 696 697 Not Collective 698 699 Input Parameters: 700 + mat - the shell matrix 701 - op - the name of the operation 702 703 Output Parameter: 704 . f - the function that provides the operation. 705 706 Level: advanced 707 708 Notes: 709 See the file include/petscmat.h for a complete list of matrix 710 operations, which all have the form MATOP_<OPERATION>, where 711 <OPERATION> is the name (in all capital letters) of the 712 user interface routine (e.g., MatMult() -> MATOP_MULT). 713 714 All user-provided functions have the same calling 715 sequence as the usual matrix interface routines, since they 716 are intended to be accessed via the usual matrix interface 717 routines, e.g., 718 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 719 720 Within each user-defined routine, the user should call 721 MatShellGetContext() to obtain the user-defined context that was 722 set by MatCreateShell(). 723 724 .keywords: matrix, shell, set, operation 725 726 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 727 @*/ 728 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 729 { 730 PetscErrorCode ierr; 731 PetscBool flg; 732 733 PetscFunctionBegin; 734 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 735 if (op == MATOP_DESTROY) { 736 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 737 if (flg) { 738 Mat_Shell *shell = (Mat_Shell*)mat->data; 739 *f = (void(*)(void))shell->destroy; 740 } else { 741 *f = (void(*)(void))mat->ops->destroy; 742 } 743 } else if (op == MATOP_VIEW) { 744 *f = (void(*)(void))mat->ops->view; 745 } else { 746 *f = (((void(**)(void))mat->ops)[op]); 747 } 748 749 PetscFunctionReturn(0); 750 } 751 752