Actual source code: shell.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  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: */

  8: #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
  9: #include <petsc/private/vecimpl.h>

 11: typedef struct {
 12:   PetscErrorCode (*destroy)(Mat);
 13:   PetscErrorCode (*mult)(Mat,Vec,Vec);
 14:   PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
 15:   PetscErrorCode (*getdiagonal)(Mat,Vec);

 17:   PetscScalar vscale,vshift;
 18:   Vec         dshift;
 19:   Vec         left,right;
 20:   Vec         dshift_owned,left_owned,right_owned;
 21:   Vec         left_work,right_work;
 22:   Vec         left_add_work,right_add_work;
 23:   PetscBool   usingscaled;
 24:   void        *ctx;
 25: } Mat_Shell;
 26: /*
 27:  The most general expression for the matrix is

 29:  S = L (a A + B) R

 31:  where
 32:  A is the matrix defined by the user's function
 33:  a is a scalar multiple
 34:  L is left scaling
 35:  R is right scaling
 36:  B is a diagonal shift defined by
 37:    diag(dshift) if the vector dshift is non-NULL
 38:    vscale*identity otherwise

 40:  The following identities apply:

 42:  Scale by c:
 43:   c [L (a A + B) R] = L [(a c) A + c B] R

 45:  Shift by c:
 46:   [L (a A + B) R] + c = L [a A + (B + c Linv Rinv)] R

 48:  Diagonal scaling is achieved by simply multiplying with existing L and R vectors

 50:  In the data structure:

 52:  vscale=1.0  means no special scaling will be applied
 53:  dshift=NULL means a constant diagonal shift (fall back to vshift)
 54:  vshift=0.0  means no constant diagonal shift, note that vshift is only used if dshift is NULL
 55: */

 57: static PetscErrorCode MatMult_Shell(Mat,Vec,Vec);
 58: static PetscErrorCode MatMultTranspose_Shell(Mat,Vec,Vec);
 59: static PetscErrorCode MatGetDiagonal_Shell(Mat,Vec);

 63: static PetscErrorCode MatShellUseScaledMethods(Mat Y)
 64: {
 65:   Mat_Shell *shell = (Mat_Shell*)Y->data;

 68:   if (shell->usingscaled) return(0);
 69:   shell->mult  = Y->ops->mult;
 70:   Y->ops->mult = MatMult_Shell;
 71:   if (Y->ops->multtranspose) {
 72:     shell->multtranspose  = Y->ops->multtranspose;
 73:     Y->ops->multtranspose = MatMultTranspose_Shell;
 74:   }
 75:   if (Y->ops->getdiagonal) {
 76:     shell->getdiagonal  = Y->ops->getdiagonal;
 77:     Y->ops->getdiagonal = MatGetDiagonal_Shell;
 78:   }
 79:   shell->usingscaled = PETSC_TRUE;
 80:   return(0);
 81: }

 85: static PetscErrorCode MatShellPreScaleLeft(Mat A,Vec x,Vec *xx)
 86: {
 87:   Mat_Shell      *shell = (Mat_Shell*)A->data;

 91:   *xx = NULL;
 92:   if (!shell->left) {
 93:     *xx = x;
 94:   } else {
 95:     if (!shell->left_work) {VecDuplicate(shell->left,&shell->left_work);}
 96:     VecPointwiseMult(shell->left_work,x,shell->left);
 97:     *xx  = shell->left_work;
 98:   }
 99:   return(0);
100: }

104: static PetscErrorCode MatShellPreScaleRight(Mat A,Vec x,Vec *xx)
105: {
106:   Mat_Shell      *shell = (Mat_Shell*)A->data;

110:   *xx = NULL;
111:   if (!shell->right) {
112:     *xx = x;
113:   } else {
114:     if (!shell->right_work) {VecDuplicate(shell->right,&shell->right_work);}
115:     VecPointwiseMult(shell->right_work,x,shell->right);
116:     *xx  = shell->right_work;
117:   }
118:   return(0);
119: }

123: static PetscErrorCode MatShellPostScaleLeft(Mat A,Vec x)
124: {
125:   Mat_Shell      *shell = (Mat_Shell*)A->data;

129:   if (shell->left) {VecPointwiseMult(x,x,shell->left);}
130:   return(0);
131: }

