xref: /petsc/src/mat/impls/shell/shell.c (revision 549d3d68a6ae470532d58d544870024f02ff2d7c)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: shell.c,v 1.68 1999/03/31 18:41:23 bsmith Exp balay $";
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   if (--mat->refct > 0) PetscFunctionReturn(0);
87 
88   if (mat->mapping) {
89     ierr = ISLocalToGlobalMappingDestroy(mat->mapping);CHKERRQ(ierr);
90   }
91   if (mat->bmapping) {
92     ierr = ISLocalToGlobalMappingDestroy(mat->bmapping);CHKERRQ(ierr);
93   }
94   if (mat->rmap) {
95     ierr = MapDestroy(mat->rmap);CHKERRQ(ierr);
96   }
97   if (mat->cmap) {
98     ierr = MapDestroy(mat->cmap);CHKERRQ(ierr);
99   }
100   shell = (Mat_Shell *) mat->data;
101   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
102   PetscFree(shell);
103   PLogObjectDestroy(mat);
104   PetscHeaderDestroy(mat);
105   PetscFunctionReturn(0);
106 }
107 
108 int MatGetOwnershipRange_Shell(Mat mat, int *rstart,int *rend)
109 {
110   int ierr;
111 
112   PetscFunctionBegin;
113   ierr = MPI_Scan(&mat->m,rend,1,MPI_INT,MPI_SUM,mat->comm);CHKERRQ(ierr);
114   *rstart = *rend - mat->m;
115   PetscFunctionReturn(0);
116 }
117 
118 static struct _MatOps MatOps_Values = {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        0,
145        0,
146        0,
147        0,
148        MatGetSize_Shell,
149        MatGetLocalSize_Shell,
150        MatGetOwnershipRange_Shell,
151        0,
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        MatGetMaps_Petsc};
184 
185 #undef __FUNC__
186 #define __FUNC__ "MatCreateShell"
187 /*@C
188    MatCreateShell - Creates a new matrix class for use with a user-defined
189    private data storage format.
190 
191   Collective on MPI_Comm
192 
193    Input Parameters:
194 +  comm - MPI communicator
195 .  m - number of local rows (must be given)
196 .  n - number of local columns (must be given)
197 .  M - number of global rows (may be PETSC_DETERMINE)
198 .  N - number of global columns (may be PETSC_DETERMINE)
199 -  ctx - pointer to data needed by the shell matrix routines
200 
201    Output Parameter:
202 .  A - the matrix
203 
204    Level: advanced
205 
206   Usage:
207 $    extern int mult(Mat,Vec,Vec);
208 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
209 $    MatShellSetOperation(mat,MATOP_MULT,(void *)mult);
210 $    [ Use matrix for operations that have been set ]
211 $    MatDestroy(mat);
212 
213    Notes:
214    The shell matrix type is intended to provide a simple class to use
215    with KSP (such as, for use with matrix-free methods). You should not
216    use the shell type if you plan to define a complete matrix class.
217 
218    PETSc requires that matrices and vectors being used for certain
219    operations are partitioned accordingly.  For example, when
220    creating a shell matrix, A, that supports parallel matrix-vector
221    products using MatMult(A,x,y) the user should set the number
222    of local matrix rows to be the number of local elements of the
223    corresponding result vector, y. Note that this is information is
224    required for use of the matrix interface routines, even though
225    the shell matrix may not actually be physically partitioned.
226    For example,
227 
228 $
229 $     Vec x, y
230 $     extern int mult(Mat,Vec,Vec);
231 $     Mat A
232 $
233 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
234 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
235 $     VecGetLocalSize(y,&m);
236 $     VecGetLocalSize(x,&n);
237 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
238 $     MatShellSetOperation(mat,MATOP_MULT,(void *)mult);
239 $     MatMult(A,x,y);
240 $     MatDestroy(A);
241 $     VecDestroy(y); VecDestroy(x);
242 $
243 
244 .keywords: matrix, shell, create
245 
246 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
247 @*/
248 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
249 {
250   Mat       B;
251   Mat_Shell *b;
252   int       ierr;
253 
254   PetscFunctionBegin;
255   PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,"Mat",comm,MatDestroy,MatView);
256   PLogObjectCreate(B);
257   B->factor       = 0;
258   B->assembled    = PETSC_TRUE;
259   ierr            = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
260   B->ops->destroy = MatDestroy_Shell;
261 
262   b       = PetscNew(Mat_Shell);CHKPTRQ(b);
263   PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
264   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
265   B->data = (void *) b;
266 
267   if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
268     SETERRQ(1,1,"Must give local row and column count for matrix");
269   }
270 
271   ierr = PetscSplitOwnership(comm,&m,&M);CHKERRQ(ierr);
272   ierr = PetscSplitOwnership(comm,&n,&N);CHKERRQ(ierr);
273   b->M = M; B->M = M;
274   b->N = N; B->N = N;
275   b->m = m; B->m = m;
276   b->n = n; B->n = n;
277 
278   ierr = MapCreateMPI(comm,m,M,&B->rmap);CHKERRQ(ierr);
279   ierr = MapCreateMPI(comm,n,N,&B->cmap);CHKERRQ(ierr);
280 
281   b->ctx = ctx;
282   *A     = B;
283   PetscFunctionReturn(0);
284 }
285 
286 #undef __FUNC__
287 #define __FUNC__ "MatShellSetOperation"
288 /*@C
289     MatShellSetOperation - Allows user to set a matrix operation for
290                            a shell matrix.
291 
292    Collective on Mat
293 
294     Input Parameters:
295 +   mat - the shell matrix
296 .   op - the name of the operation
297 -   f - the function that provides the operation.
298 
299    Level: advanced
300 
301     Usage:
302 $      extern int usermult(Mat,Vec,Vec);
303 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
304 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void*) usermult);
305 
306     Notes:
307     See the file include/mat.h for a complete list of matrix
308     operations, which all have the form MATOP_<OPERATION>, where
309     <OPERATION> is the name (in all capital letters) of the
310     user interface routine (e.g., MatMult() -> MATOP_MULT).
311 
312     All user-provided functions should have the same calling
313     sequence as the usual matrix interface routines, since they
314     are intended to be accessed via the usual matrix interface
315     routines, e.g.,
316 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
317 
318     Within each user-defined routine, the user should call
319     MatShellGetContext() to obtain the user-defined context that was
320     set by MatCreateShell().
321 
322 .keywords: matrix, shell, set, operation
323 
324 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
325 @*/
326 int MatShellSetOperation(Mat mat,MatOperation op, void *f)
327 {
328   PetscFunctionBegin;
329   PetscValidHeaderSpecific(mat,MAT_COOKIE);
330 
331   if (op == MATOP_DESTROY) {
332     if (mat->type == MATSHELL) {
333        Mat_Shell *shell = (Mat_Shell *) mat->data;
334        shell->destroy                 = (int (*)(Mat)) f;
335     }
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