xref: /petsc/src/mat/impls/shell/shell.c (revision c7fcc2eafc245811be4a49a6c2d749b53b1601d3)
1 #ifdef PETSC_RCS_HEADER
2 static char vcid[] = "$Id: shell.c,v 1.59 1998/07/14 02:34:52 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     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   PetscFunctionBegin;
46   PetscValidHeaderSpecific(mat,MAT_COOKIE);
47   if (mat->type != MATSHELL) *ctx = 0;
48   else                       *ctx = ((Mat_Shell *) (mat->data))->ctx;
49   PetscFunctionReturn(0);
50 }
51 
52 #undef __FUNC__
53 #define __FUNC__ "MatGetSize_Shell"
54 int MatGetSize_Shell(Mat mat,int *M,int *N)
55 {
56   Mat_Shell *shell = (Mat_Shell *) mat->data;
57 
58   PetscFunctionBegin;
59   if (M) *M = shell->M;
60   if (N) *N = shell->N;
61   PetscFunctionReturn(0);
62 }
63 
64 #undef __FUNC__
65 #define __FUNC__ "MatGetLocalSize_Shell"
66 int MatGetLocalSize_Shell(Mat mat,int *m,int *n)
67 {
68   Mat_Shell *shell = (Mat_Shell *) mat->data;
69 
70   PetscFunctionBegin;
71   if (m) *m = shell->m;
72   if (n) *n = shell->n;
73   PetscFunctionReturn(0);
74 }
75 
76 #undef __FUNC__
77 #define __FUNC__ "MatDestroy_Shell"
78 int MatDestroy_Shell(Mat mat)
79 {
80   int       ierr;
81   Mat_Shell *shell;
82 
83   PetscFunctionBegin;
84   if (--mat->refct > 0) PetscFunctionReturn(0);
85 
86   if (mat->mapping) {
87     ierr = ISLocalToGlobalMappingDestroy(mat->mapping); CHKERRQ(ierr);
88   }
89   if (mat->bmapping) {
90     ierr = ISLocalToGlobalMappingDestroy(mat->bmapping); CHKERRQ(ierr);
91   }
92   if (mat->rmap) {
93     ierr = MapDestroy(mat->rmap);CHKERRQ(ierr);
94   }
95   if (mat->cmap) {
96     ierr = MapDestroy(mat->cmap);CHKERRQ(ierr);
97   }
98   shell = (Mat_Shell *) mat->data;
99   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
100   PetscFree(shell);
101   PLogObjectDestroy(mat);
102   PetscHeaderDestroy(mat);
103   PetscFunctionReturn(0);
104 }
105 
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   Usage:
203 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
204 $    MatShellSetOperation(mat,MATOP_MULT,mult);
205 $    [ Use matrix for operations that have been set ]
206 $    MatDestroy(mat);
207 
208    Notes:
209    The shell matrix type is intended to provide a simple class to use
210    with KSP (such as, for use with matrix-free methods). You should not
211    use the shell type if you plan to define a complete matrix class.
212 
213    PETSc requires that matrices and vectors being used for certain
214    operations are partitioned accordingly.  For example, when
215    creating a shell matrix, A, that supports parallel matrix-vector
216    products using MatMult(A,x,y) the user should set the number
217    of local matrix rows to be the number of local elements of the
218    corresponding result vector, y. Note that this is information is
219    required for use of the matrix interface routines, even though
220    the shell matrix may not actually be physically partitioned.
221    For example,
222 
223 $
224 $     Vec x, y
225 $     Mat A
226 $
227 $     VecCreate(comm,PETSC_DECIDE,M,&y);
228 $     VecCreate(comm,PETSC_DECIDE,N,&x);
229 $     VecGetLocalSize(y,&m);
230 $     VecGetLocalSize(x,&n);
231 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
232 $     MatShellSetOperation(mat,MATOP_MULT,mult);
233 $     MatMult(A,x,y);
234 $     MatDestroy(A);
235 $     VecDestroy(y); VecDestroy(x);
236 $
237 
238 .keywords: matrix, shell, create
239 
240 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
241 @*/
242 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
243 {
244   Mat       B;
245   Mat_Shell *b;
246   int       ierr;
247 
248   PetscFunctionBegin;
249   PetscHeaderCreate(B,_p_Mat,struct _MatOps,MAT_COOKIE,MATSHELL,comm,MatDestroy,MatView);
250   PLogObjectCreate(B);
251   B->factor    = 0;
252   B->assembled = PETSC_TRUE;
253   PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));
254   B->ops->destroy   = MatDestroy_Shell;
255 
256   b          = PetscNew(Mat_Shell); CHKPTRQ(b);
257   PLogObjectMemory(B,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
258   PetscMemzero(b,sizeof(Mat_Shell));
259   B->data   = (void *) b;
260 
261   if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
262     SETERRQ(1,1,"Must give local row and column count for matrix");
263   }
264 
265   if (M == PETSC_DETERMINE || N == PETSC_DETERMINE) {
266     int work[2], sum[2];
267 
268     work[0] = m; work[1] = n;
269     ierr = MPI_Allreduce( work, sum,2,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
270     if (M == PETSC_DECIDE) M = sum[0];
271     if (N == PETSC_DECIDE) N = sum[1];
272   }
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 = MapCreate(comm,m,M,B->rmap);CHKERRQ(ierr);
279   ierr = MapCreate(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     Usage:
300 $      extern int usermult(Mat,Vec,Vec);
301 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
302 $      ierr = MatShellSetOperation(A,MATOP_MULT,usermult);
303 
304     Notes:
305     See the file petsc/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     }
334     else mat->ops->destroy            = (int (*)(Mat)) f;
335   }
336   else if (op == MATOP_VIEW) mat->ops->view  = (int (*)(Mat,Viewer)) f;
337   else      (((void**)mat->ops)[op]) = f;
338 
339   PetscFunctionReturn(0);
340 }
341 
342 #undef __FUNC__
343 #define __FUNC__ "MatShellGetOperation"
344 /*@C
345     MatShellGetOperation - Gets a matrix function for a shell matrix.
346 
347     Not Collective
348 
349     Input Parameters:
350 +   mat - the shell matrix
351 -   op - the name of the operation
352 
353     Output Parameter:
354 .   f - the function that provides the operation.
355 
356     Notes:
357     See the file petsc/include/mat.h for a complete list of matrix
358     operations, which all have the form MATOP_<OPERATION>, where
359     <OPERATION> is the name (in all capital letters) of the
360     user interface routine (e.g., MatMult() -> MATOP_MULT).
361 
362     All user-provided functions have the same calling
363     sequence as the usual matrix interface routines, since they
364     are intended to be accessed via the usual matrix interface
365     routines, e.g.,
366 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
367 
368     Within each user-defined routine, the user should call
369     MatShellGetContext() to obtain the user-defined context that was
370     set by MatCreateShell().
371 
372 .keywords: matrix, shell, set, operation
373 
374 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation()
375 @*/
376 int MatShellGetOperation(Mat mat,MatOperation op, void **f)
377 {
378   PetscFunctionBegin;
379   PetscValidHeaderSpecific(mat,MAT_COOKIE);
380 
381   if (op == MATOP_DESTROY) {
382     if (mat->type == MATSHELL) {
383       Mat_Shell *shell = (Mat_Shell *) mat->data;
384       *f = (void *) shell->destroy;
385     } else {
386       *f = (void *) mat->ops->destroy;
387     }
388   } else if (op == MATOP_VIEW) {
389     *f = (void *) mat->ops->view;
390   } else {
391     *f = (((void**)&mat->ops)[op]);
392   }
393 
394   PetscFunctionReturn(0);
395 }
396 
397