Actual source code: shell.c

  1: #define PETSCMAT_DLL

  3: /*
  4:    This provides a simple shell for Fortran (and C programmers) to 
  5:   create a very simple matrix class for use with KSP without coding 
  6:   much of anything.
  7: */

 9:  #include private/matimpl.h
 10:  #include private/vecimpl.h

 12: typedef struct {
 13:   PetscErrorCode (*destroy)(Mat);
 14:   PetscErrorCode (*mult)(Mat,Vec,Vec);
 15:   PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
 16:   PetscErrorCode (*getdiagonal)(Mat,Vec);
 17:   PetscTruth     scale,shift;
 18:   PetscScalar    vscale,vshift;
 19:   void           *ctx;
 20: } Mat_Shell;

 24: /*@C
 25:     MatShellGetContext - Returns the user-provided context associated with a shell matrix.

 27:     Not Collective

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

 32:     Output Parameter:
 33: .   ctx - the user provided context

 35:     Level: advanced

 37:     Notes:
 38:     This routine is intended for use within various shell matrix routines,
 39:     as set with MatShellSetOperation().
 40:     
 41: .keywords: matrix, shell, get, context

 43: .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
 44: @*/
 45: PetscErrorCode  MatShellGetContext(Mat mat,void **ctx)
 46: {
 48:   PetscTruth     flg;

 53:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
 54:   if (!flg) *ctx = 0;
 55:   else      *ctx = ((Mat_Shell*)(mat->data))->ctx;
 56:   return(0);
 57: }

 61: PetscErrorCode MatDestroy_Shell(Mat mat)
 62: {
 64:   Mat_Shell      *shell;

 67:   shell = (Mat_Shell*)mat->data;
 68:   if (shell->destroy) {(*shell->destroy)(mat);}
 69:   PetscFree(shell);
 70:   return(0);
 71: }

 75: PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
 76: {
 77:   Mat_Shell      *shell = (Mat_Shell*)A->data;

 81:   (*shell->mult)(A,x,y);
 82:   if (shell->shift && shell->scale) {
 83:     VecAXPBY(y,shell->vshift,shell->vscale,x);
 84:   } else if (shell->scale) {
 85:     VecScale(y,shell->vscale);
 86:   } else {
 87:     VecAXPY(y,shell->vshift,x);
 88:   }
 89:   return(0);
 90: }

 94: PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
 95: {
 96:   Mat_Shell      *shell = (Mat_Shell*)A->data;

100:   (*shell->multtranspose)(A,x,y);
101:   if (shell->shift && shell->scale) {
102:     VecAXPBY(y,shell->vshift,shell->vscale,x);
103:   } else if (shell->scale) {
104:     VecScale(y,shell->vscale);
105:   } else {
106:     VecAXPY(y,shell->vshift,x);
107:   }
108:   return(0);
109: }

113: PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
114: {
115:   Mat_Shell      *shell = (Mat_Shell*)A->data;

119:   (*shell->getdiagonal)(A,v);
120:   if (shell->scale) {
121:     VecScale(v,shell->vscale);
122:   }
123:   if (shell->shift) {
124:     VecShift(v,shell->vshift);
125:   }
126:   return(0);
127: }

131: PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
132: {
133:   Mat_Shell *shell = (Mat_Shell*)Y->data;

136:   if (shell->scale || shell->shift) {
137:     shell->vshift += a;
138:   } else {
139:     shell->mult  = Y->ops->mult;
140:     Y->ops->mult = MatMult_Shell;
141:     if (Y->ops->multtranspose) {
142:       shell->multtranspose  = Y->ops->multtranspose;
143:       Y->ops->multtranspose = MatMultTranspose_Shell;
144:     }
145:     if (Y->ops->getdiagonal) {
146:       shell->getdiagonal  = Y->ops->getdiagonal;
147:       Y->ops->getdiagonal = MatGetDiagonal_Shell;
148:     }
149:     shell->vshift = a;
150:   }
151:   shell->shift  =  PETSC_TRUE;
152:   return(0);
153: }

157: PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
158: {
159:   Mat_Shell *shell = (Mat_Shell*)Y->data;

162:   if (shell->scale || shell->shift) {
163:     shell->vscale *= a;
164:   } else {
165:     shell->mult  = Y->ops->mult;
166:     Y->ops->mult = MatMult_Shell;
167:     if (Y->ops->multtranspose) {
168:       shell->multtranspose  = Y->ops->multtranspose;
169:       Y->ops->multtranspose = MatMultTranspose_Shell;
170:     }
171:     if (Y->ops->getdiagonal) {
172:       shell->getdiagonal  = Y->ops->getdiagonal;
173:       Y->ops->getdiagonal = MatGetDiagonal_Shell;
174:     }
175:     shell->vscale = a;
176:   }
177:   shell->scale  =  PETSC_TRUE;
178:   return(0);
179: }

