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

 12: typedef struct {
 13:   PetscErrorCode (*destroy)(Mat);
 14:   PetscErrorCode (*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: PetscErrorCode PETSCMAT_DLLEXPORT MatShellGetContext(Mat mat,void **ctx)
 44: {
 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: PetscErrorCode MatDestroy_Shell(Mat mat)
 60: {
 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: PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
 74: {
 75:   Mat_Shell      *shell = (Mat_Shell*)A->data;

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

 92: PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
 93: {
 94:   Mat_Shell *shell = (Mat_Shell*)Y->data;

 97:   if (shell->scale || shell->shift) {
 98:     shell->vshift += a;
 99:   } else {
100:     shell->mult   = Y->ops->mult;
101:     Y->ops->mult  = MatMult_Shell;
102:     shell->vshift = a;
103:   }
104:   shell->shift  =  PETSC_TRUE;
105:   return(0);
106: }

110: PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
111: {
112:   Mat_Shell *shell = (Mat_Shell*)Y->data;

115:   if (shell->scale || shell->shift) {
116:     shell->vscale *= a;
117:   } else {
118:     shell->mult   = Y->ops->mult;
119:     Y->ops->mult  = MatMult_Shell;
120:     shell->vscale = a;
121:   }
122:   shell->scale  =  PETSC_TRUE;
123:   return(0);
124: }

128: PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
129: {
130:   Mat_Shell *shell = (Mat_Shell*)Y->data;

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

143: EXTERN PetscErrorCode MatConvert_Shell(Mat, MatType,MatReuse,Mat*);

147: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
148: {
150:   return(0);
151: }

153: static struct _MatOps MatOps_Values = {0,
154:        0,
155:        0,
156:        0,
157: /* 4*/ 0,
158:        0,
159:        0,
160:        0,
161:        0,
162:        0,
163: /*10*/ 0,
164:        0,
165:        0,
166:        0,
167:        0,
168: /*15*/ 0,
169:        0,
170:        0,
171:        0,
172:        0,
173: /*20*/ 0,
174:        MatAssemblyEnd_Shell,
175:        0,
176:        0,
177:        0,
178: /*25*/ 0,
179:        0,
180:        0,
181:        0,
182:        0,
183: /*30*/ 0,
184:        0,
185:        0,
186:        0,
187:        0,
188: /*35*/ 0,
189:        0,
190:        0,
191:        0,
192:        0,
193: /*40*/ 0,
194:        0,
195:        0,
196:        0,
197:        0,
198: /*45*/ 0,
199:        MatScale_Shell,
200:        MatShift_Shell,
201:        0,
202:        0,
203: /*50*/ MatSetBlockSize_Shell,
204:        0,
205:        0,
206:        0,
207:        0,
208: /*55*/ 0,
209:        0,
210:        0,
211:        0,
212:        0,
213: /*60*/ 0,
214:        MatDestroy_Shell,
215:        0,
216:        MatGetPetscMaps_Petsc,
217:        0,
218: /*65*/ 0,
219:        0,
220:        0,
221:        0,
222:        0,
223: /*70*/ 0,
224:        MatConvert_Shell,
225:        0,
226:        0,
227:        0,
228: /*75*/ 0,
229:        0,
230:        0,
231:        0,
232:        0,
233: /*80*/ 0,
234:        0,
235:        0,
236:        0,
237:        0,
238: /*85*/ 0,
239:        0,
240:        0,
241:        0,
242:        0,
243: /*90*/ 0,
244:        0,
245:        0,
246:        0,
247:        0,
248: /*95*/ 0,
249:        0,
250:        0,
251:        0};

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

256:   Level: advanced

258: .seealso: MatCreateShell
259: M*/

264: PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Shell(Mat A)
265: {
266:   Mat_Shell      *b;

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

272:   PetscNew(Mat_Shell,&b);
273:   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
274:   A->data = (void*)b;

276:   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
277:     SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
278:   }

280:   PetscSplitOwnership(A->comm,&A->m,&A->M);
281:   PetscSplitOwnership(A->comm,&A->n,&A->N);

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

286:   b->ctx          = 0;
287:   b->scale        = PETSC_FALSE;
288:   b->shift        = PETSC_FALSE;
289:   b->vshift       = 0.0;
290:   b->vscale       = 1.0;
291:   b->mult         = 0;
292:   A->assembled    = PETSC_TRUE;
293:   A->preallocated = PETSC_TRUE;
294:   return(0);
295: }

300: /*@C
301:    MatCreateShell - Creates a new matrix class for use with a user-defined
302:    private data storage format. 

304:   Collective on MPI_Comm

306:    Input Parameters:
307: +  comm - MPI communicator
308: .  m - number of local rows (must be given)
309: .  n - number of local columns (must be given)
310: .  M - number of global rows (may be PETSC_DETERMINE)
311: .  N - number of global columns (may be PETSC_DETERMINE)
312: -  ctx - pointer to data needed by the shell matrix routines

314:    Output Parameter:
315: .  A - the matrix

317:    Level: advanced

319:   Usage:
321: $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
322: $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
323: $    [ Use matrix for operations that have been set ]
324: $    MatDestroy(mat);

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

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

334:    PETSc requires that matrices and vectors being used for certain
335:    operations are partitioned accordingly.  For example, when
336:    creating a shell matrix, A, that supports parallel matrix-vector
337:    products using MatMult(A,x,y) the user should set the number
338:    of local matrix rows to be the number of local elements of the
339:    corresponding result vector, y. Note that this is information is
340:    required for use of the matrix interface routines, even though
341:    the shell matrix may not actually be physically partitioned.
342:    For example,

344: $
345: $     Vec x, y
347: $     Mat A
348: $
349: $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
350: $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
351: $     VecGetLocalSize(y,&m);
352: $     VecGetLocalSize(x,&n);
353: $     MatCreateShell(comm,m,n,M,N,ctx,&A);
354: $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
355: $     MatMult(A,x,y);
356: $     MatDestroy(A);
357: $     VecDestroy(y); VecDestroy(x);
358: $

360: .keywords: matrix, shell, create

362: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
363: @*/
364: PetscErrorCode PETSCMAT_DLLEXPORT MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
365: {

369:   MatCreate(comm,A);
370:   MatSetSizes(*A,m,n,M,N);
371:   MatSetType(*A,MATSHELL);
372:   MatShellSetContext(*A,ctx);
373:   return(0);
374: }

378: /*@C
379:     MatShellSetContext - sets the context for a shell matrix

381:    Collective on Mat

383:     Input Parameters:
384: +   mat - the shell matrix
385: -   ctx - the context

387:    Level: advanced

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: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
393: @*/
394: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetContext(Mat mat,void *ctx)
395: {
396:   Mat_Shell      *shell = (Mat_Shell*)mat->data;
398:   PetscTruth     flg;

402:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
403:   if (flg) {
404:     shell->ctx = ctx;
405:   }
406:   return(0);
407: }

411: /*@C
412:     MatShellSetOperation - Allows user to set a matrix operation for
413:                            a shell matrix.

415:    Collective on Mat

417:     Input Parameters:
418: +   mat - the shell matrix
419: .   op - the name of the operation
420: -   f - the function that provides the operation.

422:    Level: advanced

424:     Usage:
426: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
427: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

435:     All user-provided functions should have the same calling
436:     sequence as the usual matrix interface routines, since they
437:     are intended to be accessed via the usual matrix interface
438:     routines, e.g., 
439: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

441:     Within each user-defined routine, the user should call
442:     MatShellGetContext() to obtain the user-defined context that was
443:     set by MatCreateShell().

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

447: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
448: @*/
449: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
450: {
452:   PetscTruth     flg;

456:   if (op == MATOP_DESTROY) {
457:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
458:     if (flg) {
459:        Mat_Shell *shell = (Mat_Shell*)mat->data;
460:        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
461:     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
462:   }
463:   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
464:   else                       (((void(**)(void))mat->ops)[op]) = f;

466:   return(0);
467: }

471: /*@C
472:     MatShellGetOperation - Gets a matrix function for a shell matrix.

474:     Not Collective

476:     Input Parameters:
477: +   mat - the shell matrix
478: -   op - the name of the operation

480:     Output Parameter:
481: .   f - the function that provides the operation.

483:     Level: advanced

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

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

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

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

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

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

526:   return(0);
527: }