Actual source code: shell.c

  1: /*$Id: shell.c,v 1.88 2001/09/07 20:09:41 bsmith Exp $*/

  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 vecimpl.h

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

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

 25:     Not Collective

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

 30:     Output Parameter:
 31: .   ctx - the user provided context

 33:     Level: advanced

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

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

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

 59: int MatDestroy_Shell(Mat mat)
 60: {
 61:   int       ierr;
 62:   Mat_Shell *shell;

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

 73: int MatMult_Shell(Mat A,Vec x,Vec y)
 74: {
 75:   Mat_Shell   *shell = (Mat_Shell*)A->data;
 76:   int         ierr;

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

 92: int MatShift_Shell(const PetscScalar *a,Mat Y)
 93: {
 94:   Mat_Shell *shell = (Mat_Shell*)Y->data;
 96:   if (shell->scale || shell->shift) {
 97:     shell->vshift += *a;
 98:   } else {
 99:     shell->mult   = Y->ops->mult;
100:     Y->ops->mult  = MatMult_Shell;
101:     shell->vshift = *a;
102:   }
103:   shell->shift  =  PETSC_TRUE;
104:   return(0);
105: }

109: int MatScale_Shell(const PetscScalar *a,Mat Y)
110: {
111:   Mat_Shell *shell = (Mat_Shell*)Y->data;
113:   if (shell->scale || shell->shift) {
114:     shell->vscale *= *a;
115:   } else {
116:     shell->mult   = Y->ops->mult;
117:     Y->ops->mult  = MatMult_Shell;
118:     shell->vscale = *a;
119:   }
120:   shell->scale  =  PETSC_TRUE;
121:   return(0);
122: }

126: int MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
127: {
128:   Mat_Shell *shell = (Mat_Shell*)Y->data;

131:   if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
132:     shell->scale  = PETSC_FALSE;
133:     shell->shift  = PETSC_FALSE;
134:     shell->vshift = 0.0;
135:     shell->vscale = 1.0;
136:     Y->ops->mult  = shell->mult;
137:   }
138:   return(0);
139: }

141: extern int MatConvert_Shell(Mat,const MatType,Mat*);

143: static struct _MatOps MatOps_Values = {0,
144:        0,
145:        0,
146:        0,
147: /* 4*/ 0,
148:        0,
149:        0,
150:        0,
151:        0,
152:        0,
153: /*10*/ 0,
154:        0,
155:        0,
156:        0,
157:        0,
158: /*15*/ 0,
159:        0,
160:        0,
161:        0,
162:        0,
163: /*20*/ 0,
164:        MatAssemblyEnd_Shell,
165:        0,
166:        0,
167:        0,
168: /*25*/ 0,
169:        0,
170:        0,
171:        0,
172:        0,
173: /*30*/ 0,
174:        0,
175:        0,
176:        0,
177:        0,
178: /*35*/ 0,
179:        0,
180:        0,
181:        0,
182:        0,
183: /*40*/ 0,
184:        0,
185:        0,
186:        0,
187:        0,
188: /*45*/ 0,
189:        MatScale_Shell,
190:        MatShift_Shell,
191:        0,
192:        0,
193: /*50*/ 0,
194:        0,
195:        0,
196:        0,
197:        0,
198: /*55*/ 0,
199:        0,
200:        0,
201:        0,
202:        0,
203: /*60*/ 0,
204:        MatDestroy_Shell,
205:        0,
206:        MatGetPetscMaps_Petsc,
207:        0,
208: /*65*/ 0,
209:        0,
210:        0,
211:        0,
212:        0,
213: /*70*/ 0,
214:        MatConvert_Shell,
215:        0,
216:        0,
217:        0,
218: /*75*/ 0,
219:        0,
220:        0,
221:        0,
222:        0,
223: /*80*/ 0,
224:        0,
225:        0,
226:        0,
227: /*85*/ 0
228: };

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

233:   Level: advanced

235: .seealso: MatCreateShell
236: M*/

238: EXTERN_C_BEGIN
241: int MatCreate_Shell(Mat A)
242: {
243:   Mat_Shell *b;
244:   int       ierr;

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

249:   PetscNew(Mat_Shell,&b);
250:   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
251:   PetscMemzero(b,sizeof(Mat_Shell));
252:   A->data = (void*)b;

254:   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
255:     SETERRQ(1,"Must give local row and column count for matrix");
256:   }

258:   PetscSplitOwnership(A->comm,&A->m,&A->M);
259:   PetscSplitOwnership(A->comm,&A->n,&A->N);

261:   PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);
262:   PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);

264:   b->ctx          = 0;
265:   b->scale        = PETSC_FALSE;
266:   b->shift        = PETSC_FALSE;
267:   b->vshift       = 0.0;
268:   b->vscale       = 1.0;
269:   b->mult         = 0;
270:   A->assembled    = PETSC_TRUE;
271:   A->preallocated = PETSC_TRUE;
272:   return(0);
273: }
274: EXTERN_C_END