135: static PetscErrorCode MatShellPostScaleRight(Mat A,Vec x)
136: {
137:   Mat_Shell      *shell = (Mat_Shell*)A->data;

141:   if (shell->right) {VecPointwiseMult(x,x,shell->right);}
142:   return(0);
143: }

147: static PetscErrorCode MatShellShiftAndScale(Mat A,Vec X,Vec Y)
148: {
149:   Mat_Shell      *shell = (Mat_Shell*)A->data;

153:   if (shell->dshift) {          /* get arrays because there is no VecPointwiseMultAdd() */
154:     PetscInt          i,m;
155:     const PetscScalar *x,*d;
156:     PetscScalar       *y;
157:     VecGetLocalSize(X,&m);
158:     VecGetArrayRead(shell->dshift,&d);
159:     VecGetArrayRead(X,&x);
160:     VecGetArray(Y,&y);
161:     for (i=0; i<m; i++) y[i] = shell->vscale*y[i] + d[i]*x[i];
162:     VecRestoreArrayRead(shell->dshift,&d);
163:     VecRestoreArrayRead(X,&x);
164:     VecRestoreArray(Y,&y);
165:   } else if (PetscAbsScalar(shell->vshift) != 0) {
166:     VecAXPBY(Y,shell->vshift,shell->vscale,X);
167:   } else if (shell->vscale != 1.0) {
168:     VecScale(Y,shell->vscale);
169:   }
170:   return(0);
171: }

175: /*@
176:     MatShellGetContext - Returns the user-provided context associated with a shell matrix.

178:     Not Collective

180:     Input Parameter:
181: .   mat - the matrix, should have been created with MatCreateShell()

183:     Output Parameter:
184: .   ctx - the user provided context

186:     Level: advanced

188:    Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this
189:     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.

191: .keywords: matrix, shell, get, context

193: .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
194: @*/
195: PetscErrorCode  MatShellGetContext(Mat mat,void *ctx)
196: {
198:   PetscBool      flg;

203:   PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);
204:   if (flg) *(void**)ctx = ((Mat_Shell*)(mat->data))->ctx;
205:   else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot get context from non-shell matrix");
206:   return(0);
207: }

211: PetscErrorCode MatDestroy_Shell(Mat mat)
212: {
214:   Mat_Shell      *shell = (Mat_Shell*)mat->data;

217:   if (shell->destroy) {
218:     (*shell->destroy)(mat);
219:   }
220:   VecDestroy(&shell->left_owned);
221:   VecDestroy(&shell->right_owned);
222:   VecDestroy(&shell->dshift_owned);
223:   VecDestroy(&shell->left_work);
224:   VecDestroy(&shell->right_work);
225:   VecDestroy(&shell->left_add_work);
226:   VecDestroy(&shell->right_add_work);
227:   PetscFree(mat->data);
228:   return(0);
229: }

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:   PetscObjectState instate,outstate;

241:   MatShellPreScaleRight(A,x,&xx);
242:   PetscObjectStateGet((PetscObject)y, &instate);
243:   (*shell->mult)(A,xx,y);
244:   PetscObjectStateGet((PetscObject)y, &outstate);
245:   if (instate == outstate) {
246:     /* increase the state of the output vector since the user did not update its state themself as should have been done */
247:     PetscObjectStateIncrease((PetscObject)y);
248:   }
249:   MatShellShiftAndScale(A,xx,y);
250:   MatShellPostScaleLeft(A,y);
251:   return(0);
252: }

256: PetscErrorCode MatMultAdd_Shell(Mat A,Vec x,Vec y,Vec z)
257: {
258:   Mat_Shell      *shell = (Mat_Shell*)A->data;

262:   if (y == z) {
263:     if (!shell->right_add_work) {VecDuplicate(z,&shell->right_add_work);}
264:     MatMult(A,x,shell->right_add_work);
265:     VecAXPY(z,1.0,shell->right_add_work);
266:   } else {
267:     MatMult(A,x,z);
268:     VecAXPY(z,1.0,y);
269:   }
270:   return(0);
271: }

