xref: /petsc/src/mat/impls/shell/shellcnv.c (revision 6098dc10f64a9429b4a6e4cb977ddd6c38617718)
1 #ifndef lint
2 static char vcid[] = "$Id: shell.c,v 1.43 1997/01/12 04:33:57 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     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        0 };
187 
188 #undef __FUNC__
189 #define __FUNC__ "MatCreateShell"
190 /*@C
191    MatCreateShell - Creates a new matrix class for use with a user-defined
192    private data storage format.
193 
194    Input Parameters:
195 .  comm - MPI communicator
196 .  m - number of local rows
197 .  n - number of local columns
198 .  M - number of global rows
199 .  N - number of global columns
200 .  ctx - pointer to data needed by the shell matrix routines
201 
202    Output Parameter:
203 .  A - the matrix
204 
205    Usage:
206 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
207 $    MatShellSetOperation(mat,MATOP_MULT,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 $     Mat A
229 $
230 $     VecCreate(comm,M,&y);
231 $     VecCreate(comm,N,&x);
232 $     VecGetLocalSize(y,&m);
233 $     MatCreateShell(comm,m,N,M,N,ctx,&A);
234 $     MatShellSetOperation(mat,MATOP_MULT,mult);
235 $     MatMult(A,x,y);
236 $     MatDestroy(A);
237 $     VecDestroy(y); VecDestroy(x);
238 $
239 
240 .keywords: matrix, shell, create
241 
242 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
243 @*/
244 int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
245 {
246   Mat       B;
247   Mat_Shell *b;
248 
249   PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSHELL,comm);
250   PLogObjectCreate(B);
251   B->factor    = 0;
252   B->destroy   = MatDestroy_Shell;
253   B->assembled = PETSC_TRUE;
254   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
255 
256   b          = PetscNew(Mat_Shell); CHKPTRQ(b);
257   PetscMemzero(b,sizeof(Mat_Shell));
258   B->data   = (void *) b;
259   b->M = M; B->M = M;
260   b->N = N; B->N = N;
261   b->m = m; B->m = m;
262   b->n = n; B->n = n;
263   b->ctx     = ctx;
264   *A = B;
265   return 0;
266 }
267 
268 #undef __FUNC__
269 #define __FUNC__ "MatShellSetOperation"
270 /*@C
271     MatShellSetOperation - Allows user to set a matrix operation for
272                            a shell matrix.
273 
274     Input Parameters:
275 .   mat - the shell matrix
276 .   op - the name of the operation
277 .   f - the function that provides the operation.
278 
279     Usage:
280 $      extern int usermult(Mat,Vec,Vec);
281 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
282 $      ierr = MatShellSetOperation(A,MATOP_MULT,usermult);
283 
284     Notes:
285     See the file petsc/include/mat.h for a complete list of matrix
286     operations, which all have the form MATOP_<OPERATION>, where
287     <OPERATION> is the name (in all capital letters) of the
288     user interface routine (e.g., MatMult() -> MATOP_MULT).
289 
290     All user-provided functions should have the same calling
291     sequence as the usual matrix interface routines, since they
292     are intended to be accessed via the usual matrix interface
293     routines, e.g.,
294 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
295 
296     Within each user-defined routine, the user should call
297     MatShellGetContext() to obtain the user-defined context that was
298     set by MatCreateShell().
299 
300 .keywords: matrix, shell, set, operation
301 
302 .seealso: MatCreateShell(), MatShellGetContext()
303 @*/
304 int MatShellSetOperation(Mat mat,MatOperation op, void *f)
305 {
306   PetscValidHeaderSpecific(mat,MAT_COOKIE);
307 
308   if (op == MATOP_DESTROY) {
309     if (mat->type == MATSHELL) {
310        Mat_Shell *shell = (Mat_Shell *) mat->data;
311        shell->destroy                 = (int (*)(Mat)) f;
312     }
313     else mat->destroy                 = (int (*)(PetscObject)) f;
314   }
315   else if (op == MATOP_VIEW) mat->view  = (int (*)(PetscObject,Viewer)) f;
316   else      (((void**)&mat->ops)[op]) = f;
317 
318   return 0;
319 }
320 
321 
322 
323