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 10 struct _MatShellOps { 11 /* 0 */ 12 PetscErrorCode (*mult)(Mat,Vec,Vec); 13 /* 5 */ 14 PetscErrorCode (*multtranspose)(Mat,Vec,Vec); 15 /* 10 */ 16 /* 15 */ 17 PetscErrorCode (*getdiagonal)(Mat,Vec); 18 /* 20 */ 19 /* 24 */ 20 /* 29 */ 21 /* 34 */ 22 /* 39 */ 23 PetscErrorCode (*axpy)(Mat,PetscScalar,Mat,MatStructure); 24 PetscErrorCode (*copy)(Mat,Mat,MatStructure); 25 /* 44 */ 26 PetscErrorCode (*diagonalset)(Mat,Vec,InsertMode); 27 /* 49 */ 28 /* 54 */ 29 /* 59 */ 30 PetscErrorCode (*destroy)(Mat); 31 /* 64 */ 32 /* 69 */ 33 /* 74 */ 34 /* 79 */ 35 /* 84 */ 36 /* 89 */ 37 /* 94 */ 38 /* 99 */ 39 /* 104 */ 40 /* 109 */ 41 /* 114 */ 42 /* 119 */ 43 /* 124 */ 44 /* 129 */ 45 /* 134 */ 46 /* 139 */ 47 /* 144 */ 48 }; 49 50 typedef struct { 51 struct _MatShellOps ops[1]; 52 53 PetscScalar vscale,vshift; 54 Vec dshift; 55 Vec left,right; 56 Vec left_work,right_work; 57 Vec left_add_work,right_add_work; 58 Mat axpy; 59 PetscScalar axpy_vscale; 60 PetscBool managescalingshifts; /* The user will manage the scaling and shifts for the MATSHELL, not the default */ 61 void *ctx; 62 } Mat_Shell; 63 64 /* 65 xx = diag(left)*x 66 */ 67 static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx) 68 { 69 Mat_Shell *shell = (Mat_Shell*)A->data; 70 PetscErrorCode ierr; 71 72 PetscFunctionBegin; 73 *xx = NULL; 74 if (!shell->left) { 75 *xx = x; 76 } else { 77 if (!shell->left_work) {ierr = VecDuplicate(shell->left,&shell->left_work);CHKERRQ(ierr);} 78 ierr = VecPointwiseMult(shell->left_work,x,shell->left);CHKERRQ(ierr); 79 *xx = shell->left_work; 80 } 81 PetscFunctionReturn(0); 82 } 83 84 /* 85 xx = diag(right)*x 86 */ 87 static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx) 88 { 89 Mat_Shell *shell = (Mat_Shell*)A->data; 90 PetscErrorCode ierr; 91 92 PetscFunctionBegin; 93 *xx = NULL; 94 if (!shell->right) { 95 *xx = x; 96 } else { 97 if (!shell->right_work) {ierr = VecDuplicate(shell->right,&shell->right_work);CHKERRQ(ierr);} 98 ierr = VecPointwiseMult(shell->right_work,x,shell->right);CHKERRQ(ierr); 99 *xx = shell->right_work; 100 } 101 PetscFunctionReturn(0); 102 } 103 104 /* 105 x = diag(left)*x 106 */ 107 static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x) 108 { 109 Mat_Shell *shell = (Mat_Shell*)A->data; 110 PetscErrorCode ierr; 111 112 PetscFunctionBegin; 113 if (shell->left) {ierr = VecPointwiseMult(x,x,shell->left);CHKERRQ(ierr);} 114 PetscFunctionReturn(0); 115 } 116 117 /* 118 x = diag(right)*x 119 */ 120 static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x) 121 { 122 Mat_Shell *shell = (Mat_Shell*)A->data; 123 PetscErrorCode ierr; 124 125 PetscFunctionBegin; 126 if (shell->right) {ierr = VecPointwiseMult(x,x,shell->right);CHKERRQ(ierr);} 127 PetscFunctionReturn(0); 128 } 129 130 /* 131 Y = vscale*Y + diag(dshift)*X + vshift*X 132 133 On input Y already contains A*x 134 */ 135 static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y) 136 { 137 Mat_Shell *shell = (Mat_Shell*)A->data; 138 PetscErrorCode ierr; 139 140 PetscFunctionBegin; 141 if (shell->dshift) { /* get arrays because there is no VecPointwiseMultAdd() */ 142 PetscInt i,m; 143 const PetscScalar *x,*d; 144 PetscScalar *y; 145 ierr = VecGetLocalSize(X,&m);CHKERRQ(ierr); 146 ierr = VecGetArrayRead(shell->dshift,&d);CHKERRQ(ierr); 147 ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr); 148 ierr = VecGetArray(Y,&y);CHKERRQ(ierr); 149 for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i]; 150 ierr = VecRestoreArrayRead(shell->dshift,&d);CHKERRQ(ierr); 151 ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr); 152 ierr = VecRestoreArray(Y,&y);CHKERRQ(ierr); 153 } else { 154 ierr = VecScale(Y,shell->vscale);CHKERRQ(ierr); 155 } 156 if (shell->vshift) {ierr = VecAXPY(Y,shell->vshift,X);CHKERRQ(ierr);} /* if test is for non-square matrices */ 157 PetscFunctionReturn(0); 158 } 159 160 /*@ 161 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 162 163 Not Collective 164 165 Input Parameter: 166 . mat - the matrix, should have been created with MatCreateShell() 167 168 Output Parameter: 169 . ctx - the user provided context 170 171 Level: advanced 172 173 Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this 174 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 175 176 .keywords: matrix, shell, get, context 177 178 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 179 @*/ 180 PetscErrorCode MatShellGetContext(Mat mat,void *ctx) 181 { 182 PetscErrorCode ierr; 183 PetscBool flg; 184 185 PetscFunctionBegin; 186 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 187 PetscValidPointer(ctx,2); 188 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 189 if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx; 190 else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix"); 191 PetscFunctionReturn(0); 192 } 193 194 PetscErrorCode MatDestroy_Shell(Mat mat) 195 { 196 PetscErrorCode ierr; 197 Mat_Shell *shell = (Mat_Shell*)mat->data; 198 199 PetscFunctionBegin; 200 if (shell->ops->destroy) { 201 ierr = (*shell->ops->destroy)(mat);CHKERRQ(ierr); 202 } 203 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 204 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 205 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 206 ierr = VecDestroy(&shell->left_work);CHKERRQ(ierr); 207 ierr = VecDestroy(&shell->right_work);CHKERRQ(ierr); 208 ierr = VecDestroy(&shell->left_add_work);CHKERRQ(ierr); 209 ierr = VecDestroy(&shell->right_add_work);CHKERRQ(ierr); 210 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 211 ierr = PetscFree(mat->data);CHKERRQ(ierr); 212 PetscFunctionReturn(0); 213 } 214 215 PetscErrorCode MatCopy_Shell(Mat A,Mat B,MatStructure str) 216 { 217 Mat_Shell *shellA = (Mat_Shell*)A->data,*shellB = (Mat_Shell*)B->data; 218 PetscErrorCode ierr; 219 PetscBool matflg; 220 221 PetscFunctionBegin; 222 ierr = PetscObjectTypeCompare((PetscObject)B,MATSHELL,&matflg);CHKERRQ(ierr); 223 if (!matflg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_NOTSAMETYPE,"Output matrix must be a MATSHELL"); 224 225 ierr = PetscMemcpy(B->ops,A->ops,sizeof(struct _MatOps));CHKERRQ(ierr); 226 ierr = PetscMemcpy(shellB->ops,shellA->ops,sizeof(struct _MatShellOps));CHKERRQ(ierr); 227 228 if (shellA->ops->copy) { 229 ierr = (*shellA->ops->copy)(A,B,str);CHKERRQ(ierr); 230 } 231 shellB->vscale = shellA->vscale; 232 shellB->vshift = shellA->vshift; 233 if (shellA->dshift) { 234 if (!shellB->dshift) { 235 ierr = VecDuplicate(shellA->dshift,&shellB->dshift);CHKERRQ(ierr); 236 } 237 ierr = VecCopy(shellA->dshift,shellB->dshift);CHKERRQ(ierr); 238 } else { 239 ierr = VecDestroy(&shellB->dshift);CHKERRQ(ierr); 240 } 241 if (shellA->left) { 242 if (!shellB->left) { 243 ierr = VecDuplicate(shellA->left,&shellB->left);CHKERRQ(ierr); 244 } 245 ierr = VecCopy(shellA->left,shellB->left);CHKERRQ(ierr); 246 } else { 247 ierr = VecDestroy(&shellB->left);CHKERRQ(ierr); 248 } 249 if (shellA->right) { 250 if (!shellB->right) { 251 ierr = VecDuplicate(shellA->right,&shellB->right);CHKERRQ(ierr); 252 } 253 ierr = VecCopy(shellA->right,shellB->right);CHKERRQ(ierr); 254 } else { 255 ierr = VecDestroy(&shellB->right);CHKERRQ(ierr); 256 } 257 PetscFunctionReturn(0); 258 } 259 260 PetscErrorCode MatDuplicate_Shell(Mat mat,MatDuplicateOption op,Mat *M) 261 { 262 PetscErrorCode ierr; 263 void *ctx; 264 265 PetscFunctionBegin; 266 ierr = MatShellGetContext(mat,&ctx);CHKERRQ(ierr); 267 ierr = MatCreateShell(PetscObjectComm((PetscObject)mat),mat->rmap->n,mat->cmap->n,mat->rmap->N,mat->cmap->N,ctx,M);CHKERRQ(ierr); 268 ierr = MatCopy(mat,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 269 PetscFunctionReturn(0); 270 } 271 272 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 273 { 274 Mat_Shell *shell = (Mat_Shell*)A->data; 275 PetscErrorCode ierr; 276 Vec xx; 277 PetscObjectState instate,outstate; 278 279 PetscFunctionBegin; 280 ierr = MatShellPreScaleRight(A,x,&xx);CHKERRQ(ierr); 281 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 282 ierr = (*shell->ops->mult)(A,xx,y);CHKERRQ(ierr); 283 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 284 if (instate == outstate) { 285 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 286 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 287 } 288 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 289 ierr = MatShellPostScaleLeft(A,y);CHKERRQ(ierr); 290 291 if (shell->axpy) { 292 if (!shell->left_work) {ierr = MatCreateVecs(A,&shell->left_work,NULL);CHKERRQ(ierr);} 293 ierr = MatMult(shell->axpy,x,shell->left_work);CHKERRQ(ierr); 294 ierr = VecAXPY(y,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr); 295 } 296 PetscFunctionReturn(0); 297 } 298 299 PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z) 300 { 301 Mat_Shell *shell = (Mat_Shell*)A->data; 302 PetscErrorCode ierr; 303 304 PetscFunctionBegin; 305 if (y == z) { 306 if (!shell->right_add_work) {ierr = VecDuplicate(z,&shell->right_add_work);CHKERRQ(ierr);} 307 ierr = MatMult(A,x,shell->right_add_work);CHKERRQ(ierr); 308 ierr = VecAXPY(z,1.0,shell->right_add_work);CHKERRQ(ierr); 309 } else { 310 ierr = MatMult(A,x,z);CHKERRQ(ierr); 311 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 312 } 313 PetscFunctionReturn(0); 314 } 315 316 PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y) 317 { 318 Mat_Shell *shell = (Mat_Shell*)A->data; 319 PetscErrorCode ierr; 320 Vec xx; 321 PetscObjectState instate,outstate; 322 323 PetscFunctionBegin; 324 ierr = MatShellPreScaleLeft(A,x,&xx);CHKERRQ(ierr); 325 ierr = PetscObjectStateGet((PetscObject)y, &instate);CHKERRQ(ierr); 326 if (!shell->ops->multtranspose) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Have not provided a MatMultTranspose() for this MATSHELL"); 327 ierr = (*shell->ops->multtranspose)(A,xx,y);CHKERRQ(ierr); 328 ierr = PetscObjectStateGet((PetscObject)y, &outstate);CHKERRQ(ierr); 329 if (instate == outstate) { 330 /* increase the state of the output vector since the user did not update its state themself as should have been done */ 331 ierr = PetscObjectStateIncrease((PetscObject)y);CHKERRQ(ierr); 332 } 333 ierr = MatShellShiftAndScale(A,xx,y);CHKERRQ(ierr); 334 ierr = MatShellPostScaleRight(A,y);CHKERRQ(ierr); 335 PetscFunctionReturn(0); 336 } 337 338 PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z) 339 { 340 Mat_Shell *shell = (Mat_Shell*)A->data; 341 PetscErrorCode ierr; 342 343 PetscFunctionBegin; 344 if (y == z) { 345 if (!shell->left_add_work) {ierr = VecDuplicate(z,&shell->left_add_work);CHKERRQ(ierr);} 346 ierr = MatMultTranspose(A,x,shell->left_add_work);CHKERRQ(ierr); 347 ierr = VecWAXPY(z,1.0,shell->left_add_work,y);CHKERRQ(ierr); 348 } else { 349 ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr); 350 ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr); 351 } 352 PetscFunctionReturn(0); 353 } 354 355 /* 356 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 357 */ 358 PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v) 359 { 360 Mat_Shell *shell = (Mat_Shell*)A->data; 361 PetscErrorCode ierr; 362 363 PetscFunctionBegin; 364 if (shell->ops->getdiagonal) { 365 ierr = (*shell->ops->getdiagonal)(A,v);CHKERRQ(ierr); 366 } else { 367 ierr = VecSet(v,0.0);CHKERRQ(ierr); 368 } 369 ierr = VecScale(v,shell->vscale);CHKERRQ(ierr); 370 if (shell->dshift) { 371 ierr = VecAXPY(v,1.0,shell->dshift);CHKERRQ(ierr); 372 } 373 ierr = VecShift(v,shell->vshift);CHKERRQ(ierr); 374 if (shell->left) {ierr = VecPointwiseMult(v,v,shell->left);CHKERRQ(ierr);} 375 if (shell->right) {ierr = VecPointwiseMult(v,v,shell->right);CHKERRQ(ierr);} 376 if (shell->axpy) { 377 if (!shell->left_work) {ierr = VecDuplicate(v,&shell->left_work);CHKERRQ(ierr);} 378 ierr = MatGetDiagonal(shell->axpy,shell->left_work);CHKERRQ(ierr); 379 ierr = VecAXPY(v,shell->axpy_vscale,shell->left_work);CHKERRQ(ierr); 380 } 381 PetscFunctionReturn(0); 382 } 383 384 PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a) 385 { 386 Mat_Shell *shell = (Mat_Shell*)Y->data; 387 PetscErrorCode ierr; 388 389 PetscFunctionBegin; 390 if (shell->left || shell->right) { 391 if (!shell->dshift) { 392 ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr); 393 ierr = VecSet(shell->dshift,a);CHKERRQ(ierr); 394 } else { 395 if (shell->left) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 396 if (shell->right) {ierr = VecPointwiseMult(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 397 ierr = VecShift(shell->dshift,a);CHKERRQ(ierr); 398 } 399 if (shell->left) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);CHKERRQ(ierr);} 400 if (shell->right) {ierr = VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);CHKERRQ(ierr);} 401 } else shell->vshift += a; 402 PetscFunctionReturn(0); 403 } 404 405 PetscErrorCode MatDiagonalSet_Shell(Mat A,Vec D,InsertMode ins) 406 { 407 Mat_Shell *shell = (Mat_Shell*)A->data; 408 PetscErrorCode ierr; 409 410 PetscFunctionBegin; 411 if (ins == INSERT_VALUES) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE, "Operation not supported with INSERT_VALUES"); 412 if (!shell->dshift) {ierr = VecDuplicate(D,&shell->dshift);CHKERRQ(ierr);} 413 if (shell->left || shell->right) { 414 if (!shell->right_work) ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->right_work);CHKERRQ(ierr); 415 if (shell->left && shell->right) { 416 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 417 ierr = VecPointwiseDivide(shell->right_work,shell->right_work,shell->right);CHKERRQ(ierr); 418 } else if (shell->left) { 419 ierr = VecPointwiseDivide(shell->right_work,D,shell->left);CHKERRQ(ierr); 420 } else { 421 ierr = VecPointwiseDivide(shell->right_work,D,shell->right);CHKERRQ(ierr); 422 } 423 if (!shell->dshift) { 424 ierr = VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift);CHKERRQ(ierr); 425 ierr = VecCopy(shell->dshift,shell->right_work);CHKERRQ(ierr); 426 } else { 427 ierr = VecAXPY(shell->dshift,1.0,shell->right_work);CHKERRQ(ierr); 428 } 429 } else { 430 ierr = VecAXPY(shell->dshift,1.0,D);CHKERRQ(ierr); 431 } 432 PetscFunctionReturn(0); 433 } 434 435 PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a) 436 { 437 Mat_Shell *shell = (Mat_Shell*)Y->data; 438 PetscErrorCode ierr; 439 440 PetscFunctionBegin; 441 shell->vscale *= a; 442 shell->vshift *= a; 443 if (shell->dshift) { 444 ierr = VecScale(shell->dshift,a);CHKERRQ(ierr); 445 } 446 shell->axpy_vscale *= a; 447 PetscFunctionReturn(0); 448 } 449 450 static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right) 451 { 452 Mat_Shell *shell = (Mat_Shell*)Y->data; 453 PetscErrorCode ierr; 454 455 PetscFunctionBegin; 456 if (shell->axpy) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot diagonal scale MATSHELL after MatAXPY operation"); 457 if (left) { 458 if (!shell->left) { 459 ierr = VecDuplicate(left,&shell->left);CHKERRQ(ierr); 460 ierr = VecCopy(left,shell->left);CHKERRQ(ierr); 461 } else { 462 ierr = VecPointwiseMult(shell->left,shell->left,left);CHKERRQ(ierr); 463 } 464 } 465 if (right) { 466 if (!shell->right) { 467 ierr = VecDuplicate(right,&shell->right);CHKERRQ(ierr); 468 ierr = VecCopy(right,shell->right);CHKERRQ(ierr); 469 } else { 470 ierr = VecPointwiseMult(shell->right,shell->right,right);CHKERRQ(ierr); 471 } 472 } 473 PetscFunctionReturn(0); 474 } 475 476 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 477 { 478 Mat_Shell *shell = (Mat_Shell*)Y->data; 479 PetscErrorCode ierr; 480 481 PetscFunctionBegin; 482 if (t == MAT_FINAL_ASSEMBLY) { 483 shell->vshift = 0.0; 484 shell->vscale = 1.0; 485 ierr = VecDestroy(&shell->dshift);CHKERRQ(ierr); 486 ierr = VecDestroy(&shell->left);CHKERRQ(ierr); 487 ierr = VecDestroy(&shell->right);CHKERRQ(ierr); 488 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 489 } 490 PetscFunctionReturn(0); 491 } 492 493 PETSC_INTERN PetscErrorCode MatConvert_Shell(Mat, MatType,MatReuse,Mat*); 494 495 static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool *missing,PetscInt *d) 496 { 497 PetscFunctionBegin; 498 *missing = PETSC_FALSE; 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode MatAXPY_Shell(Mat Y,PetscScalar a,Mat X,MatStructure str) 503 { 504 Mat_Shell *shell = (Mat_Shell*)Y->data; 505 PetscErrorCode ierr; 506 507 PetscFunctionBegin; 508 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 509 ierr = MatDestroy(&shell->axpy);CHKERRQ(ierr); 510 shell->axpy = X; 511 shell->axpy_vscale = a; 512 PetscFunctionReturn(0); 513 } 514 515 static struct _MatOps MatOps_Values = {0, 516 0, 517 0, 518 0, 519 /* 4*/ MatMultAdd_Shell, 520 0, 521 MatMultTransposeAdd_Shell, 522 0, 523 0, 524 0, 525 /*10*/ 0, 526 0, 527 0, 528 0, 529 0, 530 /*15*/ 0, 531 0, 532 MatGetDiagonal_Shell, 533 MatDiagonalScale_Shell, 534 0, 535 /*20*/ 0, 536 MatAssemblyEnd_Shell, 537 0, 538 0, 539 /*24*/ 0, 540 0, 541 0, 542 0, 543 0, 544 /*29*/ 0, 545 0, 546 0, 547 0, 548 0, 549 /*34*/ MatDuplicate_Shell, 550 0, 551 0, 552 0, 553 0, 554 /*39*/ MatAXPY_Shell, 555 0, 556 0, 557 0, 558 MatCopy_Shell, 559 /*44*/ 0, 560 MatScale_Shell, 561 MatShift_Shell, 562 MatDiagonalSet_Shell, 563 0, 564 /*49*/ 0, 565 0, 566 0, 567 0, 568 0, 569 /*54*/ 0, 570 0, 571 0, 572 0, 573 0, 574 /*59*/ 0, 575 MatDestroy_Shell, 576 0, 577 0, 578 0, 579 /*64*/ 0, 580 0, 581 0, 582 0, 583 0, 584 /*69*/ 0, 585 0, 586 MatConvert_Shell, 587 0, 588 0, 589 /*74*/ 0, 590 0, 591 0, 592 0, 593 0, 594 /*79*/ 0, 595 0, 596 0, 597 0, 598 0, 599 /*84*/ 0, 600 0, 601 0, 602 0, 603 0, 604 /*89*/ 0, 605 0, 606 0, 607 0, 608 0, 609 /*94*/ 0, 610 0, 611 0, 612 0, 613 0, 614 /*99*/ 0, 615 0, 616 0, 617 0, 618 0, 619 /*104*/ 0, 620 0, 621 0, 622 0, 623 0, 624 /*109*/ 0, 625 0, 626 0, 627 0, 628 MatMissingDiagonal_Shell, 629 /*114*/ 0, 630 0, 631 0, 632 0, 633 0, 634 /*119*/ 0, 635 0, 636 0, 637 0, 638 0, 639 /*124*/ 0, 640 0, 641 0, 642 0, 643 0, 644 /*129*/ 0, 645 0, 646 0, 647 0, 648 0, 649 /*134*/ 0, 650 0, 651 0, 652 0, 653 0, 654 /*139*/ 0, 655 0, 656 0 657 }; 658 659 /*MC 660 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 661 662 Level: advanced 663 664 .seealso: MatCreateShell() 665 M*/ 666 667 PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A) 668 { 669 Mat_Shell *b; 670 PetscErrorCode ierr; 671 672 PetscFunctionBegin; 673 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 674 675 ierr = PetscNewLog(A,&b);CHKERRQ(ierr); 676 A->data = (void*)b; 677 678 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 679 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 680 681 b->ctx = 0; 682 b->vshift = 0.0; 683 b->vscale = 1.0; 684 b->managescalingshifts = PETSC_TRUE; 685 A->assembled = PETSC_TRUE; 686 A->preallocated = PETSC_FALSE; 687 688 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSHELL);CHKERRQ(ierr); 689 PetscFunctionReturn(0); 690 } 691 692 /*@C 693 MatCreateShell - Creates a new matrix class for use with a user-defined 694 private data storage format. 695 696 Collective on MPI_Comm 697 698 Input Parameters: 699 + comm - MPI communicator 700 . m - number of local rows (must be given) 701 . n - number of local columns (must be given) 702 . M - number of global rows (may be PETSC_DETERMINE) 703 . N - number of global columns (may be PETSC_DETERMINE) 704 - ctx - pointer to data needed by the shell matrix routines 705 706 Output Parameter: 707 . A - the matrix 708 709 Level: advanced 710 711 Usage: 712 $ extern int mult(Mat,Vec,Vec); 713 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 714 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 715 $ [ Use matrix for operations that have been set ] 716 $ MatDestroy(mat); 717 718 Notes: 719 The shell matrix type is intended to provide a simple class to use 720 with KSP (such as, for use with matrix-free methods). You should not 721 use the shell type if you plan to define a complete matrix class. 722 723 Fortran Notes: To use this from Fortran with a ctx you must write an interface definition for this 724 function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing 725 in as the ctx argument. 726 727 PETSc requires that matrices and vectors being used for certain 728 operations are partitioned accordingly. For example, when 729 creating a shell matrix, A, that supports parallel matrix-vector 730 products using MatMult(A,x,y) the user should set the number 731 of local matrix rows to be the number of local elements of the 732 corresponding result vector, y. Note that this is information is 733 required for use of the matrix interface routines, even though 734 the shell matrix may not actually be physically partitioned. 735 For example, 736 737 MATSHELL handles MatShift(), MatDiagonalSet(), MatDiagonalScale(), and MatScale() internally so these 738 operations cannot be overwritten unless MatShellSetManageScalingShifts() is called. 739 740 $ 741 $ Vec x, y 742 $ extern int mult(Mat,Vec,Vec); 743 $ Mat A 744 $ 745 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 746 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 747 $ VecGetLocalSize(y,&m); 748 $ VecGetLocalSize(x,&n); 749 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 750 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 751 $ MatMult(A,x,y); 752 $ MatDestroy(A); 753 $ VecDestroy(y); VecDestroy(x); 754 $ 755 756 For rectangular matrices do all the scalings and shifts make sense? 757 758 Developers Notes: Regarding shifting and scaling. The general form is 759 760 diag(left)(vscale*A + diag(dshift) + vshift I)diag(right) 761 762 The order you apply the operations is important. For example if you have a dshift then 763 apply a MatScale(s) you get s*vscale*A + s*diag(shift). But if you first scale and then shift 764 you get s*vscale*A + diag(shift) 765 766 A is the user provided function. 767 768 .keywords: matrix, shell, create 769 770 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext(), MATSHELL, MatShellSetManageScalingShifts() 771 @*/ 772 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 773 { 774 PetscErrorCode ierr; 775 776 PetscFunctionBegin; 777 ierr = MatCreate(comm,A);CHKERRQ(ierr); 778 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 779 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 780 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 781 ierr = MatSetUp(*A);CHKERRQ(ierr); 782 PetscFunctionReturn(0); 783 } 784 785 /*@ 786 MatShellSetContext - sets the context for a shell matrix 787 788 Logically Collective on Mat 789 790 Input Parameters: 791 + mat - the shell matrix 792 - ctx - the context 793 794 Level: advanced 795 796 Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this 797 function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument. 798 799 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 800 @*/ 801 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 802 { 803 Mat_Shell *shell = (Mat_Shell*)mat->data; 804 PetscErrorCode ierr; 805 PetscBool flg; 806 807 PetscFunctionBegin; 808 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 809 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 810 if (flg) { 811 shell->ctx = ctx; 812 } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix"); 813 PetscFunctionReturn(0); 814 } 815 816 /*@ 817 MatShellSetManageScalingShifts - Allows the user to control the scaling and shift operations of the MATSHELL. Must be called immediately 818 after MatCreateShell() 819 820 Logically Collective on Mat 821 822 Input Parameter: 823 . mat - the shell matrix 824 825 Level: advanced 826 827 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation() 828 @*/ 829 PetscErrorCode MatShellSetManageScalingShifts(Mat A) 830 { 831 PetscErrorCode ierr; 832 Mat_Shell *shell = (Mat_Shell*)A->data; 833 PetscBool flg; 834 835 PetscFunctionBegin; 836 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 837 ierr = PetscObjectTypeCompare((PetscObject)A,MATSHELL,&flg);CHKERRQ(ierr); 838 if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Can only use with MATSHELL matrices"); 839 shell->managescalingshifts = PETSC_FALSE; 840 A->ops->diagonalscale = 0; 841 A->ops->scale = 0; 842 A->ops->shift = 0; 843 A->ops->diagonalset = 0; 844 PetscFunctionReturn(0); 845 } 846 847 /*@C 848 MatShellTestMult - Compares the multiply routine provided to the MATSHELL with differencing on a given function. 849 850 Logically Collective on Mat 851 852 Input Parameters: 853 + mat - the shell matrix 854 . f - the function 855 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 856 - ctx - an optional context for the function 857 858 Output Parameter: 859 . flg - PETSC_TRUE if the multiply is likely correct 860 861 Options Database: 862 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 863 864 Level: advanced 865 866 Fortran Notes: Not supported from Fortran 867 868 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMultTranspose() 869 @*/ 870 PetscErrorCode MatShellTestMult(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 871 { 872 PetscErrorCode ierr; 873 PetscInt m,n; 874 Mat mf,Dmf,Dmat,Ddiff; 875 PetscReal Diffnorm,Dmfnorm; 876 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 877 878 PetscFunctionBegin; 879 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 880 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_view",&v);CHKERRQ(ierr); 881 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 882 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,PETSC_DECIDE,PETSC_DECIDE,&mf);CHKERRQ(ierr); 883 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 884 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 885 886 ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr); 887 ierr = MatComputeExplicitOperator(mat,&Dmat);CHKERRQ(ierr); 888 889 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 890 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 891 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 892 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 893 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 894 flag = PETSC_FALSE; 895 if (v) { 896 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm)); 897 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 898 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 899 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_view");CHKERRQ(ierr); 900 } 901 } else if (v) { 902 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce the same results\n"); 903 } 904 if (flg) *flg = flag; 905 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 906 ierr = MatDestroy(&mf);CHKERRQ(ierr); 907 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 908 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 909 PetscFunctionReturn(0); 910 } 911 912 /*@C 913 MatShellTestMultTranpose - Compares the multiply transpose routine provided to the MATSHELL with differencing on a given function. 914 915 Logically Collective on Mat 916 917 Input Parameters: 918 + mat - the shell matrix 919 . f - the function 920 . base - differences are computed around this vector, see MatMFFDSetBase(), for Jacobians this is the point at which the Jacobian is being evaluated 921 - ctx - an optional context for the function 922 923 Output Parameter: 924 . flg - PETSC_TRUE if the multiply is likely correct 925 926 Options Database: 927 . -mat_shell_test_mult_view - print if any differences are detected between the products and print the difference 928 929 Level: advanced 930 931 Fortran Notes: Not supported from Fortran 932 933 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellTestMult() 934 @*/ 935 PetscErrorCode MatShellTestMultTranspose(Mat mat,PetscErrorCode (*f)(void*,Vec,Vec),Vec base,void *ctx,PetscBool *flg) 936 { 937 PetscErrorCode ierr; 938 Vec x,y,z; 939 PetscInt m,n,M,N; 940 Mat mf,Dmf,Dmat,Ddiff; 941 PetscReal Diffnorm,Dmfnorm; 942 PetscBool v = PETSC_FALSE, flag = PETSC_TRUE; 943 944 PetscFunctionBegin; 945 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 946 ierr = PetscOptionsHasName(NULL,((PetscObject)mat)->prefix,"-mat_shell_test_mult_transpose_view",&v);CHKERRQ(ierr); 947 ierr = MatCreateVecs(mat,&x,&y);CHKERRQ(ierr); 948 ierr = VecDuplicate(y,&z);CHKERRQ(ierr); 949 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 950 ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr); 951 ierr = MatCreateMFFD(PetscObjectComm((PetscObject)mat),m,n,M,N,&mf);CHKERRQ(ierr); 952 ierr = MatMFFDSetFunction(mf,f,ctx);CHKERRQ(ierr); 953 ierr = MatMFFDSetBase(mf,base,NULL);CHKERRQ(ierr); 954 ierr = MatComputeExplicitOperator(mf,&Dmf);CHKERRQ(ierr); 955 ierr = MatTranspose(Dmf,MAT_INPLACE_MATRIX,&Dmf);CHKERRQ(ierr); 956 ierr = MatComputeExplicitOperatorTranspose(mat,&Dmat);CHKERRQ(ierr); 957 958 ierr = MatDuplicate(Dmat,MAT_COPY_VALUES,&Ddiff);CHKERRQ(ierr); 959 ierr = MatAXPY(Ddiff,-1.0,Dmf,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 960 ierr = MatNorm(Ddiff,NORM_FROBENIUS,&Diffnorm);CHKERRQ(ierr); 961 ierr = MatNorm(Dmf,NORM_FROBENIUS,&Dmfnorm);CHKERRQ(ierr); 962 if (Diffnorm/Dmfnorm > 10*PETSC_SQRT_MACHINE_EPSILON) { 963 flag = PETSC_FALSE; 964 if (v) { 965 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL and matrix free multiple appear to produce different results.\n Norm Ratio %g Difference results followed by finite difference one\n",(double)(Diffnorm/Dmfnorm)); 966 ierr = MatViewFromOptions(Ddiff,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 967 ierr = MatViewFromOptions(Dmf,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 968 ierr = MatViewFromOptions(Dmat,(PetscObject)mat,"-mat_shell_test_mult_transpose_view");CHKERRQ(ierr); 969 } 970 } else if (v) { 971 ierr = PetscPrintf(PetscObjectComm((PetscObject)mat),"MATSHELL transpose and matrix free multiple appear to produce the same results\n"); 972 } 973 if (flg) *flg = flag; 974 ierr = MatDestroy(&mf);CHKERRQ(ierr); 975 ierr = MatDestroy(&Dmat);CHKERRQ(ierr); 976 ierr = MatDestroy(&Ddiff);CHKERRQ(ierr); 977 ierr = MatDestroy(&Dmf);CHKERRQ(ierr); 978 ierr = VecDestroy(&x);CHKERRQ(ierr); 979 ierr = VecDestroy(&y);CHKERRQ(ierr); 980 ierr = VecDestroy(&z);CHKERRQ(ierr); 981 PetscFunctionReturn(0); 982 } 983 984 /*@C 985 MatShellSetOperation - Allows user to set a matrix operation for 986 a shell matrix. 987 MatShellSetOperation - Allows user to set a matrix operation for a shell matrix. 988 989 Logically Collective on Mat 990 991 Input Parameters: 992 + mat - the shell matrix 993 . op - the name of the operation 994 - f - the function that provides the operation. 995 996 Level: advanced 997 998 Usage: 999 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 1000 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 1001 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 1002 1003 Notes: 1004 See the file include/petscmat.h for a complete list of matrix 1005 operations, which all have the form MATOP_<OPERATION>, where 1006 <OPERATION> is the name (in all capital letters) of the 1007 user interface routine (e.g., MatMult() -> MATOP_MULT). 1008 1009 All user-provided functions (except for MATOP_DESTROY) should have the same calling 1010 sequence as the usual matrix interface routines, since they 1011 are intended to be accessed via the usual matrix interface 1012 routines, e.g., 1013 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 1014 1015 In particular each function MUST return an error code of 0 on success and 1016 nonzero on failure. 1017 1018 Within each user-defined routine, the user should call 1019 MatShellGetContext() to obtain the user-defined context that was 1020 set by MatCreateShell(). 1021 1022 Fortran Notes: For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not 1023 generate a matrix. See src/mat/examples/tests/ex120f.F 1024 1025 Use MatSetOperation() to set an operation for any matrix type 1026 1027 .keywords: matrix, shell, set, operation 1028 1029 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatSetOperation(), MatShellSetManageScalingShifts() 1030 @*/ 1031 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 1032 { 1033 PetscErrorCode ierr; 1034 PetscBool flg; 1035 Mat_Shell *shell = (Mat_Shell*)mat->data; 1036 1037 PetscFunctionBegin; 1038 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1039 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1040 if (!flg) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Can only use with MATSHELL matrices"); 1041 switch (op) { 1042 case MATOP_DESTROY: 1043 shell->ops->destroy = (PetscErrorCode (*)(Mat))f; 1044 break; 1045 case MATOP_DIAGONAL_SET: 1046 case MATOP_DIAGONAL_SCALE: 1047 case MATOP_SHIFT: 1048 case MATOP_SCALE: 1049 case MATOP_AXPY: 1050 if (shell->managescalingshifts) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MATSHELL is managing scalings and shifts, see MatShellSetManageScalingShifts()"); 1051 (((void(**)(void))mat->ops)[op]) = f; 1052 break; 1053 case MATOP_GET_DIAGONAL: 1054 if (shell->managescalingshifts) shell->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1055 else mat->ops->getdiagonal = (PetscErrorCode (*)(Mat,Vec))f; 1056 case MATOP_VIEW: 1057 if (!mat->ops->viewnative) { 1058 mat->ops->viewnative = mat->ops->view; 1059 } 1060 mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f; 1061 break; 1062 case MATOP_MULT: 1063 if (shell->managescalingshifts){ 1064 shell->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1065 mat->ops->mult = MatMult_Shell; 1066 } else mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1067 break; 1068 case MATOP_MULT_TRANSPOSE: 1069 if (shell->managescalingshifts) { 1070 shell->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1071 mat->ops->multtranspose = MatMultTranspose_Shell; 1072 } else mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f; 1073 break; 1074 default: 1075 (((void(**)(void))mat->ops)[op]) = f; 1076 } 1077 PetscFunctionReturn(0); 1078 } 1079 1080 /*@C 1081 MatShellGetOperation - Gets a matrix function for a shell matrix. 1082 1083 Not Collective 1084 1085 Input Parameters: 1086 + mat - the shell matrix 1087 - op - the name of the operation 1088 1089 Output Parameter: 1090 . f - the function that provides the operation. 1091 1092 Level: advanced 1093 1094 Notes: 1095 See the file include/petscmat.h for a complete list of matrix 1096 operations, which all have the form MATOP_<OPERATION>, where 1097 <OPERATION> is the name (in all capital letters) of the 1098 user interface routine (e.g., MatMult() -> MATOP_MULT). 1099 1100 All user-provided functions have the same calling 1101 sequence as the usual matrix interface routines, since they 1102 are intended to be accessed via the usual matrix interface 1103 routines, e.g., 1104 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 1105 1106 Within each user-defined routine, the user should call 1107 MatShellGetContext() to obtain the user-defined context that was 1108 set by MatCreateShell(). 1109 1110 .keywords: matrix, shell, set, operation 1111 1112 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 1113 @*/ 1114 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 1115 { 1116 PetscErrorCode ierr; 1117 PetscBool flg; 1118 1119 PetscFunctionBegin; 1120 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1121 switch (op) { 1122 case MATOP_DESTROY: 1123 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1124 if (flg) { 1125 Mat_Shell *shell = (Mat_Shell*)mat->data; 1126 *f = (void (*)(void))shell->ops->destroy; 1127 } else { 1128 *f = (void (*)(void))mat->ops->destroy; 1129 } 1130 break; 1131 case MATOP_DIAGONAL_SET: 1132 ierr = PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 1133 if (flg) { 1134 Mat_Shell *shell = (Mat_Shell*)mat->data; 1135 *f = (void (*)(void))shell->ops->diagonalset; 1136 } else { 1137 *f = (void (*)(void))mat->ops->diagonalset; 1138 } 1139 break; 1140 case MATOP_VIEW: 1141 *f = (void (*)(void))mat->ops->view; 1142 break; 1143 default: 1144 *f = (((void (**)(void))mat->ops)[op]); 1145 } 1146 PetscFunctionReturn(0); 1147 } 1148 1149 /*@C 1150 MatSetOperation - Allows user to set a matrix operation for any matrix type 1151 1152 Logically Collective on Mat 1153 1154 Input Parameters: 1155 + mat - the shell matrix 1156 . op - the name of the operation 1157 - f - the function that provides the operation. 1158 1159 Level: developer 1160 1161 Usage: 1162 $ extern PetscErrorCode usermult(Mat,Vec,Vec); 1163 $ ierr = MatCreateXXX(comm,...&A); 1164 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 1165 1166 Notes: 1167 See the file include/petscmat.h for a complete list of matrix 1168 operations, which all have the form MATOP_<OPERATION>, where 1169 <OPERATION> is the name (in all capital letters) of the 1170 user interface routine (e.g., MatMult() -> MATOP_MULT). 1171 1172 All user-provided functions (except for MATOP_DESTROY) should have the same calling 1173 sequence as the usual matrix interface routines, since they 1174 are intended to be accessed via the usual matrix interface 1175 routines, e.g., 1176 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 1177 1178 In particular each function MUST return an error code of 0 on success and 1179 nonzero on failure. 1180 1181 This routine is distinct from MatShellSetOperation() in that it can be called on any matrix type. 1182 1183 .keywords: matrix, shell, set, operation 1184 1185 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext(), MatShellSetOperation() 1186 @*/ 1187 PetscErrorCode MatSetOperation(Mat mat,MatOperation op,void (*f)(void)) 1188 { 1189 PetscFunctionBegin; 1190 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1191 (((void(**)(void))mat->ops)[op]) = f; 1192 PetscFunctionReturn(0); 1193 } 1194