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