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