xref: /petsc/src/mat/impls/shell/shell.c (revision b7d02931603f2882dca46274911ebda259f56fb0)
1 /*$Id: shell.c,v 1.88 2001/09/07 20:09:41 bsmith Exp $*/
2 
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 */
8 
9 #include "src/mat/matimpl.h"        /*I "petscmat.h" I*/
10 #include "src/vec/vecimpl.h"
11 
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;
19 
20 #undef __FUNCT__
21 #define __FUNCT__ "MatShellGetContext"
22 /*@
23     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
24 
25     Not Collective
26 
27     Input Parameter:
28 .   mat - the matrix, should have been created with MatCreateShell()
29 
30     Output Parameter:
31 .   ctx - the user provided context
32 
33     Level: advanced
34 
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
40 
41 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext()
42 @*/
43 int MatShellGetContext(Mat mat,void **ctx)
44 {
45   int        ierr;
46   PetscTruth flg;
47 
48   PetscFunctionBegin;
49   PetscValidHeaderSpecific(mat,MAT_COOKIE);
50   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
51   if (!flg) *ctx = 0;
52   else      *ctx = ((Mat_Shell*)(mat->data))->ctx;
53   PetscFunctionReturn(0);
54 }
55 
56 #undef __FUNCT__
57 #define __FUNCT__ "MatDestroy_Shell"
58 int MatDestroy_Shell(Mat mat)
59 {
60   int       ierr;
61   Mat_Shell *shell;
62 
63   PetscFunctionBegin;
64   shell = (Mat_Shell*)mat->data;
65   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
66   ierr = PetscFree(shell);CHKERRQ(ierr);
67   PetscFunctionReturn(0);
68 }
69 
70 #undef __FUNCT__
71 #define __FUNCT__ "MatMult_Shell"
72 int MatMult_Shell(Mat A,Vec x,Vec y)
73 {
74   Mat_Shell   *shell = (Mat_Shell*)A->data;
75   int         ierr;
76 
77   PetscFunctionBegin;
78   ierr = (*shell->mult)(A,x,y);CHKERRQ(ierr);
79   if (shell->shift && shell->scale) {
80     ierr = VecAXPBY(&shell->vshift,&shell->vscale,x,y);CHKERRQ(ierr);
81   } else if (shell->scale) {
82     ierr = VecScale(&shell->vscale,y);CHKERRQ(ierr);
83   } else {
84     ierr = VecAXPY(&shell->vshift,x,y);CHKERRQ(ierr);
85   }
86   PetscFunctionReturn(0);
87 }
88 
89 #undef __FUNCT__
90 #define __FUNCT__ "MatShift_Shell"
91 int MatShift_Shell(const PetscScalar *a,Mat Y)
92 {
93   Mat_Shell *shell = (Mat_Shell*)Y->data;
94   PetscFunctionBegin;
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   PetscFunctionReturn(0);
104 }
105 
106 #undef __FUNCT__
107 #define __FUNCT__ "MatScale_Shell"
108 int MatScale_Shell(const PetscScalar *a,Mat Y)
109 {
110   Mat_Shell *shell = (Mat_Shell*)Y->data;
111   PetscFunctionBegin;
112   if (shell->scale || shell->shift) {
113     shell->vscale *= *a;
114   } else {
115     shell->mult   = Y->ops->mult;
116     Y->ops->mult  = MatMult_Shell;
117     shell->vscale = *a;
118   }
119   shell->scale  =  PETSC_TRUE;
120   PetscFunctionReturn(0);
121 }
122 
123 #undef __FUNCT__
124 #define __FUNCT__ "MatAssemblyEnd_Shell"
125 int MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
126 {
127   Mat_Shell *shell = (Mat_Shell*)Y->data;
128 
129   PetscFunctionBegin;
130   if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
131     shell->scale  = PETSC_FALSE;
132     shell->shift  = PETSC_FALSE;
133     shell->vshift = 0.0;
134     shell->vscale = 1.0;
135     Y->ops->mult  = shell->mult;
136   }
137   PetscFunctionReturn(0);
138 }
139 
140 extern int MatConvert_Shell(Mat,MatType,Mat*);
141 
142 static struct _MatOps MatOps_Values = {0,
143        0,
144        0,
145        0,
146        0,
147        0,
148        0,
149        0,
150        0,
151        0,
152        0,
153        0,
154        0,
155        0,
156        0,
157        0,
158        0,
159        0,
160        0,
161        0,
162        0,
163        MatAssemblyEnd_Shell,
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        0,
177        0,
178        0,
179        0,
180        0,
181        0,
182        0,
183        0,
184        0,
185        0,
186        0,
187        0,
188        MatScale_Shell,
189        MatShift_Shell,
190        0,
191        0,
192        0,
193        0,
194        0,
195        0,
196        0,
197        0,
198        0,
199        0,
200        0,
201        0,
202        0,
203        MatDestroy_Shell,
204        0,
205        MatGetPetscMaps_Petsc,
206        0,
207        0,
208        0,
209        0,
210        0,
211        0,
212        0,
213        MatConvert_Shell};
214 
215 /*MC
216    MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
217 
218   Level: advanced
219 
220 .seealso: MatCreateShell
221 M*/
222 
223 EXTERN_C_BEGIN
224 #undef __FUNCT__
225 #define __FUNCT__ "MatCreate_Shell"
226 int MatCreate_Shell(Mat A)
227 {
228   Mat_Shell *b;
229   int       ierr;
230 
231   PetscFunctionBegin;
232   ierr            = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
233 
234   ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr);
235   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
236   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
237   A->data = (void*)b;
238 
239   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
240     SETERRQ(1,"Must give local row and column count for matrix");
241   }
242 
243   ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr);
244   ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr);
245 
246   ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr);
247   ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr);
248 
249   b->ctx          = 0;
250   b->scale        = PETSC_FALSE;
251   b->shift        = PETSC_FALSE;
252   b->vshift       = 0.0;
253   b->vscale       = 1.0;
254   b->mult         = 0;
255   A->assembled    = PETSC_TRUE;
256   A->preallocated = PETSC_TRUE;
257   PetscFunctionReturn(0);
258 }
259 EXTERN_C_END
260 
261 #undef __FUNCT__
262 #define __FUNCT__ "MatCreateShell"
263 /*@C
264    MatCreateShell - Creates a new matrix class for use with a user-defined
265    private data storage format.
266 
267   Collective on MPI_Comm
268 
269    Input Parameters:
270 +  comm - MPI communicator
271 .  m - number of local rows (must be given)
272 .  n - number of local columns (must be given)
273 .  M - number of global rows (may be PETSC_DETERMINE)
274 .  N - number of global columns (may be PETSC_DETERMINE)
275 -  ctx - pointer to data needed by the shell matrix routines
276 
277    Output Parameter:
278 .  A - the matrix
279 
280    Level: advanced
281 
282   Usage:
283 $    extern int mult(Mat,Vec,Vec);
284 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
285 $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
286 $    [ Use matrix for operations that have been set ]
287 $    MatDestroy(mat);
288 
289    Notes:
290    The shell matrix type is intended to provide a simple class to use
291    with KSP (such as, for use with matrix-free methods). You should not
292    use the shell type if you plan to define a complete matrix class.
293 
294    PETSc requires that matrices and vectors being used for certain
295    operations are partitioned accordingly.  For example, when
296    creating a shell matrix, A, that supports parallel matrix-vector
297    products using MatMult(A,x,y) the user should set the number
298    of local matrix rows to be the number of local elements of the
299    corresponding result vector, y. Note that this is information is
300    required for use of the matrix interface routines, even though
301    the shell matrix may not actually be physically partitioned.
302    For example,
303 
304 $
305 $     Vec x, y
306 $     extern int mult(Mat,Vec,Vec);
307 $     Mat A
308 $
309 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
310 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
311 $     VecGetLocalSize(y,&m);
312 $     VecGetLocalSize(x,&n);
313 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
314 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
315 $     MatMult(A,x,y);
316 $     MatDestroy(A);
317 $     VecDestroy(y); VecDestroy(x);
318 $
319 
320 .keywords: matrix, shell, create
321 
322 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
323 @*/
324 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
325 {
326   int       ierr;
327 
328   PetscFunctionBegin;
329   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
330   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
331   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
332   PetscFunctionReturn(0);
333 }
334 
335 #undef __FUNCT__
336 #define __FUNCT__ "MatShellSetContext"
337 /*@C
338     MatShellSetContext - sets the context for a shell matrix
339 
340    Collective on Mat
341 
342     Input Parameters:
343 +   mat - the shell matrix
344 -   ctx - the context
345 
346    Level: advanced
347 
348 
349 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
350 @*/
351 int MatShellSetContext(Mat mat,void *ctx)
352 {
353   Mat_Shell  *shell = (Mat_Shell*)mat->data;
354   int        ierr;
355   PetscTruth flg;
356 
357   PetscFunctionBegin;
358   PetscValidHeaderSpecific(mat,MAT_COOKIE);
359   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
360   if (flg) {
361     shell->ctx = ctx;
362   }
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "MatShellSetOperation"
368 /*@C
369     MatShellSetOperation - Allows user to set a matrix operation for
370                            a shell matrix.
371 
372    Collective on Mat
373 
374     Input Parameters:
375 +   mat - the shell matrix
376 .   op - the name of the operation
377 -   f - the function that provides the operation.
378 
379    Level: advanced
380 
381     Usage:
382 $      extern int usermult(Mat,Vec,Vec);
383 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
384 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
385 
386     Notes:
387     See the file include/petscmat.h for a complete list of matrix
388     operations, which all have the form MATOP_<OPERATION>, where
389     <OPERATION> is the name (in all capital letters) of the
390     user interface routine (e.g., MatMult() -> MATOP_MULT).
391 
392     All user-provided functions should have the same calling
393     sequence as the usual matrix interface routines, since they
394     are intended to be accessed via the usual matrix interface
395     routines, e.g.,
396 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
397 
398     Within each user-defined routine, the user should call
399     MatShellGetContext() to obtain the user-defined context that was
400     set by MatCreateShell().
401 
402 .keywords: matrix, shell, set, operation
403 
404 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
405 @*/
406 int MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
407 {
408   int        ierr;
409   PetscTruth flg;
410 
411   PetscFunctionBegin;
412   PetscValidHeaderSpecific(mat,MAT_COOKIE);
413   if (op == MATOP_DESTROY) {
414     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
415     if (flg) {
416        Mat_Shell *shell = (Mat_Shell*)mat->data;
417        shell->destroy                 = (int (*)(Mat)) f;
418     } else mat->ops->destroy            = (int (*)(Mat)) f;
419   }
420   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,PetscViewer)) f;
421   else                       (((void(**)(void))mat->ops)[op]) = f;
422 
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "MatShellGetOperation"
428 /*@C
429     MatShellGetOperation - Gets a matrix function for a shell matrix.
430 
431     Not Collective
432 
433     Input Parameters:
434 +   mat - the shell matrix
435 -   op - the name of the operation
436 
437     Output Parameter:
438 .   f - the function that provides the operation.
439 
440     Level: advanced
441 
442     Notes:
443     See the file include/petscmat.h for a complete list of matrix
444     operations, which all have the form MATOP_<OPERATION>, where
445     <OPERATION> is the name (in all capital letters) of the
446     user interface routine (e.g., MatMult() -> MATOP_MULT).
447 
448     All user-provided functions have the same calling
449     sequence as the usual matrix interface routines, since they
450     are intended to be accessed via the usual matrix interface
451     routines, e.g.,
452 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
453 
454     Within each user-defined routine, the user should call
455     MatShellGetContext() to obtain the user-defined context that was
456     set by MatCreateShell().
457 
458 .keywords: matrix, shell, set, operation
459 
460 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
461 @*/
462 int MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
463 {
464   int        ierr;
465   PetscTruth flg;
466 
467   PetscFunctionBegin;
468   PetscValidHeaderSpecific(mat,MAT_COOKIE);
469   if (op == MATOP_DESTROY) {
470     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
471     if (flg) {
472       Mat_Shell *shell = (Mat_Shell*)mat->data;
473       *f = (void(*)(void))shell->destroy;
474     } else {
475       *f = (void(*)(void))mat->ops->destroy;
476     }
477   } else if (op == MATOP_VIEW) {
478     *f = (void(*)(void))mat->ops->view;
479   } else {
480     *f = (((void(**)(void))mat->ops)[op]);
481   }
482 
483   PetscFunctionReturn(0);
484 }
485 
486