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