275: PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
276: {
277:   Mat_Shell        *shell = (Mat_Shell*)A->data;
278:   PetscErrorCode   ierr;
279:   Vec              xx;
280:   PetscObjectState instate,outstate;

283:   MatShellPreScaleLeft(A,x,&xx);
284:   PetscObjectStateGet((PetscObject)y, &instate);
285:   (*shell->multtranspose)(A,xx,y);
286:   PetscObjectStateGet((PetscObject)y, &outstate);
287:   if (instate == outstate) {
288:     /* increase the state of the output vector since the user did not update its state themself as should have been done */
289:     PetscObjectStateIncrease((PetscObject)y);
290:   }
291:   MatShellShiftAndScale(A,xx,y);
292:   MatShellPostScaleRight(A,y);
293:   return(0);
294: }

298: PetscErrorCode MatMultTransposeAdd_Shell(Mat A,Vec x,Vec y,Vec z)
299: {
300:   Mat_Shell      *shell = (Mat_Shell*)A->data;

304:   if (y == z) {
305:     if (!shell->left_add_work) {VecDuplicate(z,&shell->left_add_work);}
306:     MatMultTranspose(A,x,shell->left_add_work);
307:     VecWAXPY(z,1.0,shell->left_add_work,y);
308:   } else {
309:     MatMultTranspose(A,x,z);
310:     VecAXPY(z,1.0,y);
311:   }
312:   return(0);
313: }

317: PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
318: {
319:   Mat_Shell      *shell = (Mat_Shell*)A->data;

323:   (*shell->getdiagonal)(A,v);
324:   VecScale(v,shell->vscale);
325:   if (shell->dshift) {
326:     VecPointwiseMult(v,v,shell->dshift);
327:   } else {
328:     VecShift(v,shell->vshift);
329:   }
330:   if (shell->left)  {VecPointwiseMult(v,v,shell->left);}
331:   if (shell->right) {VecPointwiseMult(v,v,shell->right);}
332:   return(0);
333: }

337: PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
338: {
339:   Mat_Shell      *shell = (Mat_Shell*)Y->data;

343:   if (shell->left || shell->right || shell->dshift) {
344:     if (!shell->dshift) {
345:       if (!shell->dshift_owned) {VecDuplicate(shell->left ? shell->left : shell->right, &shell->dshift_owned);}
346:       shell->dshift = shell->dshift_owned;
347:       VecSet(shell->dshift,shell->vshift+a);
348:     } else {VecScale(shell->dshift,a);}
349:     if (shell->left)  {VecPointwiseDivide(shell->dshift,shell->dshift,shell->left);}
350:     if (shell->right) {VecPointwiseDivide(shell->dshift,shell->dshift,shell->right);}
351:   } else shell->vshift += a;
352:   MatShellUseScaledMethods(Y);
353:   return(0);
354: }

358: PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
359: {
360:   Mat_Shell      *shell = (Mat_Shell*)Y->data;

364:   shell->vscale *= a;
365:   if (shell->dshift) {
366:     VecScale(shell->dshift,a);
367:   } else shell->vshift *= a;
368:   MatShellUseScaledMethods(Y);
369:   return(0);
370: }

374: static PetscErrorCode MatDiagonalScale_Shell(Mat Y,Vec left,Vec right)
375: {
376:   Mat_Shell      *shell = (Mat_Shell*)Y->data;

380:   if (left) {
381:     if (!shell->left_owned) {VecDuplicate(left,&shell->left_owned);}
382:     if (shell->left) {
383:       VecPointwiseMult(shell->left,shell->left,left);
384:     } else {
385:       shell->left = shell->left_owned;
386:       VecCopy(left,shell->left);
387:     }
388:   }
389:   if (right) {
390:     if (!shell->right_owned) {VecDuplicate(right,&shell->right_owned);}
391:     if (shell->right) {
392:       VecPointwiseMult(shell->right,shell->right,right);
393:     } else {
394:       shell->right = shell->right_owned;
395:       VecCopy(right,shell->right);
396:     }
397:   }
398:   MatShellUseScaledMethods(Y);
399:   return(0);
400: }

