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