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 src/mat/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: /*@
 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 PETSCMAT_DLLEXPORT 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, MatType,MatReuse,Mat*);

204: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
205: {
207:   return(0);
208: }

210: static struct _MatOps MatOps_Values = {0,
211:        0,
212:        0,
213:        0,
214: /* 4*/ 0,
215:        0,
216:        0,
217:        0,
218:        0,
219:        0,
220: /*10*/ 0,
221:        0,
222:        0,
223:        0,
224:        0,
225: /*15*/ 0,
226:        0,
227:        0,
228:        0,
229:        0,
230: /*20*/ 0,
231:        MatAssemblyEnd_Shell,
232:        0,
233:        0,
234:        0,
235: /*25*/ 0,
236:        0,
237:        0,
238:        0,
239:        0,
240: /*30*/ 0,
241:        0,
242:        0,
243:        0,
244:        0,
245: /*35*/ 0,
246:        0,
247:        0,
248:        0,
249:        0,
250: /*40*/ 0,
251:        0,
252:        0,
253:        0,
254:        0,
255: /*45*/ 0,
256:        MatScale_Shell,
257:        MatShift_Shell,
258:        0,
259:        0,
260: /*50*/ MatSetBlockSize_Shell,
261:        0,
262:        0,
263:        0,
264:        0,
265: /*55*/ 0,
266:        0,
267:        0,
268:        0,
269:        0,
270: /*60*/ 0,
271:        MatDestroy_Shell,
272:        0,
273:        0,
274:        0,
275: /*65*/ 0,
276:        0,
277:        0,
278:        0,
279:        0,
280: /*70*/ 0,
281:        MatConvert_Shell,
282:        0,
283:        0,
284:        0,
285: /*75*/ 0,
286:        0,
287:        0,
288:        0,
289:        0,
290: /*80*/ 0,
291:        0,
292:        0,
293:        0,
294:        0,
295: /*85*/ 0,
296:        0,
297:        0,
298:        0,
299:        0,
300: /*90*/ 0,
301:        0,
302:        0,
303:        0,
304:        0,
305: /*95*/ 0,
306:        0,
307:        0,
308:        0};

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

313:   Level: advanced

315: .seealso: MatCreateShell
316: M*/

321: PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Shell(Mat A)
322: {
323:   Mat_Shell      *b;

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

329:   PetscNew(Mat_Shell,&b);
330:   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
331:   A->data = (void*)b;

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

337:   PetscMapInitialize(A->comm,&A->rmap);
338:   PetscMapInitialize(A->comm,&A->cmap);

340:   b->ctx           = 0;
341:   b->scale         = PETSC_FALSE;
342:   b->shift         = PETSC_FALSE;
343:   b->vshift        = 0.0;
344:   b->vscale        = 1.0;
345:   b->mult          = 0;
346:   b->multtranspose = 0;
347:   b->getdiagonal   = 0;
348:   A->assembled     = PETSC_TRUE;
349:   A->preallocated  = PETSC_FALSE;
350:   return(0);
351: }

356: /*@C
357:    MatCreateShell - Creates a new matrix class for use with a user-defined
358:    private data storage format. 

360:   Collective on MPI_Comm

362:    Input Parameters:
363: +  comm - MPI communicator
364: .  m - number of local rows (must be given)
365: .  n - number of local columns (must be given)
366: .  M - number of global rows (may be PETSC_DETERMINE)
367: .  N - number of global columns (may be PETSC_DETERMINE)
368: -  ctx - pointer to data needed by the shell matrix routines

370:    Output Parameter:
371: .  A - the matrix

373:    Level: advanced

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

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

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

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

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

416: .keywords: matrix, shell, create

418: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
419: @*/
420: PetscErrorCode PETSCMAT_DLLEXPORT MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
421: {

425:   MatCreate(comm,A);
426:   MatSetSizes(*A,m,n,M,N);
427: 
428:   MatSetType(*A,MATSHELL);
429:   MatShellSetContext(*A,ctx);
430:   return(0);
431: }

435: /*@
436:     MatShellSetContext - sets the context for a shell matrix

438:    Collective on Mat

440:     Input Parameters:
441: +   mat - the shell matrix
442: -   ctx - the context

444:    Level: advanced

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

449: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
450: @*/
451: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetContext(Mat mat,void *ctx)
452: {
453:   Mat_Shell      *shell = (Mat_Shell*)mat->data;
455:   PetscTruth     flg;

459:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
460:   if (flg) {
461:     shell->ctx = ctx;
462:   }
463:   return(0);
464: }

468: /*@C
469:     MatShellSetOperation - Allows user to set a matrix operation for
470:                            a shell matrix.

472:    Collective on Mat

474:     Input Parameters:
475: +   mat - the shell matrix
476: .   op - the name of the operation
477: -   f - the function that provides the operation.

479:    Level: advanced

481:     Usage:
483: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
484: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

492:     All user-provided functions should have the same calling
493:     sequence as the usual matrix interface routines, since they
494:     are intended to be accessed via the usual matrix interface
495:     routines, e.g., 
496: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

498:     Within each user-defined routine, the user should call
499:     MatShellGetContext() to obtain the user-defined context that was
500:     set by MatCreateShell().

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

504: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
505: @*/
506: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
507: {
509:   PetscTruth     flg;

513:   if (op == MATOP_DESTROY) {
514:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
515:     if (flg) {
516:        Mat_Shell *shell = (Mat_Shell*)mat->data;
517:        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
518:     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
519:   }
520:   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
521:   else                       (((void(**)(void))mat->ops)[op]) = f;

523:   return(0);
524: }

528: /*@C
529:     MatShellGetOperation - Gets a matrix function for a shell matrix.

531:     Not Collective

533:     Input Parameters:
534: +   mat - the shell matrix
535: -   op - the name of the operation

537:     Output Parameter:
538: .   f - the function that provides the operation.

540:     Level: advanced

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

548:     All user-provided functions have the same calling
549:     sequence as the usual matrix interface routines, since they
550:     are intended to be accessed via the usual matrix interface
551:     routines, e.g., 
552: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

554:     Within each user-defined routine, the user should call
555:     MatShellGetContext() to obtain the user-defined context that was
556:     set by MatCreateShell().

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

560: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
561: @*/
562: PetscErrorCode PETSCMAT_DLLEXPORT MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
563: {
565:   PetscTruth     flg;

569:   if (op == MATOP_DESTROY) {
570:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
571:     if (flg) {
572:       Mat_Shell *shell = (Mat_Shell*)mat->data;
573:       *f = (void(*)(void))shell->destroy;
574:     } else {
575:       *f = (void(*)(void))mat->ops->destroy;
576:     }
577:   } else if (op == MATOP_VIEW) {
578:     *f = (void(*)(void))mat->ops->view;
579:   } else {
580:     *f = (((void(**)(void))mat->ops)[op]);
581:   }

583:   return(0);
584: }