404: PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
405: {
406:   Mat_Shell *shell = (Mat_Shell*)Y->data;

409:   if (t == MAT_FINAL_ASSEMBLY) {
410:     shell->vshift = 0.0;
411:     shell->vscale = 1.0;
412:     shell->dshift = NULL;
413:     shell->left   = NULL;
414:     shell->right  = NULL;
415:     if (shell->mult) {
416:       Y->ops->mult = shell->mult;
417:       shell->mult  = NULL;
418:     }
419:     if (shell->multtranspose) {
420:       Y->ops->multtranspose = shell->multtranspose;
421:       shell->multtranspose  = NULL;
422:     }
423:     if (shell->getdiagonal) {
424:       Y->ops->getdiagonal = shell->getdiagonal;
425:       shell->getdiagonal  = NULL;
426:     }
427:     shell->usingscaled = PETSC_FALSE;
428:   }
429:   return(0);
430: }

432: PETSC_INTERN PetscErrorCode MatConvert_Shell(Mat, MatType,MatReuse,Mat*);

436: static PetscErrorCode MatMissingDiagonal_Shell(Mat A,PetscBool  *missing,PetscInt *d)
437: {
439:   *missing = PETSC_FALSE;
440:   return(0);
441: }

443: static struct _MatOps MatOps_Values = {0,
444:                                        0,
445:                                        0,
446:                                        0,
447:                                 /* 4*/ 0,
448:                                        0,
449:                                        0,
450:                                        0,
451:                                        0,
452:                                        0,
453:                                 /*10*/ 0,
454:                                        0,
455:                                        0,
456:                                        0,
457:                                        0,
458:                                 /*15*/ 0,
459:                                        0,
460:                                        0,
461:                                        MatDiagonalScale_Shell,
462:                                        0,
463:                                 /*20*/ 0,
464:                                        MatAssemblyEnd_Shell,
465:                                        0,
466:                                        0,
467:                                 /*24*/ 0,
468:                                        0,
469:                                        0,
470:                                        0,
471:                                        0,
472:                                 /*29*/ 0,
473:                                        0,
474:                                        0,
475:                                        0,
476:                                        0,
477:                                 /*34*/ 0,
478:                                        0,
479:                                        0,
480:                                        0,
481:                                        0,
482:                                 /*39*/ 0,
483:                                        0,
484:                                        0,
485:                                        0,
486:                                        0,
487:                                 /*44*/ 0,
488:                                        MatScale_Shell,
489:                                        MatShift_Shell,
490:                                        0,
491:                                        0,
492:                                 /*49*/ 0,
493:                                        0,
494:                                        0,
495:                                        0,
496:                                        0,
497:                                 /*54*/ 0,
498:                                        0,
499:                                        0,
500:                                        0,
501:                                        0,
502:                                 /*59*/ 0,
503:                                        MatDestroy_Shell,
504:                                        0,
505:                                        0,
506:                                        0,
507:                                 /*64*/ 0,
508:                                        0,
509:                                        0,
510:                                        0,
511:                                        0,
512:                                 /*69*/ 0,
513:                                        0,
514:                                        MatConvert_Shell,
515:                                        0,
516:                                        0,
517:                                 /*74*/ 0,
518:                                        0,
519:                                        0,
520:                                        0,
521:                                        0,
522:                                 /*79*/ 0,
523:                                        0,
524:                                        0,
525:                                        0,
526:                                        0,
527:                                 /*84*/ 0,
528:                                        0,
529:                                        0,
530:                                        0,
531:                                        0,
532:                                 /*89*/ 0,
533:                                        0,
534:                                        0,
535:                                        0,
536:                                        0,
537:                                 /*94*/ 0,
538:                                        0,
539:                                        0,
540:                                        0,
541:                                        0,
542:                                 /*99*/ 0,
543:                                        0,
544:                                        0,
545:                                        0,
546:                                        0,
547:                                /*104*/ 0,
548:                                        0,
549:                                        0,
550:                                        0,
551:                                        0,
552:                                /*109*/ 0,
553:                                        0,
554:                                        0,
555:                                        0,
556:                                        MatMissingDiagonal_Shell,
557:                                /*114*/ 0,
558:                                        0,
559:                                        0,
560:                                        0,
561:                                        0,
562:                                /*119*/ 0,
563:                                        0,
564:                                        0,
565:                                        0,
566:                                        0,
567:                                /*124*/ 0,
568:                                        0,
569:                                        0,
570:                                        0,
571:                                        0,
572:                                /*129*/ 0,
573:                                        0,
574:                                        0,
575:                                        0,
576:                                        0,
577:                                /*134*/ 0,
578:                                        0,
579:                                        0,
580:                                        0,
581:                                        0,
582:                                /*139*/ 0,
583:                                        0,
584:                                        0
585: };

