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