xref: /petsc/src/mat/impls/shell/shell.c (revision b951964f0fc83ed405b88515d4693dd22c4dfee8)
1 #ifndef lint
2 static char vcid[] = "$Id: shell.c,v 1.42 1997/01/06 20:24:40 balay 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     Input Parameter:
28 .   mat - the matrix, should have been created with MatCreateShell()
29 
30     Output Parameter:
31 .   ctx - the user provided context
32 
33     Notes:
34     This routine is intended for use within various shell matrix routines,
35     as set with MatShellSetOperation().
36 
37 .keywords: matrix, shell, get, context
38 
39 .seealso: MatCreateShell(), MatShellSetOperation()
40 @*/
41 int MatShellGetContext(Mat mat,void **ctx)
42 {
43   PetscValidHeaderSpecific(mat,MAT_COOKIE);
44   if (mat->type != MATSHELL) *ctx = 0;
45   else                       *ctx = ((Mat_Shell *) (mat->data))->ctx;
46   return 0;
47 }
48 
49 #undef __FUNC__
50 #define __FUNC__ "MatGetSize_Shell"
51 static int MatGetSize_Shell(Mat mat,int *M,int *N)
52 {
53   Mat_Shell *shell = (Mat_Shell *) mat->data;
54   *M = shell->M; *N = shell->N;
55   return 0;
56 }
57 
58 #undef __FUNC__
59 #define __FUNC__ "MatGetLocalSize_Shell"
60 static int MatGetLocalSize_Shell(Mat mat,int *m,int *n)
61 {
62   Mat_Shell *shell = (Mat_Shell *) mat->data;
63   *m = shell->n; *n = shell->n;
64   return 0;
65 }
66 
67 #undef __FUNC__
68 #define __FUNC__ "MatDestroy_Shell"
69 static int MatDestroy_Shell(PetscObject obj)
70 {
71   int       ierr;
72   Mat       mat = (Mat) obj;
73   Mat_Shell *shell;
74 
75   shell = (Mat_Shell *) mat->data;
76   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
77   PetscFree(shell);
78   PLogObjectDestroy(mat);
79   PetscHeaderDestroy(mat);
80   return 0;
81 }
82 
83 #undef __FUNC__
84 #define __FUNC__ "MatConvert_Shell"
85 int MatConvert_Shell(Mat oldmat,MatType newtype, Mat *mat)
86 {
87   Vec      in,out;
88   int      ierr,i,M,m,size,*rows,start,end;
89   MPI_Comm comm;
90   Scalar   *array,zero = 0.0,one = 1.0;
91 
92   PetscValidHeaderSpecific(oldmat,MAT_COOKIE);
93   PetscValidPointer(mat);
94 
95   if (newtype != MATSEQDENSE || newtype != MATMPIDENSE) {
96     SETERRQ(PETSC_ERR_SUP,1,"Can only convert shell matrices to dense currently");
97   }
98   comm = oldmat->comm;
99 
100   MPI_Comm_size(comm,&size);
101 
102   ierr = MatGetOwnershipRange(oldmat,&start,&end); CHKERRQ(ierr);
103   ierr = VecCreateMPI(comm,end-start,PETSC_DECIDE,&in); CHKERRQ(ierr);
104   ierr = VecDuplicate(in,&out); CHKERRQ(ierr);
105   ierr = VecGetSize(in,&M); CHKERRQ(ierr);
106   ierr = VecGetLocalSize(in,&m); CHKERRQ(ierr);
107   rows = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(rows);
108   for ( i=0; i<m; i++ ) {rows[i] = start + i;}
109 
110   if (size == 1) {
111     ierr = MatCreateSeqDense(comm,M,M,PETSC_NULL,mat); CHKERRQ(ierr);
112   } else {
113     ierr = MatCreateMPIDense(comm,m,M,M,M,PETSC_NULL,mat); CHKERRQ(ierr);
114     /* ierr = MatCreateMPIAIJ(comm,m,m,M,M,0,0,0,0,mat); CHKERRQ(ierr); */
115   }
116 
117   for ( i=0; i<M; i++ ) {
118 
119     ierr = VecSet(&zero,in); CHKERRQ(ierr);
120     ierr = VecSetValues(in,1,&i,&one,INSERT_VALUES); CHKERRQ(ierr);
121     ierr = VecAssemblyBegin(in); CHKERRQ(ierr);
122     ierr = VecAssemblyEnd(in); CHKERRQ(ierr);
123 
124     ierr = MatMult(oldmat,in,out); CHKERRQ(ierr);
125 
126     ierr = VecGetArray(out,&array); CHKERRQ(ierr);
127     ierr = MatSetValues(*mat,m,rows,1,&i,array,INSERT_VALUES); CHKERRQ(ierr);
128     ierr = VecRestoreArray(out,&array); CHKERRQ(ierr);
129 
130   }
131   PetscFree(rows);
132   ierr = VecDestroy(in); CHKERRQ(ierr);
133   ierr = VecDestroy(out); CHKERRQ(ierr);
134   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
135   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
136   return 0;
137 }
138 
139 static int MatGetOwnershipRange_Shell(Mat mat, int *rstart,int *rend)
140 {
141   MPI_Scan(&mat->m,rend,1,MPI_INT,MPI_SUM,mat->comm);
142   *rstart = *rend - mat->m;
143   return 0;
144 }
145 
146 
147 
148 
149 static struct _MatOps MatOps = {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        MatGetSize_Shell,
180        MatGetLocalSize_Shell,
181        MatGetOwnershipRange_Shell,
182        0,
183        0,
184        0,
185        0,
186        MatConvert_Shell,
187        0 };
188 
189 #undef __FUNC__
190 #define __FUNC__ "MatCreateShell"
191 /*@C
192    MatCreateShell - Creates a new matrix class for use with a user-defined
193    private data storage format.
194 
195    Input Parameters:
196 .  comm - MPI communicator
197 .  m - number of local rows
198 .  n - number of local columns
199 .  M - number of global rows
200 .  N - number of global columns
201 .  ctx - pointer to data needed by the shell matrix routines
202 
203    Output Parameter:
204 .  A - the matrix
205 
206    Usage:
207 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
208 $    MatShellSetOperation(mat,MATOP_MULT,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 $     Mat A
230 $
231 $     VecCreate(comm,M,&y);
232 $     VecCreate(comm,N,&x);
233 $     VecGetLocalSize(y,&m);
234 $     MatCreateShell(comm,m,N,M,N,ctx,&A);
235 $     MatShellSetOperation(mat,MATOP_MULT,mult);
236 $     MatMult(A,x,y);
237 $     MatDestroy(A);
238 $     VecDestroy(y); VecDestroy(x);
239 $
240 
241 .keywords: matrix, shell, create
242 
243 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
244 @*/
245 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
246 {
247   Mat       B;
248   Mat_Shell *b;
249 
250   PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSHELL,comm);
251   PLogObjectCreate(B);
252   B->factor    = 0;
253   B->destroy   = MatDestroy_Shell;
254   B->assembled = PETSC_TRUE;
255   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
256 
257   b          = PetscNew(Mat_Shell); CHKPTRQ(b);
258   PetscMemzero(b,sizeof(Mat_Shell));
259   B->data   = (void *) b;
260   b->M = M; B->M = M;
261   b->N = N; B->N = N;
262   b->m = m; B->m = m;
263   b->n = n; B->n = n;
264   b->ctx     = ctx;
265   *A = B;
266   return 0;
267 }
268 
269 #undef __FUNC__
270 #define __FUNC__ "MatShellSetOperation"
271 /*@C
272     MatShellSetOperation - Allows user to set a matrix operation for
273                            a shell matrix.
274 
275     Input Parameters:
276 .   mat - the shell matrix
277 .   op - the name of the operation
278 .   f - the function that provides the operation.
279 
280     Usage:
281 $      extern int usermult(Mat,Vec,Vec);
282 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
283 $      ierr = MatShellSetOperation(A,MATOP_MULT,usermult);
284 
285     Notes:
286     See the file petsc/include/mat.h for a complete list of matrix
287     operations, which all have the form MATOP_<OPERATION>, where
288     <OPERATION> is the name (in all capital letters) of the
289     user interface routine (e.g., MatMult() -> MATOP_MULT).
290 
291     All user-provided functions should have the same calling
292     sequence as the usual matrix interface routines, since they
293     are intended to be accessed via the usual matrix interface
294     routines, e.g.,
295 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
296 
297     Within each user-defined routine, the user should call
298     MatShellGetContext() to obtain the user-defined context that was
299     set by MatCreateShell().
300 
301 .keywords: matrix, shell, set, operation
302 
303 .seealso: MatCreateShell(), MatShellGetContext()
304 @*/
305 int MatShellSetOperation(Mat mat,MatOperation op, void *f)
306 {
307   PetscValidHeaderSpecific(mat,MAT_COOKIE);
308 
309   if (op == MATOP_DESTROY) {
310     if (mat->type == MATSHELL) {
311        Mat_Shell *shell = (Mat_Shell *) mat->data;
312        shell->destroy                 = (int (*)(Mat)) f;
313     }
314     else mat->destroy                 = (int (*)(PetscObject)) f;
315   }
316   else if (op == MATOP_VIEW) mat->view  = (int (*)(PetscObject,Viewer)) f;
317   else      (((void**)&mat->ops)[op]) = f;
318 
319   return 0;
320 }
321 
322 
323 
324