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 private/matimpl.h
10: #include private/vecimpl.h
12: typedef struct {
13: PetscErrorCode (*destroy)(Mat);
14: PetscErrorCode (*mult)(Mat,Vec,Vec);
15: PetscErrorCode (*multtranspose)(Mat,Vec,Vec);
16: PetscErrorCode (*getdiagonal)(Mat,Vec);
17: PetscTruth scale,shift;
18: PetscScalar vscale,vshift;
19: void *ctx;
20: } Mat_Shell;
24: /*@C
25: MatShellGetContext - Returns the user-provided context associated with a shell matrix.
27: Not Collective
29: Input Parameter:
30: . mat - the matrix, should have been created with MatCreateShell()
32: Output Parameter:
33: . ctx - the user provided context
35: Level: advanced
37: Notes:
38: This routine is intended for use within various shell matrix routines,
39: as set with MatShellSetOperation().
40:
41: .keywords: matrix, shell, get, context
43: .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
44: @*/
45: PetscErrorCode MatShellGetContext(Mat mat,void **ctx)
46: {
48: PetscTruth flg;
53: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
54: if (!flg) *ctx = 0;
55: else *ctx = ((Mat_Shell*)(mat->data))->ctx;
56: return(0);
57: }
61: PetscErrorCode MatDestroy_Shell(Mat mat)
62: {
64: Mat_Shell *shell;
67: shell = (Mat_Shell*)mat->data;
68: if (shell->destroy) {(*shell->destroy)(mat);}
69: PetscFree(shell);
70: return(0);
71: }
75: PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
76: {
77: Mat_Shell *shell = (Mat_Shell*)A->data;
81: (*shell->mult)(A,x,y);
82: if (shell->shift && shell->scale) {
83: VecAXPBY(y,shell->vshift,shell->vscale,x);
84: } else if (shell->scale) {
85: VecScale(y,shell->vscale);
86: } else {
87: VecAXPY(y,shell->vshift,x);
88: }
89: return(0);
90: }
94: PetscErrorCode MatMultTranspose_Shell(Mat A,Vec x,Vec y)
95: {
96: Mat_Shell *shell = (Mat_Shell*)A->data;
100: (*shell->multtranspose)(A,x,y);
101: if (shell->shift && shell->scale) {
102: VecAXPBY(y,shell->vshift,shell->vscale,x);
103: } else if (shell->scale) {
104: VecScale(y,shell->vscale);
105: } else {
106: VecAXPY(y,shell->vshift,x);
107: }
108: return(0);
109: }
113: PetscErrorCode MatGetDiagonal_Shell(Mat A,Vec v)
114: {
115: Mat_Shell *shell = (Mat_Shell*)A->data;
119: (*shell->getdiagonal)(A,v);
120: if (shell->scale) {
121: VecScale(v,shell->vscale);
122: }
123: if (shell->shift) {
124: VecShift(v,shell->vshift);
125: }
126: return(0);
127: }
131: PetscErrorCode MatShift_Shell(Mat Y,PetscScalar a)
132: {
133: Mat_Shell *shell = (Mat_Shell*)Y->data;
136: if (shell->scale || shell->shift) {
137: shell->vshift += a;
138: } else {
139: shell->mult = Y->ops->mult;
140: Y->ops->mult = MatMult_Shell;
141: if (Y->ops->multtranspose) {
142: shell->multtranspose = Y->ops->multtranspose;
143: Y->ops->multtranspose = MatMultTranspose_Shell;
144: }
145: if (Y->ops->getdiagonal) {
146: shell->getdiagonal = Y->ops->getdiagonal;
147: Y->ops->getdiagonal = MatGetDiagonal_Shell;
148: }
149: shell->vshift = a;
150: }
151: shell->shift = PETSC_TRUE;
152: return(0);
153: }
157: PetscErrorCode MatScale_Shell(Mat Y,PetscScalar a)
158: {
159: Mat_Shell *shell = (Mat_Shell*)Y->data;
162: if (shell->scale || shell->shift) {
163: shell->vscale *= a;
164: } else {
165: shell->mult = Y->ops->mult;
166: Y->ops->mult = MatMult_Shell;
167: if (Y->ops->multtranspose) {
168: shell->multtranspose = Y->ops->multtranspose;
169: Y->ops->multtranspose = MatMultTranspose_Shell;
170: }
171: if (Y->ops->getdiagonal) {
172: shell->getdiagonal = Y->ops->getdiagonal;
173: Y->ops->getdiagonal = MatGetDiagonal_Shell;
174: }
175: shell->vscale = a;
176: }
177: shell->scale = PETSC_TRUE;
178: return(0);
179: }
183: PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
184: {
185: Mat_Shell *shell = (Mat_Shell*)Y->data;
188: if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
189: shell->scale = PETSC_FALSE;
190: shell->shift = PETSC_FALSE;
191: shell->vshift = 0.0;
192: shell->vscale = 1.0;
193: Y->ops->mult = shell->mult;
194: Y->ops->multtranspose = shell->multtranspose;
195: Y->ops->getdiagonal = shell->getdiagonal;
196: }
197: return(0);
198: }
200: EXTERN PetscErrorCode MatConvert_Shell(Mat, const MatType,MatReuse,Mat*);
204: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
205: {
209: PetscLayoutSetBlockSize(A->rmap,bs);
210: PetscLayoutSetBlockSize(A->cmap,bs);
211: return(0);
212: }
214: static struct _MatOps MatOps_Values = {0,
215: 0,
216: 0,
217: 0,
218: /* 4*/ 0,
219: 0,
220: 0,
221: 0,
222: 0,
223: 0,
224: /*10*/ 0,
225: 0,
226: 0,
227: 0,
228: 0,
229: /*15*/ 0,
230: 0,
231: 0,
232: 0,
233: 0,
234: /*20*/ 0,
235: MatAssemblyEnd_Shell,
236: 0,
237: 0,
238: /*24*/ 0,
239: 0,
240: 0,
241: 0,
242: 0,
243: /*29*/ 0,
244: 0,
245: 0,
246: 0,
247: 0,
248: /*34*/ 0,
249: 0,
250: 0,
251: 0,
252: 0,
253: /*39*/ 0,
254: 0,
255: 0,
256: 0,
257: 0,
258: /*44*/ 0,
259: MatScale_Shell,
260: MatShift_Shell,
261: 0,
262: 0,
263: /*49*/ MatSetBlockSize_Shell,
264: 0,
265: 0,
266: 0,
267: 0,
268: /*54*/ 0,
269: 0,
270: 0,
271: 0,
272: 0,
273: /*59*/ 0,
274: MatDestroy_Shell,
275: 0,
276: 0,
277: 0,
278: /*64*/ 0,
279: 0,
280: 0,
281: 0,
282: 0,
283: /*69*/ 0,
284: 0,
285: MatConvert_Shell,
286: 0,
287: 0,
288: /*74*/ 0,
289: 0,
290: 0,
291: 0,
292: 0,
293: /*79*/ 0,
294: 0,
295: 0,
296: 0,
297: 0,
298: /*84*/ 0,
299: 0,
300: 0,
301: 0,
302: 0,
303: /*89*/ 0,
304: 0,
305: 0,
306: 0,
307: 0,
308: /*94*/ 0,
309: 0,
310: 0,
311: 0};
313: /*MC
314: MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
316: Level: advanced
318: .seealso: MatCreateShell
319: M*/
324: PetscErrorCode MatCreate_Shell(Mat A)
325: {
326: Mat_Shell *b;
330: PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));
332: PetscNewLog(A,Mat_Shell,&b);
333: A->data = (void*)b;
335: if (A->rmap->n == PETSC_DECIDE || A->cmap->n == PETSC_DECIDE) {
336: SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
337: }
339: PetscLayoutSetBlockSize(A->rmap,1);
340: PetscLayoutSetBlockSize(A->cmap,1);
341: PetscLayoutSetUp(A->rmap);
342: PetscLayoutSetUp(A->cmap);
344: b->ctx = 0;
345: b->scale = PETSC_FALSE;
346: b->shift = PETSC_FALSE;
347: b->vshift = 0.0;
348: b->vscale = 1.0;
349: b->mult = 0;
350: b->multtranspose = 0;
351: b->getdiagonal = 0;
352: A->assembled = PETSC_TRUE;
353: A->preallocated = PETSC_FALSE;
354: PetscObjectChangeTypeName((PetscObject)A,MATSHELL);
355: return(0);
356: }
361: /*@C
362: MatCreateShell - Creates a new matrix class for use with a user-defined
363: private data storage format.
365: Collective on MPI_Comm
367: Input Parameters:
368: + comm - MPI communicator
369: . m - number of local rows (must be given)
370: . n - number of local columns (must be given)
371: . M - number of global rows (may be PETSC_DETERMINE)
372: . N - number of global columns (may be PETSC_DETERMINE)
373: - ctx - pointer to data needed by the shell matrix routines
375: Output Parameter:
376: . A - the matrix
378: Level: advanced
380: Usage:
382: $ MatCreateShell(comm,m,n,M,N,ctx,&mat);
383: $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
384: $ [ Use matrix for operations that have been set ]
385: $ MatDestroy(mat);
387: Notes:
388: The shell matrix type is intended to provide a simple class to use
389: with KSP (such as, for use with matrix-free methods). You should not
390: use the shell type if you plan to define a complete matrix class.
392: Fortran Notes: The context can only be an integer or a PetscObject
393: unfortunately it cannot be a Fortran array or derived type.
395: PETSc requires that matrices and vectors being used for certain
396: operations are partitioned accordingly. For example, when
397: creating a shell matrix, A, that supports parallel matrix-vector
398: products using MatMult(A,x,y) the user should set the number
399: of local matrix rows to be the number of local elements of the
400: corresponding result vector, y. Note that this is information is
401: required for use of the matrix interface routines, even though
402: the shell matrix may not actually be physically partitioned.
403: For example,
405: $
406: $ Vec x, y
408: $ Mat A
409: $
410: $ VecCreateMPI(comm,PETSC_DECIDE,M,&y);
411: $ VecCreateMPI(comm,PETSC_DECIDE,N,&x);
412: $ VecGetLocalSize(y,&m);
413: $ VecGetLocalSize(x,&n);
414: $ MatCreateShell(comm,m,n,M,N,ctx,&A);
415: $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
416: $ MatMult(A,x,y);
417: $ MatDestroy(A);
418: $ VecDestroy(y); VecDestroy(x);
419: $
421: .keywords: matrix, shell, create
423: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
424: @*/
425: PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
426: {
430: MatCreate(comm,A);
431: MatSetSizes(*A,m,n,M,N);
432:
433: MatSetType(*A,MATSHELL);
434: MatShellSetContext(*A,ctx);
435: return(0);
436: }
440: /*@
441: MatShellSetContext - sets the context for a shell matrix
443: Collective on Mat
445: Input Parameters:
446: + mat - the shell matrix
447: - ctx - the context
449: Level: advanced
451: Fortran Notes: The context can only be an integer or a PetscObject
452: unfortunately it cannot be a Fortran array or derived type.
454: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
455: @*/
456: PetscErrorCode MatShellSetContext(Mat mat,void *ctx)
457: {
458: Mat_Shell *shell = (Mat_Shell*)mat->data;
460: PetscTruth flg;
464: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
465: if (flg) {
466: shell->ctx = ctx;
467: }
468: return(0);
469: }
473: /*@C
474: MatShellSetOperation - Allows user to set a matrix operation for
475: a shell matrix.
477: Collective on Mat
479: Input Parameters:
480: + mat - the shell matrix
481: . op - the name of the operation
482: - f - the function that provides the operation.
484: Level: advanced
486: Usage:
488: $ MatCreateShell(comm,m,n,M,N,ctx,&A);
489: $ MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
491: Notes:
492: See the file include/petscmat.h for a complete list of matrix
493: operations, which all have the form MATOP_<OPERATION>, where
494: <OPERATION> is the name (in all capital letters) of the
495: user interface routine (e.g., MatMult() -> MATOP_MULT).
497: All user-provided functions should have the same calling
498: sequence as the usual matrix interface routines, since they
499: are intended to be accessed via the usual matrix interface
500: routines, e.g.,
501: $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
503: In particular each function MUST return an error code of 0 on success and
504: nonzero on failure.
506: Within each user-defined routine, the user should call
507: MatShellGetContext() to obtain the user-defined context that was
508: set by MatCreateShell().
510: .keywords: matrix, shell, set, operation
512: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
513: @*/
514: PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
515: {
517: PetscTruth flg;
521: if (op == MATOP_DESTROY) {
522: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
523: if (flg) {
524: Mat_Shell *shell = (Mat_Shell*)mat->data;
525: shell->destroy = (PetscErrorCode (*)(Mat)) f;
526: } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f;
527: }
528: else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f;
529: else (((void(**)(void))mat->ops)[op]) = f;
531: return(0);
532: }
536: /*@C
537: MatShellGetOperation - Gets a matrix function for a shell matrix.
539: Not Collective
541: Input Parameters:
542: + mat - the shell matrix
543: - op - the name of the operation
545: Output Parameter:
546: . f - the function that provides the operation.
548: Level: advanced
550: Notes:
551: See the file include/petscmat.h for a complete list of matrix
552: operations, which all have the form MATOP_<OPERATION>, where
553: <OPERATION> is the name (in all capital letters) of the
554: user interface routine (e.g., MatMult() -> MATOP_MULT).
556: All user-provided functions have the same calling
557: sequence as the usual matrix interface routines, since they
558: are intended to be accessed via the usual matrix interface
559: routines, e.g.,
560: $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
562: Within each user-defined routine, the user should call
563: MatShellGetContext() to obtain the user-defined context that was
564: set by MatCreateShell().
566: .keywords: matrix, shell, set, operation
568: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
569: @*/
570: PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
571: {
573: PetscTruth flg;
577: if (op == MATOP_DESTROY) {
578: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
579: if (flg) {
580: Mat_Shell *shell = (Mat_Shell*)mat->data;
581: *f = (void(*)(void))shell->destroy;
582: } else {
583: *f = (void(*)(void))mat->ops->destroy;
584: }
585: } else if (op == MATOP_VIEW) {
586: *f = (void(*)(void))mat->ops->view;
587: } else {
588: *f = (((void(**)(void))mat->ops)[op]);
589: }
591: return(0);
592: }