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 src/vec/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;

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

 23:     Not Collective

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

 28:     Output Parameter:
 29: .   ctx - the user provided context

 31:     Level: advanced

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

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

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

 54: int MatDestroy_Shell(Mat mat)
 55: {
 56:   int       ierr;
 57:   Mat_Shell *shell;

 60:   shell = (Mat_Shell*)mat->data;
 61:   if (shell->destroy) {(*shell->destroy)(mat);}
 62:   PetscFree(shell);
 63:   return(0);
 64: }

 66: int MatMult_Shell(Mat A,Vec x,Vec y)
 67: {
 68:   Mat_Shell   *shell = (Mat_Shell*)A->data;
 69:   int         ierr;

 72:   (*shell->mult)(A,x,y);
 73:   if (shell->shift && shell->scale) {
 74:     VecAXPBY(&shell->vshift,&shell->vscale,x,y);
 75:   } else if (shell->scale) {
 76:     VecScale(&shell->vscale,y);
 77:   } else {
 78:     VecAXPY(&shell->vshift,x,y);
 79:   }
 80:   return(0);
 81: }

 83: int MatShift_Shell(PetscScalar *a,Mat Y)
 84: {
 85:   Mat_Shell *shell = (Mat_Shell*)Y->data;
 87:   if (shell->scale || shell->shift) {
 88:     shell->vshift += *a;
 89:   } else {
 90:     shell->mult   = Y->ops->mult;
 91:     Y->ops->mult  = MatMult_Shell;
 92:     shell->vshift = *a;
 93:   }
 94:   shell->shift  =  PETSC_TRUE;
 95:   return(0);
 96: }

 98: int MatScale_Shell(PetscScalar *a,Mat Y)
 99: {
100:   Mat_Shell *shell = (Mat_Shell*)Y->data;
102:   if (shell->scale || shell->shift) {
103:     shell->vscale *= *a;
104:   } else {
105:     shell->mult   = Y->ops->mult;
106:     Y->ops->mult  = MatMult_Shell;
107:     shell->vscale = *a;
108:   }
109:   shell->scale  =  PETSC_TRUE;
110:   return(0);
111: }

113: int MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
114: {
115:   Mat_Shell *shell = (Mat_Shell*)Y->data;

118:   if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
119:     shell->scale  = PETSC_FALSE;
120:     shell->shift  = PETSC_FALSE;
121:     shell->vshift = 0.0;
122:     shell->vscale = 1.0;
123:     Y->ops->mult  = shell->mult;
124:   }
125:   return(0);
126: }

128: extern int MatConvert_Shell(Mat,MatType,Mat*);

130: static struct _MatOps MatOps_Values = {0,
131:        0,
132:        0,
133:        0,
134:        0,
135:        0,
136:        0,
137:        0,
138:        0,
139:        0,
140:        0,
141:        0,
142:        0,
143:        0,
144:        0,
145:        0,
146:        0,
147:        0,
148:        0,
149:        0,
150:        0,
151:        MatAssemblyEnd_Shell,
152:        0,
153:        0,
154:        0,
155:        0,
156:        0,
157:        0,
158:        0,
159:        0,
160:        0,
161:        0,
162:        0,
163:        0,
164:        0,
165:        0,
166:        0,
167:        0,
168:        0,
169:        0,
170:        0,
171:        0,
172:        0,
173:        0,
174:        0,
175:        0,
176:        MatScale_Shell,
177:        MatShift_Shell,
178:        0,
179:        0,
180:        0,
181:        0,
182:        0,
183:        0,
184:        0,
185:        0,
186:        0,
187:        0,
188:        0,
189:        0,
190:        0,
191:        MatDestroy_Shell,
192:        0,
193:        MatGetPetscMaps_Petsc,
194:        0,
195:        0,
196:        0,
197:        0,
198:        0,
199:        0,
200:        0,
201:        MatConvert_Shell};

203: EXTERN_C_BEGIN
204: int MatCreate_Shell(Mat A)
205: {
206:   Mat_Shell *b;
207:   int       ierr;

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

212:   PetscNew(Mat_Shell,&b);
213:   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
214:   ierr    = PetscMemzero(b,sizeof(Mat_Shell));
215:   A->data = (void*)b;

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

221:   PetscSplitOwnership(A->comm,&A->m,&A->M);
222:   PetscSplitOwnership(A->comm,&A->n,&A->N);

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

227:   b->ctx          = 0;
228:   b->scale        = PETSC_FALSE;
229:   b->shift        = PETSC_FALSE;
230:   b->vshift       = 0.0;
231:   b->vscale       = 1.0;
232:   b->mult         = 0;
233:   A->assembled    = PETSC_TRUE;
234:   A->preallocated = PETSC_TRUE;
235:   return(0);
236: }
237: EXTERN_C_END