183: PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
184: {
185:   Mat_Shell *shell = (Mat_Shell*)Y->data;

188:   if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
189:     shell->scale  = PETSC_FALSE;
190:     shell->shift  = PETSC_FALSE;
191:     shell->vshift = 0.0;
192:     shell->vscale = 1.0;
193:     Y->ops->mult          = shell->mult;
194:     Y->ops->multtranspose = shell->multtranspose;
195:     Y->ops->getdiagonal   = shell->getdiagonal;
196:   }
197:   return(0);
198: }

200: EXTERN PetscErrorCode MatConvert_Shell(Mat, const MatType,MatReuse,Mat*);

204: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
205: {

209:   PetscLayoutSetBlockSize(A->rmap,bs);
210:   PetscLayoutSetBlockSize(A->cmap,bs);
211:   return(0);
212: }

214: static struct _MatOps MatOps_Values = {0,
215:        0,
216:        0,
217:        0,
218: /* 4*/ 0,
219:        0,
220:        0,
221:        0,
222:        0,
223:        0,
224: /*10*/ 0,
225:        0,
226:        0,
227:        0,
228:        0,
229: /*15*/ 0,
230:        0,
231:        0,
232:        0,
233:        0,
234: /*20*/ 0,
235:        MatAssemblyEnd_Shell,
236:        0,
237:        0,
238: /*24*/ 0,
239:        0,
240:        0,
241:        0,
242:        0,
243: /*29*/ 0,
244:        0,
245:        0,
246:        0,
247:        0,
248: /*34*/ 0,
249:        0,
250:        0,
251:        0,
252:        0,
253: /*39*/ 0,
254:        0,
255:        0,
256:        0,
257:        0,
258: /*44*/ 0,
259:        MatScale_Shell,
260:        MatShift_Shell,
261:        0,
262:        0,
263: /*49*/ MatSetBlockSize_Shell,
264:        0,
265:        0,
266:        0,
267:        0,
268: /*54*/ 0,
269:        0,
270:        0,
271:        0,
272:        0,
273: /*59*/ 0,
274:        MatDestroy_Shell,
275:        0,
276:        0,
277:        0,
278: /*64*/ 0,
279:        0,
280:        0,
281:        0,
282:        0,
283: /*69*/ 0,
284:        0,
285:        MatConvert_Shell,
286:        0,
287:        0,
288: /*74*/ 0,
289:        0,
290:        0,
291:        0,
292:        0,
293: /*79*/ 0,
294:        0,
295:        0,
296:        0,
297:        0,
298: /*84*/ 0,
299:        0,
300:        0,
301:        0,
302:        0,
303: /*89*/ 0,
304:        0,
305:        0,
306:        0,
307:        0,
308: /*94*/ 0,
309:        0,
310:        0,
311:        0};

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

316:   Level: advanced

318: .seealso: MatCreateShell
319: M*/

324: PetscErrorCode  MatCreate_Shell(Mat A)
325: {
326:   Mat_Shell      *b;

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

332:   PetscNewLog(A,Mat_Shell,&b);
333:   A->data = (void*)b;

335:   if (A->rmap->n == PETSC_DECIDE || A->cmap->n == PETSC_DECIDE) {
336:     SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
337:   }

339:   PetscLayoutSetBlockSize(A->rmap,1);
340:   PetscLayoutSetBlockSize(A->cmap,1);
341:   PetscLayoutSetUp(A->rmap);
342:   PetscLayoutSetUp(A->cmap);

344:   b->ctx           = 0;
345:   b->scale         = PETSC_FALSE;
346:   b->shift         = PETSC_FALSE;
347:   b->vshift        = 0.0;
348:   b->vscale        = 1.0;
349:   b->mult          = 0;
350:   b->multtranspose = 0;
351:   b->getdiagonal   = 0;
352:   A->assembled     = PETSC_TRUE;
353:   A->preallocated  = PETSC_FALSE;
354:   PetscObjectChangeTypeName((PetscObject)A,MATSHELL);
355:   return(0);
356: }

