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: {
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:        0,
282:        MatConvert_Shell,
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  MatCreate_Shell(Mat A)
322: {
323:   Mat_Shell      *b;

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

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

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

336:   PetscMapSetBlockSize(A->rmap,1);
337:   PetscMapSetBlockSize(A->cmap,1);
338:   PetscMapSetUp(A->rmap);
339:   PetscMapSetUp(A->cmap);

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

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

362:   Collective on MPI_Comm

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

372:    Output Parameter:
373: .  A - the matrix

375:    Level: advanced

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

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

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

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

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

418: .keywords: matrix, shell, create

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

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

437: /*@C
438:     MatShellSetContext - sets the context for a shell matrix

440:    Collective on Mat

442:     Input Parameters:
443: +   mat - the shell matrix
444: -   ctx - the context

446:    Level: advanced

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

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

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

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

474:    Collective on Mat

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

481:    Level: advanced

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

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

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

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

503:     Within each user-defined routine, the user should call
504:     MatShellGetContext() to obtain the user-defined context that was
505:     set by MatCreateShell().

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

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

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

528:   return(0);
529: }

533: /*@C
534:     MatShellGetOperation - Gets a matrix function for a shell matrix.

536:     Not Collective

538:     Input Parameters:
539: +   mat - the shell matrix
540: -   op - the name of the operation

542:     Output Parameter:
543: .   f - the function that provides the operation.

545:     Level: advanced

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

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

559:     Within each user-defined routine, the user should call
560:     MatShellGetContext() to obtain the user-defined context that was
561:     set by MatCreateShell().

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

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

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

588:   return(0);
589: }