239: /*@C
240:    MatCreateShell - Creates a new matrix class for use with a user-defined
241:    private data storage format. 

243:   Collective on MPI_Comm

245:    Input Parameters:
246: +  comm - MPI communicator
247: .  m - number of local rows (must be given)
248: .  n - number of local columns (must be given)
249: .  M - number of global rows (may be PETSC_DETERMINE)
250: .  N - number of global columns (may be PETSC_DETERMINE)
251: -  ctx - pointer to data needed by the shell matrix routines

253:    Output Parameter:
254: .  A - the matrix

256:    Level: advanced

258:   Usage:
259: $    extern int mult(Mat,Vec,Vec);
260: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
261: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
262: $    [ Use matrix for operations that have been set ]
263: $    MatDestroy(mat);

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

270:    PETSc requires that matrices and vectors being used for certain
271:    operations are partitioned accordingly.  For example, when
272:    creating a shell matrix, A, that supports parallel matrix-vector
273:    products using MatMult(A,x,y) the user should set the number
274:    of local matrix rows to be the number of local elements of the
275:    corresponding result vector, y. Note that this is information is
276:    required for use of the matrix interface routines, even though
277:    the shell matrix may not actually be physically partitioned.
278:    For example,

280: $
281: $     Vec x, y
282: $     extern int mult(Mat,Vec,Vec);
283: $     Mat A
284: $
285: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
286: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
287: $     VecGetLocalSize(y,&m);
288: $     VecGetLocalSize(x,&n);
289: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
290: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
291: $     MatMult(A,x,y);
292: $     MatDestroy(A);
293: $     VecDestroy(y); VecDestroy(x);
294: $

296: .keywords: matrix, shell, create

298: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
299: @*/
300: int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
301: {
302:   int       ierr;

305:   MatCreate(comm,m,n,M,N,A);
306:   MatSetType(*A,MATSHELL);
307:   MatShellSetContext(*A,ctx);
308:   return(0);
309: }

311: /*@C
312:     MatShellSetContext - sets the context for a shell matrix

314:    Collective on Mat

316:     Input Parameters:
317: +   mat - the shell matrix
318: -   ctx - the context

320:    Level: advanced


323: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
324: @*/
325: int MatShellSetContext(Mat mat,void *ctx)
326: {
327:   Mat_Shell  *shell = (Mat_Shell*)mat->data;
328:   int        ierr;
329:   PetscTruth flg;

333:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
334:   if (flg) {
335:     shell->ctx = ctx;
336:   }
337:   return(0);
338: }

340: /*@C
341:     MatShellSetOperation - Allows user to set a matrix operation for
342:                            a shell matrix.

344:    Collective on Mat

346:     Input Parameters:
347: +   mat - the shell matrix
348: .   op - the name of the operation
349: -   f - the function that provides the operation.

351:    Level: advanced

353:     Usage:
354: $      extern int usermult(Mat,Vec,Vec);
355: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
356: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

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

370:     Within each user-defined routine, the user should call
371:     MatShellGetContext() to obtain the user-defined context that was
372:     set by MatCreateShell().

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

376: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
377: @*/
378: int MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
379: {
380:   int        ierr;
381:   PetscTruth flg;

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

395:   return(0);
396: }

398: /*@C
399:     MatShellGetOperation - Gets a matrix function for a shell matrix.

401:     Not Collective

403:     Input Parameters:
404: +   mat - the shell matrix
405: -   op - the name of the operation

407:     Output Parameter:
408: .   f - the function that provides the operation.

410:     Level: advanced

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

418:     All user-provided functions have the same calling
419:     sequence as the usual matrix interface routines, since they
420:     are intended to be accessed via the usual matrix interface
421:     routines, e.g., 
422: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

424:     Within each user-defined routine, the user should call
425:     MatShellGetContext() to obtain the user-defined context that was
426:     set by MatCreateShell().

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

430: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation()
431: @*/
432: int MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
433: {
434:   int        ierr;
435:   PetscTruth flg;

439:   if (op == MATOP_DESTROY) {
440:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
441:     if (flg) {
442:       Mat_Shell *shell = (Mat_Shell*)mat->data;
443:       *f = (void(*)(void))shell->destroy;
444:     } else {
445:       *f = (void(*)(void))mat->ops->destroy;
446:     }
447:   } else if (op == MATOP_VIEW) {
448:     *f = (void(*)(void))mat->ops->view;
449:   } else {
450:     *f = (((void(**)(void))mat->ops)[op]);
451:   }

453:   return(0);
454: }