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