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