xref: /petsc/src/mat/impls/shell/shell.c (revision b951964f0fc83ed405b88515d4693dd22c4dfee8)
1357feee3SLois Curfman McInnes #ifndef lint
2*b951964fSBarry Smith static char vcid[] = "$Id: shell.c,v 1.42 1997/01/06 20:24:40 balay Exp bsmith $";
3357feee3SLois Curfman McInnes #endif
4e51e0e81SBarry Smith 
5e51e0e81SBarry Smith /*
620563c6bSBarry Smith    This provides a simple shell for Fortran (and C programmers) to
720563c6bSBarry Smith   create a very simple matrix class for use with KSP without coding
8ed3cc1f0SBarry Smith   much of anything.
9e51e0e81SBarry Smith */
10e51e0e81SBarry Smith 
11e51e0e81SBarry Smith #include "petsc.h"
1270f55243SBarry Smith #include "src/mat/matimpl.h"        /*I "mat.h" I*/
13f5eb4b81SSatish Balay #include "src/vec/vecimpl.h"
14e51e0e81SBarry Smith 
1520563c6bSBarry Smith typedef struct {
16f39d1f56SLois Curfman McInnes   int  M, N;                  /* number of global rows, columns */
17f39d1f56SLois Curfman McInnes   int  m, n;                  /* number of local rows, columns */
183a3eedf2SBarry Smith   int  (*destroy)(Mat);
1920563c6bSBarry Smith   void *ctx;
2088cf3e7dSBarry Smith } Mat_Shell;
21e51e0e81SBarry Smith 
225615d1e5SSatish Balay #undef __FUNC__
235615d1e5SSatish Balay #define __FUNC__ "MatShellGetContext"
24b4fd4287SBarry Smith /*@
25a62d957aSLois Curfman McInnes     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
26b4fd4287SBarry Smith 
27b4fd4287SBarry Smith     Input Parameter:
28b4fd4287SBarry Smith .   mat - the matrix, should have been created with MatCreateShell()
29b4fd4287SBarry Smith 
30b4fd4287SBarry Smith     Output Parameter:
31b4fd4287SBarry Smith .   ctx - the user provided context
32b4fd4287SBarry Smith 
33a62d957aSLois Curfman McInnes     Notes:
34a62d957aSLois Curfman McInnes     This routine is intended for use within various shell matrix routines,
35a62d957aSLois Curfman McInnes     as set with MatShellSetOperation().
36a62d957aSLois Curfman McInnes 
37a62d957aSLois Curfman McInnes .keywords: matrix, shell, get, context
38a62d957aSLois Curfman McInnes 
39a62d957aSLois Curfman McInnes .seealso: MatCreateShell(), MatShellSetOperation()
40b4fd4287SBarry Smith @*/
41b4fd4287SBarry Smith int MatShellGetContext(Mat mat,void **ctx)
42b4fd4287SBarry Smith {
4377c4ece6SBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
44b4fd4287SBarry Smith   if (mat->type != MATSHELL) *ctx = 0;
45b4fd4287SBarry Smith   else                       *ctx = ((Mat_Shell *) (mat->data))->ctx;
46b4fd4287SBarry Smith   return 0;
47b4fd4287SBarry Smith }
48b4fd4287SBarry Smith 
495615d1e5SSatish Balay #undef __FUNC__
505615d1e5SSatish Balay #define __FUNC__ "MatGetSize_Shell"
51f39d1f56SLois Curfman McInnes static int MatGetSize_Shell(Mat mat,int *M,int *N)
5271b459e3SLois Curfman McInnes {
5371b459e3SLois Curfman McInnes   Mat_Shell *shell = (Mat_Shell *) mat->data;
54f39d1f56SLois Curfman McInnes   *M = shell->M; *N = shell->N;
55f39d1f56SLois Curfman McInnes   return 0;
56f39d1f56SLois Curfman McInnes }
57f39d1f56SLois Curfman McInnes 
585615d1e5SSatish Balay #undef __FUNC__
595615d1e5SSatish Balay #define __FUNC__ "MatGetLocalSize_Shell"
60f39d1f56SLois Curfman McInnes static int MatGetLocalSize_Shell(Mat mat,int *m,int *n)
61f39d1f56SLois Curfman McInnes {
62f39d1f56SLois Curfman McInnes   Mat_Shell *shell = (Mat_Shell *) mat->data;
63f39d1f56SLois Curfman McInnes   *m = shell->n; *n = shell->n;
6471b459e3SLois Curfman McInnes   return 0;
6571b459e3SLois Curfman McInnes }
6671b459e3SLois Curfman McInnes 
675615d1e5SSatish Balay #undef __FUNC__
685615d1e5SSatish Balay #define __FUNC__ "MatDestroy_Shell"
6988cf3e7dSBarry Smith static int MatDestroy_Shell(PetscObject obj)
70e51e0e81SBarry Smith {
71b9fa9cd0SBarry Smith   int       ierr;
7220563c6bSBarry Smith   Mat       mat = (Mat) obj;
7388cf3e7dSBarry Smith   Mat_Shell *shell;
74ed3cc1f0SBarry Smith 
7588cf3e7dSBarry Smith   shell = (Mat_Shell *) mat->data;
763a3eedf2SBarry Smith   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
770452661fSBarry Smith   PetscFree(shell);
783a3eedf2SBarry Smith   PLogObjectDestroy(mat);
793a3eedf2SBarry Smith   PetscHeaderDestroy(mat);
80e51e0e81SBarry Smith   return 0;
81e51e0e81SBarry Smith }
82e51e0e81SBarry Smith 
83*b951964fSBarry Smith #undef __FUNC__
84*b951964fSBarry Smith #define __FUNC__ "MatConvert_Shell"
85*b951964fSBarry Smith int MatConvert_Shell(Mat oldmat,MatType newtype, Mat *mat)
86*b951964fSBarry Smith {
87*b951964fSBarry Smith   Vec      in,out;
88*b951964fSBarry Smith   int      ierr,i,M,m,size,*rows,start,end;
89*b951964fSBarry Smith   MPI_Comm comm;
90*b951964fSBarry Smith   Scalar   *array,zero = 0.0,one = 1.0;
91*b951964fSBarry Smith 
92*b951964fSBarry Smith   PetscValidHeaderSpecific(oldmat,MAT_COOKIE);
93*b951964fSBarry Smith   PetscValidPointer(mat);
94*b951964fSBarry Smith 
95*b951964fSBarry Smith   if (newtype != MATSEQDENSE || newtype != MATMPIDENSE) {
96*b951964fSBarry Smith     SETERRQ(PETSC_ERR_SUP,1,"Can only convert shell matrices to dense currently");
97*b951964fSBarry Smith   }
98*b951964fSBarry Smith   comm = oldmat->comm;
99*b951964fSBarry Smith 
100*b951964fSBarry Smith   MPI_Comm_size(comm,&size);
101*b951964fSBarry Smith 
102*b951964fSBarry Smith   ierr = MatGetOwnershipRange(oldmat,&start,&end); CHKERRQ(ierr);
103*b951964fSBarry Smith   ierr = VecCreateMPI(comm,end-start,PETSC_DECIDE,&in); CHKERRQ(ierr);
104*b951964fSBarry Smith   ierr = VecDuplicate(in,&out); CHKERRQ(ierr);
105*b951964fSBarry Smith   ierr = VecGetSize(in,&M); CHKERRQ(ierr);
106*b951964fSBarry Smith   ierr = VecGetLocalSize(in,&m); CHKERRQ(ierr);
107*b951964fSBarry Smith   rows = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(rows);
108*b951964fSBarry Smith   for ( i=0; i<m; i++ ) {rows[i] = start + i;}
109*b951964fSBarry Smith 
110*b951964fSBarry Smith   if (size == 1) {
111*b951964fSBarry Smith     ierr = MatCreateSeqDense(comm,M,M,PETSC_NULL,mat); CHKERRQ(ierr);
112*b951964fSBarry Smith   } else {
113*b951964fSBarry Smith     ierr = MatCreateMPIDense(comm,m,M,M,M,PETSC_NULL,mat); CHKERRQ(ierr);
114*b951964fSBarry Smith     /* ierr = MatCreateMPIAIJ(comm,m,m,M,M,0,0,0,0,mat); CHKERRQ(ierr); */
115*b951964fSBarry Smith   }
116*b951964fSBarry Smith 
117*b951964fSBarry Smith   for ( i=0; i<M; i++ ) {
118*b951964fSBarry Smith 
119*b951964fSBarry Smith     ierr = VecSet(&zero,in); CHKERRQ(ierr);
120*b951964fSBarry Smith     ierr = VecSetValues(in,1,&i,&one,INSERT_VALUES); CHKERRQ(ierr);
121*b951964fSBarry Smith     ierr = VecAssemblyBegin(in); CHKERRQ(ierr);
122*b951964fSBarry Smith     ierr = VecAssemblyEnd(in); CHKERRQ(ierr);
123*b951964fSBarry Smith 
124*b951964fSBarry Smith     ierr = MatMult(oldmat,in,out); CHKERRQ(ierr);
125*b951964fSBarry Smith 
126*b951964fSBarry Smith     ierr = VecGetArray(out,&array); CHKERRQ(ierr);
127*b951964fSBarry Smith     ierr = MatSetValues(*mat,m,rows,1,&i,array,INSERT_VALUES); CHKERRQ(ierr);
128*b951964fSBarry Smith     ierr = VecRestoreArray(out,&array); CHKERRQ(ierr);
129*b951964fSBarry Smith 
130*b951964fSBarry Smith   }
131*b951964fSBarry Smith   PetscFree(rows);
132*b951964fSBarry Smith   ierr = VecDestroy(in); CHKERRQ(ierr);
133*b951964fSBarry Smith   ierr = VecDestroy(out); CHKERRQ(ierr);
134*b951964fSBarry Smith   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
135*b951964fSBarry Smith   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
136*b951964fSBarry Smith   return 0;
137*b951964fSBarry Smith }
138*b951964fSBarry Smith 
139*b951964fSBarry Smith static int MatGetOwnershipRange_Shell(Mat mat, int *rstart,int *rend)
140*b951964fSBarry Smith {
141*b951964fSBarry Smith   MPI_Scan(&mat->m,rend,1,MPI_INT,MPI_SUM,mat->comm);
142*b951964fSBarry Smith   *rstart = *rend - mat->m;
143*b951964fSBarry Smith   return 0;
144*b951964fSBarry Smith }
145*b951964fSBarry Smith 
146*b951964fSBarry Smith 
147*b951964fSBarry Smith 
148*b951964fSBarry Smith 
149*b951964fSBarry Smith static struct _MatOps MatOps = {0,
15020563c6bSBarry Smith        0,
15120563c6bSBarry Smith        0,
15220563c6bSBarry Smith        0,
15320563c6bSBarry Smith        0,
154*b951964fSBarry Smith        0,
155*b951964fSBarry Smith        0,
156*b951964fSBarry Smith        0,
157*b951964fSBarry Smith        0,
158*b951964fSBarry Smith        0,
159*b951964fSBarry Smith        0,
160*b951964fSBarry Smith        0,
161*b951964fSBarry Smith        0,
162*b951964fSBarry Smith        0,
163*b951964fSBarry Smith        0,
164*b951964fSBarry Smith        0,
165*b951964fSBarry Smith        0,
166*b951964fSBarry Smith        0,
167*b951964fSBarry Smith        0,
168*b951964fSBarry Smith        0,
169*b951964fSBarry Smith        0,
170*b951964fSBarry Smith        0,
171*b951964fSBarry Smith        0,
172*b951964fSBarry Smith        0,
173*b951964fSBarry Smith        0,
174*b951964fSBarry Smith        0,
175*b951964fSBarry Smith        0,
176*b951964fSBarry Smith        0,
177*b951964fSBarry Smith        0,
178*b951964fSBarry Smith        0,
179*b951964fSBarry Smith        MatGetSize_Shell,
180*b951964fSBarry Smith        MatGetLocalSize_Shell,
181*b951964fSBarry Smith        MatGetOwnershipRange_Shell,
182*b951964fSBarry Smith        0,
183*b951964fSBarry Smith        0,
184*b951964fSBarry Smith        0,
185*b951964fSBarry Smith        0,
186*b951964fSBarry Smith        MatConvert_Shell,
187*b951964fSBarry Smith        0 };
188e51e0e81SBarry Smith 
1895615d1e5SSatish Balay #undef __FUNC__
1905615d1e5SSatish Balay #define __FUNC__ "MatCreateShell"
1914b828684SBarry Smith /*@C
192052efed2SBarry Smith    MatCreateShell - Creates a new matrix class for use with a user-defined
193ff756334SLois Curfman McInnes    private data storage format.
194e51e0e81SBarry Smith 
195e51e0e81SBarry Smith    Input Parameters:
1966b5873e3SBarry Smith .  comm - MPI communicator
197f39d1f56SLois Curfman McInnes .  m - number of local rows
198f39d1f56SLois Curfman McInnes .  n - number of local columns
199f39d1f56SLois Curfman McInnes .  M - number of global rows
200f39d1f56SLois Curfman McInnes .  N - number of global columns
201deebb3c3SLois Curfman McInnes .  ctx - pointer to data needed by the shell matrix routines
202e51e0e81SBarry Smith 
203ff756334SLois Curfman McInnes    Output Parameter:
20444cd7ae7SLois Curfman McInnes .  A - the matrix
205e51e0e81SBarry Smith 
206f39d1f56SLois Curfman McInnes    Usage:
207f39d1f56SLois Curfman McInnes $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
2081c1c02c0SLois Curfman McInnes $    MatShellSetOperation(mat,MATOP_MULT,mult);
209f39d1f56SLois Curfman McInnes $    [ Use matrix for operations that have been set ]
210f39d1f56SLois Curfman McInnes $    MatDestroy(mat);
211f39d1f56SLois Curfman McInnes 
212ff756334SLois Curfman McInnes    Notes:
213ff756334SLois Curfman McInnes    The shell matrix type is intended to provide a simple class to use
214ff756334SLois Curfman McInnes    with KSP (such as, for use with matrix-free methods). You should not
215ff756334SLois Curfman McInnes    use the shell type if you plan to define a complete matrix class.
216e51e0e81SBarry Smith 
217f39d1f56SLois Curfman McInnes    PETSc requires that matrices and vectors being used for certain
218f39d1f56SLois Curfman McInnes    operations are partitioned accordingly.  For example, when
219645985a0SLois Curfman McInnes    creating a shell matrix, A, that supports parallel matrix-vector
220645985a0SLois Curfman McInnes    products using MatMult(A,x,y) the user should set the number
221645985a0SLois Curfman McInnes    of local matrix rows to be the number of local elements of the
222645985a0SLois Curfman McInnes    corresponding result vector, y. Note that this is information is
223645985a0SLois Curfman McInnes    required for use of the matrix interface routines, even though
224645985a0SLois Curfman McInnes    the shell matrix may not actually be physically partitioned.
225645985a0SLois Curfman McInnes    For example,
226f39d1f56SLois Curfman McInnes 
227f39d1f56SLois Curfman McInnes $
228f39d1f56SLois Curfman McInnes $     Vec x, y
229645985a0SLois Curfman McInnes $     Mat A
230f39d1f56SLois Curfman McInnes $
231f39d1f56SLois Curfman McInnes $     VecCreate(comm,M,&y);
232f39d1f56SLois Curfman McInnes $     VecCreate(comm,N,&x);
233f39d1f56SLois Curfman McInnes $     VecGetLocalSize(y,&m);
234645985a0SLois Curfman McInnes $     MatCreateShell(comm,m,N,M,N,ctx,&A);
2351c1c02c0SLois Curfman McInnes $     MatShellSetOperation(mat,MATOP_MULT,mult);
236645985a0SLois Curfman McInnes $     MatMult(A,x,y);
237645985a0SLois Curfman McInnes $     MatDestroy(A);
238f39d1f56SLois Curfman McInnes $     VecDestroy(y); VecDestroy(x);
239645985a0SLois Curfman McInnes $
240e51e0e81SBarry Smith 
2410b627109SLois Curfman McInnes .keywords: matrix, shell, create
2420b627109SLois Curfman McInnes 
2433a3eedf2SBarry Smith .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext()
244e51e0e81SBarry Smith @*/
245f39d1f56SLois Curfman McInnes int MatCreateShell(MPI_Comm comm,int m,int n,int M,int N,void *ctx,Mat *A)
246e51e0e81SBarry Smith {
24744cd7ae7SLois Curfman McInnes   Mat       B;
24844cd7ae7SLois Curfman McInnes   Mat_Shell *b;
249ed3cc1f0SBarry Smith 
25044cd7ae7SLois Curfman McInnes   PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSHELL,comm);
25144cd7ae7SLois Curfman McInnes   PLogObjectCreate(B);
25244cd7ae7SLois Curfman McInnes   B->factor    = 0;
25344cd7ae7SLois Curfman McInnes   B->destroy   = MatDestroy_Shell;
25444cd7ae7SLois Curfman McInnes   B->assembled = PETSC_TRUE;
25544cd7ae7SLois Curfman McInnes   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
256227d817aSBarry Smith 
25744cd7ae7SLois Curfman McInnes   b          = PetscNew(Mat_Shell); CHKPTRQ(b);
25844cd7ae7SLois Curfman McInnes   PetscMemzero(b,sizeof(Mat_Shell));
25944cd7ae7SLois Curfman McInnes   B->data   = (void *) b;
260f39d1f56SLois Curfman McInnes   b->M = M; B->M = M;
261f39d1f56SLois Curfman McInnes   b->N = N; B->N = N;
262f39d1f56SLois Curfman McInnes   b->m = m; B->m = m;
263f39d1f56SLois Curfman McInnes   b->n = n; B->n = n;
26444cd7ae7SLois Curfman McInnes   b->ctx     = ctx;
26544cd7ae7SLois Curfman McInnes   *A = B;
266e51e0e81SBarry Smith   return 0;
267e51e0e81SBarry Smith }
268e51e0e81SBarry Smith 
2695615d1e5SSatish Balay #undef __FUNC__
2705615d1e5SSatish Balay #define __FUNC__ "MatShellSetOperation"
271c16cb8f2SBarry Smith /*@C
2723a3eedf2SBarry Smith     MatShellSetOperation - Allows user to set a matrix operation for
2733a3eedf2SBarry Smith                            a shell matrix.
274e51e0e81SBarry Smith 
275e51e0e81SBarry Smith     Input Parameters:
276fae171e0SBarry Smith .   mat - the shell matrix
277fae171e0SBarry Smith .   op - the name of the operation
278fae171e0SBarry Smith .   f - the function that provides the operation.
279e51e0e81SBarry Smith 
280fae171e0SBarry Smith     Usage:
281a62d957aSLois Curfman McInnes $      extern int usermult(Mat,Vec,Vec);
282f39d1f56SLois Curfman McInnes $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
2831c1c02c0SLois Curfman McInnes $      ierr = MatShellSetOperation(A,MATOP_MULT,usermult);
2840b627109SLois Curfman McInnes 
285a62d957aSLois Curfman McInnes     Notes:
286a62d957aSLois Curfman McInnes     See the file petsc/include/mat.h for a complete list of matrix
2871c1c02c0SLois Curfman McInnes     operations, which all have the form MATOP_<OPERATION>, where
288a62d957aSLois Curfman McInnes     <OPERATION> is the name (in all capital letters) of the
2891c1c02c0SLois Curfman McInnes     user interface routine (e.g., MatMult() -> MATOP_MULT).
290a62d957aSLois Curfman McInnes 
291a62d957aSLois Curfman McInnes     All user-provided functions should have the same calling
292deebb3c3SLois Curfman McInnes     sequence as the usual matrix interface routines, since they
293deebb3c3SLois Curfman McInnes     are intended to be accessed via the usual matrix interface
294deebb3c3SLois Curfman McInnes     routines, e.g.,
295a62d957aSLois Curfman McInnes $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
296a62d957aSLois Curfman McInnes 
297a62d957aSLois Curfman McInnes     Within each user-defined routine, the user should call
298a62d957aSLois Curfman McInnes     MatShellGetContext() to obtain the user-defined context that was
299a62d957aSLois Curfman McInnes     set by MatCreateShell().
300a62d957aSLois Curfman McInnes 
301a62d957aSLois Curfman McInnes .keywords: matrix, shell, set, operation
302a62d957aSLois Curfman McInnes 
303a62d957aSLois Curfman McInnes .seealso: MatCreateShell(), MatShellGetContext()
304e51e0e81SBarry Smith @*/
305fae171e0SBarry Smith int MatShellSetOperation(Mat mat,MatOperation op, void *f)
306e51e0e81SBarry Smith {
30777c4ece6SBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
308fae171e0SBarry Smith 
3091c1c02c0SLois Curfman McInnes   if (op == MATOP_DESTROY) {
310a62d957aSLois Curfman McInnes     if (mat->type == MATSHELL) {
311a62d957aSLois Curfman McInnes        Mat_Shell *shell = (Mat_Shell *) mat->data;
3123a3eedf2SBarry Smith        shell->destroy                 = (int (*)(Mat)) f;
313a62d957aSLois Curfman McInnes     }
314a62d957aSLois Curfman McInnes     else mat->destroy                 = (int (*)(PetscObject)) f;
315a62d957aSLois Curfman McInnes   }
3161c1c02c0SLois Curfman McInnes   else if (op == MATOP_VIEW) mat->view  = (int (*)(PetscObject,Viewer)) f;
317fae171e0SBarry Smith   else      (((void**)&mat->ops)[op]) = f;
318a62d957aSLois Curfman McInnes 
31920563c6bSBarry Smith   return 0;
320e51e0e81SBarry Smith }
321f0479e8cSBarry Smith 
3223a3eedf2SBarry Smith 
3233a3eedf2SBarry Smith 
324