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