xref: /petsc/src/mat/impls/shell/shell.c (revision b0a32e0c6855ee6a6cd3495fa7da12ea9885bc5d)
1 /*$Id: shell.c,v 1.83 2000/10/24 20:25:38 bsmith Exp bsmith $*/
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   void *ctx;
15 } Mat_Shell;
16 
17 #undef __FUNC__
18 #define __FUNC__ "MatShellGetContext"
19 /*@
20     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
21 
22     Not Collective
23 
24     Input Parameter:
25 .   mat - the matrix, should have been created with MatCreateShell()
26 
27     Output Parameter:
28 .   ctx - the user provided context
29 
30     Level: advanced
31 
32     Notes:
33     This routine is intended for use within various shell matrix routines,
34     as set with MatShellSetOperation().
35 
36 .keywords: matrix, shell, get, context
37 
38 .seealso: MatCreateShell(), MatShellSetOperation()
39 @*/
40 int MatShellGetContext(Mat mat,void **ctx)
41 {
42   int        ierr;
43   PetscTruth flg;
44 
45   PetscFunctionBegin;
46   PetscValidHeaderSpecific(mat,MAT_COOKIE);
47   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
48   if (!flg) *ctx = 0;
49   else      *ctx = ((Mat_Shell*)(mat->data))->ctx;
50   PetscFunctionReturn(0);
51 }
52 
53 #undef __FUNC__
54 #define __FUNC__ "MatDestroy_Shell"
55 int MatDestroy_Shell(Mat mat)
56 {
57   int       ierr;
58   Mat_Shell *shell;
59 
60   PetscFunctionBegin;
61   shell = (Mat_Shell*)mat->data;
62   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
63   ierr = PetscFree(shell);CHKERRQ(ierr);
64   PetscFunctionReturn(0);
65 }
66 
67 #undef __FUNC__
68 #define __FUNC__ "MatGetOwnershipRange_Shell"
69 int MatGetOwnershipRange_Shell(Mat mat,int *rstart,int *rend)
70 {
71   int ierr,tmp;
72 
73   PetscFunctionBegin;
74   ierr = MPI_Scan(&mat->m,&tmp,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr);
75   if (rstart) *rstart = tmp - mat->m;
76   if (rend)   *rend   = tmp;
77   PetscFunctionReturn(0);
78 }
79 extern int MatConvert_Shell(Mat,MatType,Mat*);
80 
81 static struct _MatOps MatOps_Values = {0,
82        0,
83        0,
84        0,
85        0,
86        0,
87        0,
88        0,
89        0,
90        0,
91        0,
92        0,
93        0,
94        0,
95        0,
96        0,
97        0,
98        0,
99        0,
100        0,
101        0,
102        0,
103        0,
104        0,
105        0,
106        0,
107        0,
108        0,
109        0,
110        0,
111        0,
112        MatGetOwnershipRange_Shell,
113        0,
114        0,
115        0,
116        0,
117        0,
118        0,
119        0,
120        0,
121        0,
122        0,
123        0,
124        0,
125        0,
126        0,
127        0,
128        0,
129        0,
130        0,
131        0,
132        0,
133        0,
134        0,
135        0,
136        0,
137        0,
138        0,
139        0,
140        0,
141        0,
142        0,
143        0,
144        MatDestroy_Shell,
145        0,
146        MatGetMaps_Petsc,
147        0,
148        0,
149        0,
150        0,
151        0,
152        0,
153        0,
154        MatConvert_Shell};
155 
156 EXTERN_C_BEGIN
157 #undef __FUNC__
158 #define __FUNC__ "MatCreate_Shell"
159 int MatCreate_Shell(Mat A)
160 {
161   Mat_Shell *b;
162   int       ierr;
163 
164   PetscFunctionBegin;
165   ierr            = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
166 
167   ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr);
168   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
169   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
170   A->data = (void*)b;
171 
172   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
173     SETERRQ(1,"Must give local row and column count for matrix");
174   }
175 
176   ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr);
177   ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr);
178 
179   ierr = MapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr);
180   ierr = MapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr);
181 
182   b->ctx = 0;
183   A->assembled    = PETSC_TRUE;
184   A->preallocated = PETSC_TRUE;
185   PetscFunctionReturn(0);
186 }
187 EXTERN_C_END
188 
189 #undef __FUNC__
190 #define __FUNC__ "MatCreateShell"
191 /*@C
192    MatCreateShell - Creates a new matrix class for use with a user-defined
193    private data storage format.
194 
195   Collective on MPI_Comm
196 
197    Input Parameters:
198 +  comm - MPI communicator
199 .  m - number of local rows (must be given)
200 .  n - number of local columns (must be given)
201 .  M - number of global rows (may be PETSC_DETERMINE)
202 .  N - number of global columns (may be PETSC_DETERMINE)
203 -  ctx - pointer to data needed by the shell matrix routines
204 
205    Output Parameter:
206 .  A - the matrix
207 
208    Level: advanced
209 
210   Usage:
211 $    extern int mult(Mat,Vec,Vec);
212 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
213 $    MatShellSetOperation(mat,MATOP_MULT,(void *)mult);
214 $    [ Use matrix for operations that have been set ]
215 $    MatDestroy(mat);
216 
217    Notes:
218    The shell matrix type is intended to provide a simple class to use
219    with KSP (such as, for use with matrix-free methods). You should not
220    use the shell type if you plan to define a complete matrix class.
221 
222    PETSc requires that matrices and vectors being used for certain
223    operations are partitioned accordingly.  For example, when
224    creating a shell matrix, A, that supports parallel matrix-vector
225    products using MatMult(A,x,y) the user should set the number
226    of local matrix rows to be the number of local elements of the
227    corresponding result vector, y. Note that this is information is
228    required for use of the matrix interface routines, even though
229    the shell matrix may not actually be physically partitioned.
230    For example,
231 
232 $
233 $     Vec x, y
234 $     extern int mult(Mat,Vec,Vec);
235 $     Mat A
236 $
237 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
238 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
239 $     VecGetLocalSize(y,&m);
240 $     VecGetLocalSize(x,&n);
241 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
242 $     MatShellSetOperation(mat,MATOP_MULT,(void *)mult);
243 $     MatMult(A,x,y);
244 $     MatDestroy(A);
245 $     VecDestroy(y); VecDestroy(x);
246 $
247 
248 .keywords: matrix, shell, create
249 
250 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
251 @*/
252 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
253 {
254   int       ierr;
255 
256   PetscFunctionBegin;
257   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
258   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
259   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
260   PetscFunctionReturn(0);
261 }
262 
263 #undef __FUNC__
264 #define __FUNC__ "MatShellSetContext"
265 /*@C
266     MatShellSetContext - sets the context for a shell matrix
267 
268    Collective on Mat
269 
270     Input Parameters:
271 +   mat - the shell matrix
272 -   ctx - the context
273 
274    Level: advanced
275 
276 
277 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
278 @*/
279 int MatShellSetContext(Mat mat,void *ctx)
280 {
281   Mat_Shell  *shell = (Mat_Shell*)mat->data;
282   int        ierr;
283   PetscTruth flg;
284 
285   PetscFunctionBegin;
286   PetscValidHeaderSpecific(mat,MAT_COOKIE);
287   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
288   if (flg) {
289     shell->ctx = ctx;
290   }
291   PetscFunctionReturn(0);
292 }
293 
294 #undef __FUNC__
295 #define __FUNC__ "MatShellSetOperation"
296 /*@C
297     MatShellSetOperation - Allows user to set a matrix operation for
298                            a shell matrix.
299 
300    Collective on Mat
301 
302     Input Parameters:
303 +   mat - the shell matrix
304 .   op - the name of the operation
305 -   f - the function that provides the operation.
306 
307    Level: advanced
308 
309     Usage:
310 $      extern int usermult(Mat,Vec,Vec);
311 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
312 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void*) usermult);
313 
314     Notes:
315     See the file include/petscmat.h for a complete list of matrix
316     operations, which all have the form MATOP_<OPERATION>, where
317     <OPERATION> is the name (in all capital letters) of the
318     user interface routine (e.g., MatMult() -> MATOP_MULT).
319 
320     All user-provided functions should have the same calling
321     sequence as the usual matrix interface routines, since they
322     are intended to be accessed via the usual matrix interface
323     routines, e.g.,
324 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
325 
326     Within each user-defined routine, the user should call
327     MatShellGetContext() to obtain the user-defined context that was
328     set by MatCreateShell().
329 
330 .keywords: matrix, shell, set, operation
331 
332 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
333 @*/
334 int MatShellSetOperation(Mat mat,MatOperation op,void *f)
335 {
336   int        ierr;
337   PetscTruth flg;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(mat,MAT_COOKIE);
341   if (op == MATOP_DESTROY) {
342     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
343     if (flg) {
344        Mat_Shell *shell = (Mat_Shell*)mat->data;
345        shell->destroy                 = (int (*)(Mat)) f;
346     } else mat->ops->destroy            = (int (*)(Mat)) f;
347   }
348   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,PetscViewer)) f;
349   else                       (((void**)mat->ops)[op]) = f;
350 
351   PetscFunctionReturn(0);
352 }
353 
354 #undef __FUNC__
355 #define __FUNC__ "MatShellGetOperation"
356 /*@C
357     MatShellGetOperation - Gets a matrix function for a shell matrix.
358 
359     Not Collective
360 
361     Input Parameters:
362 +   mat - the shell matrix
363 -   op - the name of the operation
364 
365     Output Parameter:
366 .   f - the function that provides the operation.
367 
368     Level: advanced
369 
370     Notes:
371     See the file include/petscmat.h for a complete list of matrix
372     operations, which all have the form MATOP_<OPERATION>, where
373     <OPERATION> is the name (in all capital letters) of the
374     user interface routine (e.g., MatMult() -> MATOP_MULT).
375 
376     All user-provided functions have the same calling
377     sequence as the usual matrix interface routines, since they
378     are intended to be accessed via the usual matrix interface
379     routines, e.g.,
380 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
381 
382     Within each user-defined routine, the user should call
383     MatShellGetContext() to obtain the user-defined context that was
384     set by MatCreateShell().
385 
386 .keywords: matrix, shell, set, operation
387 
388 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation()
389 @*/
390 int MatShellGetOperation(Mat mat,MatOperation op,void **f)
391 {
392   int        ierr;
393   PetscTruth flg;
394 
395   PetscFunctionBegin;
396   PetscValidHeaderSpecific(mat,MAT_COOKIE);
397   if (op == MATOP_DESTROY) {
398     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
399     if (flg) {
400       Mat_Shell *shell = (Mat_Shell*)mat->data;
401       *f = (void*)shell->destroy;
402     } else {
403       *f = (void*)mat->ops->destroy;
404     }
405   } else if (op == MATOP_VIEW) {
406     *f = (void*)mat->ops->view;
407   } else {
408     *f = (((void**)mat->ops)[op]);
409   }
410 
411   PetscFunctionReturn(0);
412 }
413 
414