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