Actual source code: shell.c

  1: /*$Id: shell.c,v 1.86 2001/03/28 19:41:21 balay 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"        /*I "petscmat.h" I*/
 10: #include "src/vec/vecimpl.h"  

 12: typedef struct {
 13:   int  (*destroy)(Mat);
 14:   void *ctx;
 15: } Mat_Shell;

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

 20:     Not Collective

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

 25:     Output Parameter:
 26: .   ctx - the user provided context

 28:     Level: advanced

 30:     Notes:
 31:     This routine is intended for use within various shell matrix routines,
 32:     as set with MatShellSetOperation().
 33:     
 34: .keywords: matrix, shell, get, context

 36: .seealso: MatCreateShell(), MatShellSetOperation()
 37: @*/
 38: int MatShellGetContext(Mat mat,void **ctx)
 39: {
 40:   int        ierr;
 41:   PetscTruth flg;

 45:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
 46:   if (!flg) *ctx = 0;
 47:   else      *ctx = ((Mat_Shell*)(mat->data))->ctx;
 48:   return(0);
 49: }

 51: int MatDestroy_Shell(Mat mat)
 52: {
 53:   int       ierr;
 54:   Mat_Shell *shell;

 57:   shell = (Mat_Shell*)mat->data;
 58:   if (shell->destroy) {(*shell->destroy)(mat);}
 59:   PetscFree(shell);
 60:   return(0);
 61: }

 63: int MatGetOwnershipRange_Shell(Mat mat,int *rstart,int *rend)
 64: {
 65:   int ierr,tmp;

 68:   MPI_Scan(&mat->m,&tmp,1,MPI_INT,MPI_SUM,mat->comm);
 69:   if (rstart) *rstart = tmp - mat->m;
 70:   if (rend)   *rend   = tmp;
 71:   return(0);
 72: }
 73: extern int MatConvert_Shell(Mat,MatType,Mat*);

 75: static struct _MatOps MatOps_Values = {0,
 76:        0,
 77:        0,
 78:        0,
 79:        0,
 80:        0,
 81:        0,
 82:        0,
 83:        0,
 84:        0,
 85:        0,
 86:        0,
 87:        0,
 88:        0,
 89:        0,
 90:        0,
 91:        0,
 92:        0,
 93:        0,
 94:        0,
 95:        0,
 96:        0,
 97:        0,
 98:        0,
 99:        0,
100:        0,
101:        0,
102:        0,
103:        0,
104:        0,
105:        0,
106:        MatGetOwnershipRange_Shell,
107:        0,
108:        0,
109:        0,
110:        0,
111:        0,
112:        0,
113:        0,
114:        0,
115:        0,
116:        0,
117:        0,
118:        0,
119:        0,
120:        0,
121:        0,
122:        0,
123:        0,
124:        0,
125:        0,
126:        0,
127:        0,
128:        0,
129:        0,
130:        0,
131:        0,
132:        0,
133:        0,
134:        0,
135:        0,
136:        0,
137:        0,
138:        MatDestroy_Shell,
139:        0,
140:        MatGetMaps_Petsc,
141:        0,
142:        0,
143:        0,
144:        0,
145:        0,
146:        0,
147:        0,
148:        MatConvert_Shell};

150: EXTERN_C_BEGIN
151: int MatCreate_Shell(Mat A)
152: {
153:   Mat_Shell *b;
154:   int       ierr;

157:   ierr            = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));

159:   PetscNew(Mat_Shell,&b);
160:   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
161:   ierr    = PetscMemzero(b,sizeof(Mat_Shell));
162:   A->data = (void*)b;

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

168:   PetscSplitOwnership(A->comm,&A->m,&A->M);
169:   PetscSplitOwnership(A->comm,&A->n,&A->N);

171:   MapCreateMPI(A->comm,A->m,A->M,&A->rmap);
172:   MapCreateMPI(A->comm,A->n,A->N,&A->cmap);

174:   b->ctx = 0;
175:   A->assembled    = PETSC_TRUE;
176:   A->preallocated = PETSC_TRUE;
177:   return(0);
178: }
179: EXTERN_C_END

