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