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