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 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: /*@
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 PETSCMAT_DLLEXPORT 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, MatType,MatReuse,Mat*);
204: PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs)
205: {
207: return(0);
208: }
210: static struct _MatOps MatOps_Values = {0,
211: 0,
212: 0,
213: 0,
214: /* 4*/ 0,
215: 0,
216: 0,
217: 0,
218: 0,
219: 0,
220: /*10*/ 0,
221: 0,
222: 0,
223: 0,
224: 0,
225: /*15*/ 0,
226: 0,
227: 0,
228: 0,
229: 0,
230: /*20*/ 0,
231: MatAssemblyEnd_Shell,
232: 0,
233: 0,
234: 0,
235: /*25*/ 0,
236: 0,
237: 0,
238: 0,
239: 0,
240: /*30*/ 0,
241: 0,
242: 0,
243: 0,
244: 0,
245: /*35*/ 0,
246: 0,
247: 0,
248: 0,
249: 0,
250: /*40*/ 0,
251: 0,
252: 0,
253: 0,
254: 0,
255: /*45*/ 0,
256: MatScale_Shell,
257: MatShift_Shell,
258: 0,
259: 0,
260: /*50*/ MatSetBlockSize_Shell,
261: 0,
262: 0,
263: 0,
264: 0,
265: /*55*/ 0,
266: 0,
267: 0,
268: 0,
269: 0,
270: /*60*/ 0,
271: MatDestroy_Shell,
272: 0,
273: 0,
274: 0,
275: /*65*/ 0,
276: 0,
277: 0,
278: 0,
279: 0,
280: /*70*/ 0,
281: MatConvert_Shell,
282: 0,
283: 0,
284: 0,
285: /*75*/ 0,
286: 0,
287: 0,
288: 0,
289: 0,
290: /*80*/ 0,
291: 0,
292: 0,
293: 0,
294: 0,
295: /*85*/ 0,
296: 0,
297: 0,
298: 0,
299: 0,
300: /*90*/ 0,
301: 0,
302: 0,
303: 0,
304: 0,
305: /*95*/ 0,
306: 0,
307: 0,
308: 0};
310: /*MC
311: MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
313: Level: advanced
315: .seealso: MatCreateShell
316: M*/
321: PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Shell(Mat A)
322: {
323: Mat_Shell *b;
327: PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));
329: PetscNew(Mat_Shell,&b);
330: PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
331: A->data = (void*)b;
333: if (A->rmap.n == PETSC_DECIDE || A->cmap.n == PETSC_DECIDE) {
334: SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
335: }
337: PetscMapInitialize(A->comm,&A->rmap);
338: PetscMapInitialize(A->comm,&A->cmap);
340: b->ctx = 0;
341: b->scale = PETSC_FALSE;
342: b->shift = PETSC_FALSE;
343: b->vshift = 0.0;
344: b->vscale = 1.0;
345: b->mult = 0;
346: b->multtranspose = 0;
347: b->getdiagonal = 0;
348: A->assembled = PETSC_TRUE;
349: A->preallocated = PETSC_FALSE;
350: return(0);
351: }
356: /*@C
357: MatCreateShell - Creates a new matrix class for use with a user-defined
358: private data storage format.
360: Collective on MPI_Comm
362: Input Parameters:
363: + comm - MPI communicator
364: . m - number of local rows (must be given)
365: . n - number of local columns (must be given)
366: . M - number of global rows (may be PETSC_DETERMINE)
367: . N - number of global columns (may be PETSC_DETERMINE)
368: - ctx - pointer to data needed by the shell matrix routines
370: Output Parameter:
371: . A - the matrix
373: Level: advanced
375: Usage:
377: $ MatCreateShell(comm,m,n,M,N,ctx,&mat);
378: $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
379: $ [ Use matrix for operations that have been set ]
380: $ MatDestroy(mat);
382: Notes:
383: The shell matrix type is intended to provide a simple class to use
384: with KSP (such as, for use with matrix-free methods). You should not
385: use the shell type if you plan to define a complete matrix class.
387: Fortran Notes: The context can only be an integer or a PetscObject
388: unfortunately it cannot be a Fortran array or derived type.
390: PETSc requires that matrices and vectors being used for certain
391: operations are partitioned accordingly. For example, when
392: creating a shell matrix, A, that supports parallel matrix-vector
393: products using MatMult(A,x,y) the user should set the number
394: of local matrix rows to be the number of local elements of the
395: corresponding result vector, y. Note that this is information is
396: required for use of the matrix interface routines, even though
397: the shell matrix may not actually be physically partitioned.
398: For example,
400: $
401: $ Vec x, y
403: $ Mat A
404: $
405: $ VecCreateMPI(comm,PETSC_DECIDE,M,&y);
406: $ VecCreateMPI(comm,PETSC_DECIDE,N,&x);
407: $ VecGetLocalSize(y,&m);
408: $ VecGetLocalSize(x,&n);
409: $ MatCreateShell(comm,m,n,M,N,ctx,&A);
410: $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
411: $ MatMult(A,x,y);
412: $ MatDestroy(A);
413: $ VecDestroy(y); VecDestroy(x);
414: $
416: .keywords: matrix, shell, create
418: .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
419: @*/
420: PetscErrorCode PETSCMAT_DLLEXPORT MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
421: {
425: MatCreate(comm,A);
426: MatSetSizes(*A,m,n,M,N);
427:
428: MatSetType(*A,MATSHELL);
429: MatShellSetContext(*A,ctx);
430: return(0);
431: }
435: /*@
436: MatShellSetContext - sets the context for a shell matrix
438: Collective on Mat
440: Input Parameters:
441: + mat - the shell matrix
442: - ctx - the context
444: Level: advanced
446: Fortran Notes: The context can only be an integer or a PetscObject
447: unfortunately it cannot be a Fortran array or derived type.
449: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
450: @*/
451: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetContext(Mat mat,void *ctx)
452: {
453: Mat_Shell *shell = (Mat_Shell*)mat->data;
455: PetscTruth flg;
459: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
460: if (flg) {
461: shell->ctx = ctx;
462: }
463: return(0);
464: }
468: /*@C
469: MatShellSetOperation - Allows user to set a matrix operation for
470: a shell matrix.
472: Collective on Mat
474: Input Parameters:
475: + mat - the shell matrix
476: . op - the name of the operation
477: - f - the function that provides the operation.
479: Level: advanced
481: Usage:
483: $ MatCreateShell(comm,m,n,M,N,ctx,&A);
484: $ MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
486: Notes:
487: See the file include/petscmat.h for a complete list of matrix
488: operations, which all have the form MATOP_<OPERATION>, where
489: <OPERATION> is the name (in all capital letters) of the
490: user interface routine (e.g., MatMult() -> MATOP_MULT).
492: All user-provided functions should have the same calling
493: sequence as the usual matrix interface routines, since they
494: are intended to be accessed via the usual matrix interface
495: routines, e.g.,
496: $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
498: Within each user-defined routine, the user should call
499: MatShellGetContext() to obtain the user-defined context that was
500: set by MatCreateShell().
502: .keywords: matrix, shell, set, operation
504: .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
505: @*/
506: PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
507: {
509: PetscTruth flg;
513: if (op == MATOP_DESTROY) {
514: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
515: if (flg) {
516: Mat_Shell *shell = (Mat_Shell*)mat->data;
517: shell->destroy = (PetscErrorCode (*)(Mat)) f;
518: } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f;
519: }
520: else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f;
521: else (((void(**)(void))mat->ops)[op]) = f;
523: return(0);
524: }
528: /*@C
529: MatShellGetOperation - Gets a matrix function for a shell matrix.
531: Not Collective
533: Input Parameters:
534: + mat - the shell matrix
535: - op - the name of the operation
537: Output Parameter:
538: . f - the function that provides the operation.
540: Level: advanced
542: Notes:
543: See the file include/petscmat.h for a complete list of matrix
544: operations, which all have the form MATOP_<OPERATION>, where
545: <OPERATION> is the name (in all capital letters) of the
546: user interface routine (e.g., MatMult() -> MATOP_MULT).
548: All user-provided functions have the same calling
549: sequence as the usual matrix interface routines, since they
550: are intended to be accessed via the usual matrix interface
551: routines, e.g.,
552: $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
554: Within each user-defined routine, the user should call
555: MatShellGetContext() to obtain the user-defined context that was
556: set by MatCreateShell().
558: .keywords: matrix, shell, set, operation
560: .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
561: @*/
562: PetscErrorCode PETSCMAT_DLLEXPORT MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
563: {
565: PetscTruth flg;
569: if (op == MATOP_DESTROY) {
570: PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);
571: if (flg) {
572: Mat_Shell *shell = (Mat_Shell*)mat->data;
573: *f = (void(*)(void))shell->destroy;
574: } else {
575: *f = (void(*)(void))mat->ops->destroy;
576: }
577: } else if (op == MATOP_VIEW) {
578: *f = (void(*)(void))mat->ops->view;
579: } else {
580: *f = (((void(**)(void))mat->ops)[op]);
581: }
583: return(0);
584: }