587: /*MC
588:    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.

590:   Level: advanced

592: .seealso: MatCreateShell
593: M*/

597: PETSC_EXTERN PetscErrorCode MatCreate_Shell(Mat A)
598: {
599:   Mat_Shell      *b;

603:   PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));

605:   PetscNewLog(A,&b);
606:   A->data = (void*)b;

608:   PetscLayoutSetUp(A->rmap);
609:   PetscLayoutSetUp(A->cmap);

611:   b->ctx           = 0;
612:   b->vshift        = 0.0;
613:   b->vscale        = 1.0;
614:   b->mult          = 0;
615:   b->multtranspose = 0;
616:   b->getdiagonal   = 0;
617:   A->assembled     = PETSC_TRUE;
618:   A->preallocated  = PETSC_FALSE;

620:   PetscObjectChangeTypeName((PetscObject)A,MATSHELL);
621:   return(0);
622: }

626: /*@C
627:    MatCreateShell - Creates a new matrix class for use with a user-defined
628:    private data storage format.

630:   Collective on MPI_Comm

632:    Input Parameters:
633: +  comm - MPI communicator
634: .  m - number of local rows (must be given)
635: .  n - number of local columns (must be given)
636: .  M - number of global rows (may be PETSC_DETERMINE)
637: .  N - number of global columns (may be PETSC_DETERMINE)
638: -  ctx - pointer to data needed by the shell matrix routines

640:    Output Parameter:
641: .  A - the matrix

643:    Level: advanced

645:   Usage:
646: $    extern int mult(Mat,Vec,Vec);
647: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
648: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
649: $    [ Use matrix for operations that have been set ]
650: $    MatDestroy(mat);

652:    Notes:
653:    The shell matrix type is intended to provide a simple class to use
654:    with KSP (such as, for use with matrix-free methods). You should not
655:    use the shell type if you plan to define a complete matrix class.

657:    Fortran Notes: To use this from Fortran with a ctx you must write an interface definition for this
658:     function and for MatShellGetContext() that tells Fortran the Fortran derived data type you are passing
659:     in as the ctx argument.

661:    PETSc requires that matrices and vectors being used for certain
662:    operations are partitioned accordingly.  For example, when
663:    creating a shell matrix, A, that supports parallel matrix-vector
664:    products using MatMult(A,x,y) the user should set the number
665:    of local matrix rows to be the number of local elements of the
666:    corresponding result vector, y. Note that this is information is
667:    required for use of the matrix interface routines, even though
668:    the shell matrix may not actually be physically partitioned.
669:    For example,

671: $
672: $     Vec x, y
673: $     extern int mult(Mat,Vec,Vec);
674: $     Mat A
675: $
676: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
677: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
678: $     VecGetLocalSize(y,&m);
679: $     VecGetLocalSize(x,&n);
680: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
681: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
682: $     MatMult(A,x,y);
683: $     MatDestroy(A);
684: $     VecDestroy(y); VecDestroy(x);
685: $

687: .keywords: matrix, shell, create

689: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
690: @*/
691: PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
692: {

696:   MatCreate(comm,A);
697:   MatSetSizes(*A,m,n,M,N);
698:   MatSetType(*A,MATSHELL);
699:   MatShellSetContext(*A,ctx);
700:   MatSetUp(*A);
701:   return(0);
702: }

706: /*@
707:     MatShellSetContext - sets the context for a shell matrix

709:    Logically Collective on Mat

711:     Input Parameters:
712: +   mat - the shell matrix
713: -   ctx - the context

715:    Level: advanced

717:    Fortran Notes: To use this from Fortran you must write a Fortran interface definition for this
718:     function that tells Fortran the Fortran derived data type that you are passing in as the ctx argument.

720: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
721: @*/
722: PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
723: {
724:   Mat_Shell      *shell = (Mat_Shell*)mat->data;
726:   PetscBool      flg;

730:   PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);
731:   if (flg) {
732:     shell->ctx = ctx;
733:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot attach context to non-shell matrix");
734:   return(0);
735: }

