xref: /petsc/src/mat/impls/shell/shell.c (revision 2c62819748cfd70e832b5b508eca90f58e6249c6)
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()
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(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(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 EXTERN_C_BEGIN
216 #undef __FUNCT__
217 #define __FUNCT__ "MatCreate_Shell"
218 int MatCreate_Shell(Mat A)
219 {
220   Mat_Shell *b;
221   int       ierr;
222 
223   PetscFunctionBegin;
224   ierr            = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
225 
226   ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr);
227   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
228   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
229   A->data = (void*)b;
230 
231   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
232     SETERRQ(1,"Must give local row and column count for matrix");
233   }
234 
235   ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr);
236   ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr);
237 
238   ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr);
239   ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr);
240 
241   b->ctx          = 0;
242   b->scale        = PETSC_FALSE;
243   b->shift        = PETSC_FALSE;
244   b->vshift       = 0.0;
245   b->vscale       = 1.0;
246   b->mult         = 0;
247   A->assembled    = PETSC_TRUE;
248   A->preallocated = PETSC_TRUE;
249   PetscFunctionReturn(0);
250 }
251 EXTERN_C_END
252 
253 #undef __FUNCT__
254 #define __FUNCT__ "MatCreateShell"
255 /*@C
256    MatCreateShell - Creates a new matrix class for use with a user-defined
257    private data storage format.
258 
259   Collective on MPI_Comm
260 
261    Input Parameters:
262 +  comm - MPI communicator
263 .  m - number of local rows (must be given)
264 .  n - number of local columns (must be given)
265 .  M - number of global rows (may be PETSC_DETERMINE)
266 .  N - number of global columns (may be PETSC_DETERMINE)
267 -  ctx - pointer to data needed by the shell matrix routines
268 
269    Output Parameter:
270 .  A - the matrix
271 
272    Level: advanced
273 
274   Usage:
275 $    extern int mult(Mat,Vec,Vec);
276 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
277 $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
278 $    [ Use matrix for operations that have been set ]
279 $    MatDestroy(mat);
280 
281    Notes:
282    The shell matrix type is intended to provide a simple class to use
283    with KSP (such as, for use with matrix-free methods). You should not
284    use the shell type if you plan to define a complete matrix class.
285 
286    PETSc requires that matrices and vectors being used for certain
287    operations are partitioned accordingly.  For example, when
288    creating a shell matrix, A, that supports parallel matrix-vector
289    products using MatMult(A,x,y) the user should set the number
290    of local matrix rows to be the number of local elements of the
291    corresponding result vector, y. Note that this is information is
292    required for use of the matrix interface routines, even though
293    the shell matrix may not actually be physically partitioned.
294    For example,
295 
296 $
297 $     Vec x, y
298 $     extern int mult(Mat,Vec,Vec);
299 $     Mat A
300 $
301 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
302 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
303 $     VecGetLocalSize(y,&m);
304 $     VecGetLocalSize(x,&n);
305 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
306 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
307 $     MatMult(A,x,y);
308 $     MatDestroy(A);
309 $     VecDestroy(y); VecDestroy(x);
310 $
311 
312 .keywords: matrix, shell, create
313 
314 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
315 @*/
316 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
317 {
318   int       ierr;
319 
320   PetscFunctionBegin;
321   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
322   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
323   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
324   PetscFunctionReturn(0);
325 }
326 
327 #undef __FUNCT__
328 #define __FUNCT__ "MatShellSetContext"
329 /*@C
330     MatShellSetContext - sets the context for a shell matrix
331 
332    Collective on Mat
333 
334     Input Parameters:
335 +   mat - the shell matrix
336 -   ctx - the context
337 
338    Level: advanced
339 
340 
341 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
342 @*/
343 int MatShellSetContext(Mat mat,void *ctx)
344 {
345   Mat_Shell  *shell = (Mat_Shell*)mat->data;
346   int        ierr;
347   PetscTruth flg;
348 
349   PetscFunctionBegin;
350   PetscValidHeaderSpecific(mat,MAT_COOKIE);
351   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
352   if (flg) {
353     shell->ctx = ctx;
354   }
355   PetscFunctionReturn(0);
356 }
357 
358 #undef __FUNCT__
359 #define __FUNCT__ "MatShellSetOperation"
360 /*@C
361     MatShellSetOperation - Allows user to set a matrix operation for
362                            a shell matrix.
363 
364    Collective on Mat
365 
366     Input Parameters:
367 +   mat - the shell matrix
368 .   op - the name of the operation
369 -   f - the function that provides the operation.
370 
371    Level: advanced
372 
373     Usage:
374 $      extern int usermult(Mat,Vec,Vec);
375 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
376 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
377 
378     Notes:
379     See the file include/petscmat.h for a complete list of matrix
380     operations, which all have the form MATOP_<OPERATION>, where
381     <OPERATION> is the name (in all capital letters) of the
382     user interface routine (e.g., MatMult() -> MATOP_MULT).
383 
384     All user-provided functions should have the same calling
385     sequence as the usual matrix interface routines, since they
386     are intended to be accessed via the usual matrix interface
387     routines, e.g.,
388 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
389 
390     Within each user-defined routine, the user should call
391     MatShellGetContext() to obtain the user-defined context that was
392     set by MatCreateShell().
393 
394 .keywords: matrix, shell, set, operation
395 
396 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
397 @*/
398 int MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
399 {
400   int        ierr;
401   PetscTruth flg;
402 
403   PetscFunctionBegin;
404   PetscValidHeaderSpecific(mat,MAT_COOKIE);
405   if (op == MATOP_DESTROY) {
406     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
407     if (flg) {
408        Mat_Shell *shell = (Mat_Shell*)mat->data;
409        shell->destroy                 = (int (*)(Mat)) f;
410     } else mat->ops->destroy            = (int (*)(Mat)) f;
411   }
412   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,PetscViewer)) f;
413   else                       (((void(**)(void))mat->ops)[op]) = f;
414 
415   PetscFunctionReturn(0);
416 }
417 
418 #undef __FUNCT__
419 #define __FUNCT__ "MatShellGetOperation"
420 /*@C
421     MatShellGetOperation - Gets a matrix function for a shell matrix.
422 
423     Not Collective
424 
425     Input Parameters:
426 +   mat - the shell matrix
427 -   op - the name of the operation
428 
429     Output Parameter:
430 .   f - the function that provides the operation.
431 
432     Level: advanced
433 
434     Notes:
435     See the file include/petscmat.h for a complete list of matrix
436     operations, which all have the form MATOP_<OPERATION>, where
437     <OPERATION> is the name (in all capital letters) of the
438     user interface routine (e.g., MatMult() -> MATOP_MULT).
439 
440     All user-provided functions have the same calling
441     sequence as the usual matrix interface routines, since they
442     are intended to be accessed via the usual matrix interface
443     routines, e.g.,
444 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
445 
446     Within each user-defined routine, the user should call
447     MatShellGetContext() to obtain the user-defined context that was
448     set by MatCreateShell().
449 
450 .keywords: matrix, shell, set, operation
451 
452 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation()
453 @*/
454 int MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
455 {
456   int        ierr;
457   PetscTruth flg;
458 
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(mat,MAT_COOKIE);
461   if (op == MATOP_DESTROY) {
462     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
463     if (flg) {
464       Mat_Shell *shell = (Mat_Shell*)mat->data;
465       *f = (void(*)(void))shell->destroy;
466     } else {
467       *f = (void(*)(void))mat->ops->destroy;
468     }
469   } else if (op == MATOP_VIEW) {
470     *f = (void(*)(void))mat->ops->view;
471   } else {
472     *f = (((void(**)(void))mat->ops)[op]);
473   }
474 
475   PetscFunctionReturn(0);
476 }
477 
478