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