739: /*@C
740:     MatShellSetOperation - Allows user to set a matrix operation for
741:                            a shell matrix.

743:    Logically Collective on Mat

745:     Input Parameters:
746: +   mat - the shell matrix
747: .   op - the name of the operation
748: -   f - the function that provides the operation.

750:    Level: advanced

752:     Usage:
753: $      extern PetscErrorCode usermult(Mat,Vec,Vec);
754: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
755: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

757:     Notes:
758:     See the file include/petscmat.h for a complete list of matrix
759:     operations, which all have the form MATOP_<OPERATION>, where
760:     <OPERATION> is the name (in all capital letters) of the
761:     user interface routine (e.g., MatMult() -> MATOP_MULT).

763:     All user-provided functions (execept for MATOP_DESTROY) should have the same calling
764:     sequence as the usual matrix interface routines, since they
765:     are intended to be accessed via the usual matrix interface
766:     routines, e.g.,
767: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

769:     In particular each function MUST return an error code of 0 on success and
770:     nonzero on failure.

772:     Within each user-defined routine, the user should call
773:     MatShellGetContext() to obtain the user-defined context that was
774:     set by MatCreateShell().

776:     Fortran Notes: For MatCreateVecs() the user code should check if the input left or right matrix is -1 and in that case not
777:        generate a matrix. See src/mat/examples/tests/ex120f.F

779: .keywords: matrix, shell, set, operation

781: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
782: @*/
783: PetscErrorCode  MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
784: {
786:   PetscBool      flg;

790:   switch (op) {
791:   case MATOP_DESTROY:
792:     PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);
793:     if (flg) {
794:       Mat_Shell *shell = (Mat_Shell*)mat->data;
795:       shell->destroy = (PetscErrorCode (*)(Mat))f;
796:     } else mat->ops->destroy = (PetscErrorCode (*)(Mat))f;
797:     break;
798:   case MATOP_VIEW:
799:     mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer))f;
800:     break;
801:   case MATOP_MULT:
802:     mat->ops->mult = (PetscErrorCode (*)(Mat,Vec,Vec))f;
803:     if (!mat->ops->multadd) mat->ops->multadd = MatMultAdd_Shell;
804:     break;
805:   case MATOP_MULT_TRANSPOSE:
806:     mat->ops->multtranspose = (PetscErrorCode (*)(Mat,Vec,Vec))f;
807:     if (!mat->ops->multtransposeadd) mat->ops->multtransposeadd = MatMultTransposeAdd_Shell;
808:     break;
809:   default:
810:     (((void(**)(void))mat->ops)[op]) = f;
811:   }
812:   return(0);
813: }

817: /*@C
818:     MatShellGetOperation - Gets a matrix function for a shell matrix.

820:     Not Collective

822:     Input Parameters:
823: +   mat - the shell matrix
824: -   op - the name of the operation

826:     Output Parameter:
827: .   f - the function that provides the operation.

829:     Level: advanced

831:     Notes:
832:     See the file include/petscmat.h for a complete list of matrix
833:     operations, which all have the form MATOP_<OPERATION>, where
834:     <OPERATION> is the name (in all capital letters) of the
835:     user interface routine (e.g., MatMult() -> MATOP_MULT).

837:     All user-provided functions have the same calling
838:     sequence as the usual matrix interface routines, since they
839:     are intended to be accessed via the usual matrix interface
840:     routines, e.g.,
841: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

843:     Within each user-defined routine, the user should call
844:     MatShellGetContext() to obtain the user-defined context that was
845:     set by MatCreateShell().

847: .keywords: matrix, shell, set, operation

849: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
850: @*/
851: PetscErrorCode  MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
852: {
854:   PetscBool      flg;

858:   if (op == MATOP_DESTROY) {
859:     PetscObjectTypeCompare((PetscObject)mat,MATSHELL,&flg);
860:     if (flg) {
861:       Mat_Shell *shell = (Mat_Shell*)mat->data;
862:       *f = (void (*)(void))shell->destroy;
863:     } else {
864:       *f = (void (*)(void))mat->ops->destroy;
865:     }
866:   } else if (op == MATOP_VIEW) {
867:     *f = (void (*)(void))mat->ops->view;
868:   } else {
869:     *f = (((void (**)(void))mat->ops)[op]);
870:   }
871:   return(0);
872: }