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: }