361: /*@C
362:    MatCreateShell - Creates a new matrix class for use with a user-defined
363:    private data storage format. 

365:   Collective on MPI_Comm

367:    Input Parameters:
368: +  comm - MPI communicator
369: .  m - number of local rows (must be given)
370: .  n - number of local columns (must be given)
371: .  M - number of global rows (may be PETSC_DETERMINE)
372: .  N - number of global columns (may be PETSC_DETERMINE)
373: -  ctx - pointer to data needed by the shell matrix routines

375:    Output Parameter:
376: .  A - the matrix

378:    Level: advanced

380:   Usage:
382: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
383: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
384: $    [ Use matrix for operations that have been set ]
385: $    MatDestroy(mat);

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

392:    Fortran Notes: The context can only be an integer or a PetscObject
393:       unfortunately it cannot be a Fortran array or derived type.

395:    PETSc requires that matrices and vectors being used for certain
396:    operations are partitioned accordingly.  For example, when
397:    creating a shell matrix, A, that supports parallel matrix-vector
398:    products using MatMult(A,x,y) the user should set the number
399:    of local matrix rows to be the number of local elements of the
400:    corresponding result vector, y. Note that this is information is
401:    required for use of the matrix interface routines, even though
402:    the shell matrix may not actually be physically partitioned.
403:    For example,

405: $
406: $     Vec x, y
408: $     Mat A
409: $
410: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
411: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
412: $     VecGetLocalSize(y,&m);
413: $     VecGetLocalSize(x,&n);
414: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
415: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
416: $     MatMult(A,x,y);
417: $     MatDestroy(A);
418: $     VecDestroy(y); VecDestroy(x);
419: $

421: .keywords: matrix, shell, create

423: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
424: @*/
425: PetscErrorCode  MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
426: {

430:   MatCreate(comm,A);
431:   MatSetSizes(*A,m,n,M,N);
432: 
433:   MatSetType(*A,MATSHELL);
434:   MatShellSetContext(*A,ctx);
435:   return(0);
436: }

440: /*@
441:     MatShellSetContext - sets the context for a shell matrix

443:    Collective on Mat

445:     Input Parameters:
446: +   mat - the shell matrix
447: -   ctx - the context

449:    Level: advanced

451:    Fortran Notes: The context can only be an integer or a PetscObject
452:       unfortunately it cannot be a Fortran array or derived type.

454: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
455: @*/
456: PetscErrorCode  MatShellSetContext(Mat mat,void *ctx)
457: {
458:   Mat_Shell      *shell = (Mat_Shell*)mat->data;
460:   PetscTruth     flg;

464:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
465:   if (flg) {
466:     shell->ctx = ctx;
467:   }
468:   return(0);
469: }

473: /*@C
474:     MatShellSetOperation - Allows user to set a matrix operation for
475:                            a shell matrix.

477:    Collective on Mat

479:     Input Parameters:
480: +   mat - the shell matrix
481: .   op - the name of the operation
482: -   f - the function that provides the operation.

484:    Level: advanced

486:     Usage:
488: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
489: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

497:     All user-provided functions should have the same calling
498:     sequence as the usual matrix interface routines, since they
499:     are intended to be accessed via the usual matrix interface
500:     routines, e.g., 
501: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

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

506:     Within each user-defined routine, the user should call
507:     MatShellGetContext() to obtain the user-defined context that was
508:     set by MatCreateShell().

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

512: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
513: @*/
514: PetscErrorCode  MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
515: {
517:   PetscTruth     flg;

521:   if (op == MATOP_DESTROY) {
522:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
523:     if (flg) {
524:        Mat_Shell *shell = (Mat_Shell*)mat->data;
525:        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
526:     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
527:   }
528:   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
529:   else                       (((void(**)(void))mat->ops)[op]) = f;

531:   return(0);
532: }

536: /*@C
537:     MatShellGetOperation - Gets a matrix function for a shell matrix.

539:     Not Collective

541:     Input Parameters:
542: +   mat - the shell matrix
543: -   op - the name of the operation

545:     Output Parameter:
546: .   f - the function that provides the operation.

548:     Level: advanced

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

556:     All user-provided functions have the same calling
557:     sequence as the usual matrix interface routines, since they
558:     are intended to be accessed via the usual matrix interface
559:     routines, e.g., 
560: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

562:     Within each user-defined routine, the user should call
563:     MatShellGetContext() to obtain the user-defined context that was
564:     set by MatCreateShell().

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

568: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
569: @*/
570: PetscErrorCode  MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
571: {
573:   PetscTruth     flg;

577:   if (op == MATOP_DESTROY) {
578:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
579:     if (flg) {
580:       Mat_Shell *shell = (Mat_Shell*)mat->data;
581:       *f = (void(*)(void))shell->destroy;
582:     } else {
583:       *f = (void(*)(void))mat->ops->destroy;
584:     }
585:   } else if (op == MATOP_VIEW) {
586:     *f = (void(*)(void))mat->ops->view;
587:   } else {
588:     *f = (((void(**)(void))mat->ops)[op]);
589:   }

591:   return(0);
592: }