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