278: /*@C
279:    MatCreateShell - Creates a new matrix class for use with a user-defined
280:    private data storage format. 

282:   Collective on MPI_Comm

284:    Input Parameters:
285: +  comm - MPI communicator
286: .  m - number of local rows (must be given)
287: .  n - number of local columns (must be given)
288: .  M - number of global rows (may be PETSC_DETERMINE)
289: .  N - number of global columns (may be PETSC_DETERMINE)
290: -  ctx - pointer to data needed by the shell matrix routines

292:    Output Parameter:
293: .  A - the matrix

295:    Level: advanced

297:   Usage:
298: $    extern int mult(Mat,Vec,Vec);
299: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
300: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
301: $    [ Use matrix for operations that have been set ]
302: $    MatDestroy(mat);

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

309:    PETSc requires that matrices and vectors being used for certain
310:    operations are partitioned accordingly.  For example, when
311:    creating a shell matrix, A, that supports parallel matrix-vector
312:    products using MatMult(A,x,y) the user should set the number
313:    of local matrix rows to be the number of local elements of the
314:    corresponding result vector, y. Note that this is information is
315:    required for use of the matrix interface routines, even though
316:    the shell matrix may not actually be physically partitioned.
317:    For example,

319: $
320: $     Vec x, y
321: $     extern int mult(Mat,Vec,Vec);
322: $     Mat A
323: $
324: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
325: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
326: $     VecGetLocalSize(y,&m);
327: $     VecGetLocalSize(x,&n);
328: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
329: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
330: $     MatMult(A,x,y);
331: $     MatDestroy(A);
332: $     VecDestroy(y); VecDestroy(x);
333: $

335: .keywords: matrix, shell, create

337: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
338: @*/
339: int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
340: {
341:   int       ierr;

344:   MatCreate(comm,m,n,M,N,A);
345:   MatSetType(*A,MATSHELL);
346:   MatShellSetContext(*A,ctx);
347:   return(0);
348: }

352: /*@C
353:     MatShellSetContext - sets the context for a shell matrix

355:    Collective on Mat

357:     Input Parameters:
358: +   mat - the shell matrix
359: -   ctx - the context

361:    Level: advanced


364: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
365: @*/
366: int MatShellSetContext(Mat mat,void *ctx)
367: {
368:   Mat_Shell  *shell = (Mat_Shell*)mat->data;
369:   int        ierr;
370:   PetscTruth flg;

374:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
375:   if (flg) {
376:     shell->ctx = ctx;
377:   }
378:   return(0);
379: }

383: /*@C
384:     MatShellSetOperation - Allows user to set a matrix operation for
385:                            a shell matrix.

387:    Collective on Mat

389:     Input Parameters:
390: +   mat - the shell matrix
391: .   op - the name of the operation
392: -   f - the function that provides the operation.

394:    Level: advanced

396:     Usage:
397: $      extern int usermult(Mat,Vec,Vec);
398: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
399: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

407:     All user-provided functions should have the same calling
408:     sequence as the usual matrix interface routines, since they
409:     are intended to be accessed via the usual matrix interface
410:     routines, e.g., 
411: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

413:     Within each user-defined routine, the user should call
414:     MatShellGetContext() to obtain the user-defined context that was
415:     set by MatCreateShell().

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

419: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
420: @*/
421: int MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
422: {
423:   int        ierr;
424:   PetscTruth flg;

428:   if (op == MATOP_DESTROY) {
429:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
430:     if (flg) {
431:        Mat_Shell *shell = (Mat_Shell*)mat->data;
432:        shell->destroy                 = (int (*)(Mat)) f;
433:     } else mat->ops->destroy            = (int (*)(Mat)) f;
434:   }
435:   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,PetscViewer)) f;
436:   else                       (((void(**)(void))mat->ops)[op]) = f;

438:   return(0);
439: }

443: /*@C
444:     MatShellGetOperation - Gets a matrix function for a shell matrix.

446:     Not Collective

448:     Input Parameters:
449: +   mat - the shell matrix
450: -   op - the name of the operation

452:     Output Parameter:
453: .   f - the function that provides the operation.

455:     Level: advanced

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

463:     All user-provided functions have the same calling
464:     sequence as the usual matrix interface routines, since they
465:     are intended to be accessed via the usual matrix interface
466:     routines, e.g., 
467: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

469:     Within each user-defined routine, the user should call
470:     MatShellGetContext() to obtain the user-defined context that was
471:     set by MatCreateShell().

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

475: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
476: @*/
477: int MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
478: {
479:   int        ierr;
480:   PetscTruth flg;

484:   if (op == MATOP_DESTROY) {
485:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
486:     if (flg) {
487:       Mat_Shell *shell = (Mat_Shell*)mat->data;
488:       *f = (void(*)(void))shell->destroy;
489:     } else {
490:       *f = (void(*)(void))mat->ops->destroy;
491:     }
492:   } else if (op == MATOP_VIEW) {
493:     *f = (void(*)(void))mat->ops->view;
494:   } else {
495:     *f = (((void(**)(void))mat->ops)[op]);
496:   }

498:   return(0);
499: }