Actual source code: shell.c

  1: /*
  2:    This provides a simple shell for Fortran (and C programmers) to 
  3:   create a very simple matrix class for use with KSP without coding 
  4:   much of anything.
  5: */

 7:  #include src/mat/matimpl.h
 8:  #include vecimpl.h

 10: typedef struct {
 11:   PetscErrorCode (*destroy)(Mat);
 12:   PetscErrorCode (*mult)(Mat,Vec,Vec);
 13:   PetscTruth     scale,shift;
 14:   PetscScalar    vscale,vshift;
 15:   void           *ctx;
 16: } 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(), MatShellSetContext()
 40: @*/
 41: PetscErrorCode MatShellGetContext(Mat mat,void **ctx)
 42: {
 44:   PetscTruth     flg;

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

 57: PetscErrorCode MatDestroy_Shell(Mat mat)
 58: {
 60:   Mat_Shell      *shell;

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

 71: PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
 72: {
 73:   Mat_Shell      *shell = (Mat_Shell*)A->data;

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

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

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

108: PetscErrorCode MatScale_Shell(const PetscScalar *a,Mat Y)
109: {
110:   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: PetscErrorCode 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 PetscErrorCode MatConvert_Shell(Mat,const MatType,Mat*);

145: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
146: {
148:   return(0);
149: }

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

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

254:   Level: advanced

256: .seealso: MatCreateShell
257: M*/

262: PetscErrorCode MatCreate_Shell(Mat A)
263: {
264:   Mat_Shell      *b;

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

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

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

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

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

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

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

303:   Collective on MPI_Comm

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

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

316:    Level: advanced

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

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

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

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

356: .keywords: matrix, shell, create

358: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
359: @*/
360: PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
361: {

365:   MatCreate(comm,m,n,M,N,A);
366:   MatSetType(*A,MATSHELL);
367:   MatShellSetContext(*A,ctx);
368:   return(0);
369: }

373: /*@C
374:     MatShellSetContext - sets the context for a shell matrix

376:    Collective on Mat

378:     Input Parameters:
379: +   mat - the shell matrix
380: -   ctx - the context

382:    Level: advanced


385: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
386: @*/
387: PetscErrorCode MatShellSetContext(Mat mat,void *ctx)
388: {
389:   Mat_Shell      *shell = (Mat_Shell*)mat->data;
391:   PetscTruth     flg;

395:   PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
396:   if (flg) {
397:     shell->ctx = ctx;
398:   }
399:   return(0);
400: }

404: /*@C
405:     MatShellSetOperation - Allows user to set a matrix operation for
406:                            a shell matrix.

408:    Collective on Mat

410:     Input Parameters:
411: +   mat - the shell matrix
412: .   op - the name of the operation
413: -   f - the function that provides the operation.

415:    Level: advanced

417:     Usage:
419: $      MatCreateShell(comm,m,n,M,N,ctx,&A);
420: $      MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);

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

428:     All user-provided functions should have the same calling
429:     sequence as the usual matrix interface routines, since they
430:     are intended to be accessed via the usual matrix interface
431:     routines, e.g., 
432: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

434:     Within each user-defined routine, the user should call
435:     MatShellGetContext() to obtain the user-defined context that was
436:     set by MatCreateShell().

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

440: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
441: @*/
442: PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
443: {
445:   PetscTruth     flg;

449:   if (op == MATOP_DESTROY) {
450:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
451:     if (flg) {
452:        Mat_Shell *shell = (Mat_Shell*)mat->data;
453:        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
454:     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
455:   }
456:   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
457:   else                       (((void(**)(void))mat->ops)[op]) = f;

459:   return(0);
460: }

464: /*@C
465:     MatShellGetOperation - Gets a matrix function for a shell matrix.

467:     Not Collective

469:     Input Parameters:
470: +   mat - the shell matrix
471: -   op - the name of the operation

473:     Output Parameter:
474: .   f - the function that provides the operation.

476:     Level: advanced

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

484:     All user-provided functions have the same calling
485:     sequence as the usual matrix interface routines, since they
486:     are intended to be accessed via the usual matrix interface
487:     routines, e.g., 
488: $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)

490:     Within each user-defined routine, the user should call
491:     MatShellGetContext() to obtain the user-defined context that was
492:     set by MatCreateShell().

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

496: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
497: @*/
498: PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
499: {
501:   PetscTruth     flg;

505:   if (op == MATOP_DESTROY) {
506:     PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
507:     if (flg) {
508:       Mat_Shell *shell = (Mat_Shell*)mat->data;
509:       *f = (void(*)(void))shell->destroy;
510:     } else {
511:       *f = (void(*)(void))mat->ops->destroy;
512:     }
513:   } else if (op == MATOP_VIEW) {
514:     *f = (void(*)(void))mat->ops->view;
515:   } else {
516:     *f = (((void(**)(void))mat->ops)[op]);
517:   }

519:   return(0);
520: }