181: /*@C
182:    MatCreateShell - Creates a new matrix class for use with a user-defined
183:    private data storage format. 

185:   Collective on MPI_Comm

187:    Input Parameters:
188: +  comm - MPI communicator
189: .  m - number of local rows (must be given)
190: .  n - number of local columns (must be given)
191: .  M - number of global rows (may be PETSC_DETERMINE)
192: .  N - number of global columns (may be PETSC_DETERMINE)
193: -  ctx - pointer to data needed by the shell matrix routines

195:    Output Parameter:
196: .  A - the matrix

198:    Level: advanced

200:   Usage:
201: $    extern int mult(Mat,Vec,Vec);
202: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
203: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)())mult);
204: $    [ Use matrix for operations that have been set ]
205: $    MatDestroy(mat);

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

212:    PETSc requires that matrices and vectors being used for certain
213:    operations are partitioned accordingly.  For example, when
214:    creating a shell matrix, A, that supports parallel matrix-vector
215:    products using MatMult(A,x,y) the user should set the number
216:    of local matrix rows to be the number of local elements of the
217:    corresponding result vector, y. Note that this is information is
218:    required for use of the matrix interface routines, even though
219:    the shell matrix may not actually be physically partitioned.
220:    For example,

222: $
223: $     Vec x, y
224: $     extern int mult(Mat,Vec,Vec);
225: $     Mat A
226: $
227: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
228: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
229: $     VecGetLocalSize(y,&m);
230: $     VecGetLocalSize(x,&n);
231: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
232: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)())mult);
233: $     MatMult(A,x,y);
234: $     MatDestroy(A);
235: $     VecDestroy(y); VecDestroy(x);
236: $

238: .keywords: matrix, shell, create

240: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
241: @*/
242: int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
243: {
244:   int       ierr;

247:   MatCreate(comm,m,n,M,N,A);
248:   MatSetType(*A,MATSHELL);
249:   MatShellSetContext(*A,ctx);
250:   return(0);
251: }

253: /*@C
254:     MatShellSetContext - sets the context for a shell matrix

256:    Collective on Mat

258:     Input Parameters:
259: +   mat - the shell matrix
260: -   ctx - the context

262:    Level: advanced


265: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
266: @*/
267: int MatShellSetContext(Mat mat,void *ctx)
268: {
269:   Mat_Shell  *shell = (Mat_Shell*)mat->data;
270:   int        ierr;
271:   PetscTruth flg;

275:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
276:   if (flg) {
277:     shell->ctx = ctx;
278:   }
279:   return(0);
280: }

282: /*@C
283:     MatShellSetOperation - Allows user to set a matrix operation for
284:                            a shell matrix.

286:    Collective on Mat

288:     Input Parameters:
289: +   mat - the shell matrix
290: .   op - the name of the operation
291: -   f - the function that provides the operation.

293:    Level: advanced

295:     Usage:
296: $      extern int usermult(Mat,Vec,Vec);
297: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
298: $      MatShellSetOperation(A,MATOP_MULT,(void(*)())usermult);

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

306:     All user-provided functions should have the same calling
307:     sequence as the usual matrix interface routines, since they
308:     are intended to be accessed via the usual matrix interface
309:     routines, e.g., 
310: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

312:     Within each user-defined routine, the user should call
313:     MatShellGetContext() to obtain the user-defined context that was
314:     set by MatCreateShell().

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

318: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
319: @*/
320: int MatShellSetOperation(Mat mat,MatOperation op,void (*f)())
321: {
322:   int        ierr;
323:   PetscTruth flg;

327:   if (op == MATOP_DESTROY) {
328:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
329:     if (flg) {
330:        Mat_Shell *shell = (Mat_Shell*)mat->data;
331:        shell->destroy                 = (int (*)(Mat)) f;
332:     } else mat->ops->destroy            = (int (*)(Mat)) f;
333:   }
334:   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,PetscViewer)) f;
335:   else                       (((void(**)())mat->ops)[op]) = f;

337:   return(0);
338: }

340: /*@C
341:     MatShellGetOperation - Gets a matrix function for a shell matrix.

343:     Not Collective

345:     Input Parameters:
346: +   mat - the shell matrix
347: -   op - the name of the operation

349:     Output Parameter:
350: .   f - the function that provides the operation.

352:     Level: advanced

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

360:     All user-provided functions have the same calling
361:     sequence as the usual matrix interface routines, since they
362:     are intended to be accessed via the usual matrix interface
363:     routines, e.g., 
364: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

366:     Within each user-defined routine, the user should call
367:     MatShellGetContext() to obtain the user-defined context that was
368:     set by MatCreateShell().

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

372: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation()
373: @*/
374: int MatShellGetOperation(Mat mat,MatOperation op,void(**f)())
375: {
376:   int        ierr;
377:   PetscTruth flg;

381:   if (op == MATOP_DESTROY) {
382:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
383:     if (flg) {
384:       Mat_Shell *shell = (Mat_Shell*)mat->data;
385:       *f = (void(*)())shell->destroy;
386:     } else {
387:       *f = (void(*)())mat->ops->destroy;
388:     }
389:   } else if (op == MATOP_VIEW) {
390:     *f = (void(*)())mat->ops->view;
391:   } else {
392:     *f = (((void(**)())mat->ops)[op]);
393:   }

395:   return(0);
396: }