xref: /petsc/src/mat/impls/shell/shell.c (revision 1a77e246f64eb120f4a59ef3b28bc160291d5220)
1 /*
2    This provides a simple shell for Fortran (and C programmers) to
3   create a very simple matrix class for use with KSP without coding
4   much of anything.
5 */
6 
7 #include "src/mat/matimpl.h"        /*I "petscmat.h" I*/
8 #include "vecimpl.h"
9 
10 typedef struct {
11   PetscErrorCode (*destroy)(Mat);
12   PetscErrorCode (*mult)(Mat,Vec,Vec);
13   PetscTruth     scale,shift;
14   PetscScalar    vscale,vshift;
15   void           *ctx;
16 } Mat_Shell;
17 
18 #undef __FUNCT__
19 #define __FUNCT__ "MatShellGetContext"
20 /*@
21     MatShellGetContext - Returns the user-provided context associated with a shell matrix.
22 
23     Not Collective
24 
25     Input Parameter:
26 .   mat - the matrix, should have been created with MatCreateShell()
27 
28     Output Parameter:
29 .   ctx - the user provided context
30 
31     Level: advanced
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(), MatShellSetContext()
40 @*/
41 PetscErrorCode MatShellGetContext(Mat mat,void **ctx)
42 {
43   PetscErrorCode ierr;
44   PetscTruth     flg;
45 
46   PetscFunctionBegin;
47   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
48   PetscValidPointer(ctx,2);
49   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
50   if (!flg) *ctx = 0;
51   else      *ctx = ((Mat_Shell*)(mat->data))->ctx;
52   PetscFunctionReturn(0);
53 }
54 
55 #undef __FUNCT__
56 #define __FUNCT__ "MatDestroy_Shell"
57 PetscErrorCode MatDestroy_Shell(Mat mat)
58 {
59   PetscErrorCode ierr;
60   Mat_Shell      *shell;
61 
62   PetscFunctionBegin;
63   shell = (Mat_Shell*)mat->data;
64   if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);}
65   ierr = PetscFree(shell);CHKERRQ(ierr);
66   PetscFunctionReturn(0);
67 }
68 
69 #undef __FUNCT__
70 #define __FUNCT__ "MatMult_Shell"
71 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y)
72 {
73   Mat_Shell      *shell = (Mat_Shell*)A->data;
74   PetscErrorCode ierr;
75 
76   PetscFunctionBegin;
77   ierr = (*shell->mult)(A,x,y);CHKERRQ(ierr);
78   if (shell->shift && shell->scale) {
79     ierr = VecAXPBY(&shell->vshift,&shell->vscale,x,y);CHKERRQ(ierr);
80   } else if (shell->scale) {
81     ierr = VecScale(&shell->vscale,y);CHKERRQ(ierr);
82   } else {
83     ierr = VecAXPY(&shell->vshift,x,y);CHKERRQ(ierr);
84   }
85   PetscFunctionReturn(0);
86 }
87 
88 #undef __FUNCT__
89 #define __FUNCT__ "MatShift_Shell"
90 PetscErrorCode MatShift_Shell(const PetscScalar *a,Mat Y)
91 {
92   Mat_Shell *shell = (Mat_Shell*)Y->data;
93 
94   PetscFunctionBegin;
95   if (shell->scale || shell->shift) {
96     shell->vshift += *a;
97   } else {
98     shell->mult   = Y->ops->mult;
99     Y->ops->mult  = MatMult_Shell;
100     shell->vshift = *a;
101   }
102   shell->shift  =  PETSC_TRUE;
103   PetscFunctionReturn(0);
104 }
105 
106 #undef __FUNCT__
107 #define __FUNCT__ "MatScale_Shell"
108 PetscErrorCode MatScale_Shell(const PetscScalar *a,Mat Y)
109 {
110   Mat_Shell *shell = (Mat_Shell*)Y->data;
111 
112   PetscFunctionBegin;
113   if (shell->scale || shell->shift) {
114     shell->vscale *= *a;
115   } else {
116     shell->mult   = Y->ops->mult;
117     Y->ops->mult  = MatMult_Shell;
118     shell->vscale = *a;
119   }
120   shell->scale  =  PETSC_TRUE;
121   PetscFunctionReturn(0);
122 }
123 
124 #undef __FUNCT__
125 #define __FUNCT__ "MatAssemblyEnd_Shell"
126 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t)
127 {
128   Mat_Shell *shell = (Mat_Shell*)Y->data;
129 
130   PetscFunctionBegin;
131   if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) {
132     shell->scale  = PETSC_FALSE;
133     shell->shift  = PETSC_FALSE;
134     shell->vshift = 0.0;
135     shell->vscale = 1.0;
136     Y->ops->mult  = shell->mult;
137   }
138   PetscFunctionReturn(0);
139 }
140 
141 EXTERN PetscErrorCode MatConvert_Shell(Mat,const MatType,Mat*);
142 
143 static struct _MatOps MatOps_Values = {0,
144        0,
145        0,
146        0,
147 /* 4*/ 0,
148        0,
149        0,
150        0,
151        0,
152        0,
153 /*10*/ 0,
154        0,
155        0,
156        0,
157        0,
158 /*15*/ 0,
159        0,
160        0,
161        0,
162        0,
163 /*20*/ 0,
164        MatAssemblyEnd_Shell,
165        0,
166        0,
167        0,
168 /*25*/ 0,
169        0,
170        0,
171        0,
172        0,
173 /*30*/ 0,
174        0,
175        0,
176        0,
177        0,
178 /*35*/ 0,
179        0,
180        0,
181        0,
182        0,
183 /*40*/ 0,
184        0,
185        0,
186        0,
187        0,
188 /*45*/ 0,
189        MatScale_Shell,
190        MatShift_Shell,
191        0,
192        0,
193 /*50*/ 0,
194        0,
195        0,
196        0,
197        0,
198 /*55*/ 0,
199        0,
200        0,
201        0,
202        0,
203 /*60*/ 0,
204        MatDestroy_Shell,
205        0,
206        MatGetPetscMaps_Petsc,
207        0,
208 /*65*/ 0,
209        0,
210        0,
211        0,
212        0,
213 /*70*/ 0,
214        MatConvert_Shell,
215        0,
216        0,
217        0,
218 /*75*/ 0,
219        0,
220        0,
221        0,
222        0,
223 /*80*/ 0,
224        0,
225        0,
226        0,
227        0,
228 /*85*/ 0,
229        0,
230        0,
231        0,
232        0,
233 /*90*/ 0,
234        0,
235        0,
236        0,
237        0,
238 /*95*/ 0,
239        0,
240        0,
241        0};
242 
243 /*MC
244    MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free.
245 
246   Level: advanced
247 
248 .seealso: MatCreateShell
249 M*/
250 
251 EXTERN_C_BEGIN
252 #undef __FUNCT__
253 #define __FUNCT__ "MatCreate_Shell"
254 PetscErrorCode MatCreate_Shell(Mat A)
255 {
256   Mat_Shell      *b;
257   PetscErrorCode ierr;
258 
259   PetscFunctionBegin;
260   ierr            = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
261 
262   ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr);
263   PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));
264   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
265   A->data = (void*)b;
266 
267   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
268     SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
269   }
270 
271   ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr);
272   ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr);
273 
274   ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr);
275   ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr);
276 
277   b->ctx          = 0;
278   b->scale        = PETSC_FALSE;
279   b->shift        = PETSC_FALSE;
280   b->vshift       = 0.0;
281   b->vscale       = 1.0;
282   b->mult         = 0;
283   A->assembled    = PETSC_TRUE;
284   A->preallocated = PETSC_TRUE;
285   PetscFunctionReturn(0);
286 }
287 EXTERN_C_END
288 
289 #undef __FUNCT__
290 #define __FUNCT__ "MatCreateShell"
291 /*@C
292    MatCreateShell - Creates a new matrix class for use with a user-defined
293    private data storage format.
294 
295   Collective on MPI_Comm
296 
297    Input Parameters:
298 +  comm - MPI communicator
299 .  m - number of local rows (must be given)
300 .  n - number of local columns (must be given)
301 .  M - number of global rows (may be PETSC_DETERMINE)
302 .  N - number of global columns (may be PETSC_DETERMINE)
303 -  ctx - pointer to data needed by the shell matrix routines
304 
305    Output Parameter:
306 .  A - the matrix
307 
308    Level: advanced
309 
310   Usage:
311 $    extern int mult(Mat,Vec,Vec);
312 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
313 $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
314 $    [ Use matrix for operations that have been set ]
315 $    MatDestroy(mat);
316 
317    Notes:
318    The shell matrix type is intended to provide a simple class to use
319    with KSP (such as, for use with matrix-free methods). You should not
320    use the shell type if you plan to define a complete matrix class.
321 
322    PETSc requires that matrices and vectors being used for certain
323    operations are partitioned accordingly.  For example, when
324    creating a shell matrix, A, that supports parallel matrix-vector
325    products using MatMult(A,x,y) the user should set the number
326    of local matrix rows to be the number of local elements of the
327    corresponding result vector, y. Note that this is information is
328    required for use of the matrix interface routines, even though
329    the shell matrix may not actually be physically partitioned.
330    For example,
331 
332 $
333 $     Vec x, y
334 $     extern int mult(Mat,Vec,Vec);
335 $     Mat A
336 $
337 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
338 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
339 $     VecGetLocalSize(y,&m);
340 $     VecGetLocalSize(x,&n);
341 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
342 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
343 $     MatMult(A,x,y);
344 $     MatDestroy(A);
345 $     VecDestroy(y); VecDestroy(x);
346 $
347 
348 .keywords: matrix, shell, create
349 
350 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
351 @*/
352 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
353 {
354   PetscErrorCode ierr;
355 
356   PetscFunctionBegin;
357   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
358   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
359   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
360   PetscFunctionReturn(0);
361 }
362 
363 #undef __FUNCT__
364 #define __FUNCT__ "MatShellSetContext"
365 /*@C
366     MatShellSetContext - sets the context for a shell matrix
367 
368    Collective on Mat
369 
370     Input Parameters:
371 +   mat - the shell matrix
372 -   ctx - the context
373 
374    Level: advanced
375 
376 
377 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
378 @*/
379 PetscErrorCode MatShellSetContext(Mat mat,void *ctx)
380 {
381   Mat_Shell      *shell = (Mat_Shell*)mat->data;
382   PetscErrorCode ierr;
383   PetscTruth     flg;
384 
385   PetscFunctionBegin;
386   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
387   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
388   if (flg) {
389     shell->ctx = ctx;
390   }
391   PetscFunctionReturn(0);
392 }
393 
394 #undef __FUNCT__
395 #define __FUNCT__ "MatShellSetOperation"
396 /*@C
397     MatShellSetOperation - Allows user to set a matrix operation for
398                            a shell matrix.
399 
400    Collective on Mat
401 
402     Input Parameters:
403 +   mat - the shell matrix
404 .   op - the name of the operation
405 -   f - the function that provides the operation.
406 
407    Level: advanced
408 
409     Usage:
410 $      extern int usermult(Mat,Vec,Vec);
411 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
412 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
413 
414     Notes:
415     See the file include/petscmat.h for a complete list of matrix
416     operations, which all have the form MATOP_<OPERATION>, where
417     <OPERATION> is the name (in all capital letters) of the
418     user interface routine (e.g., MatMult() -> MATOP_MULT).
419 
420     All user-provided functions should have the same calling
421     sequence as the usual matrix interface routines, since they
422     are intended to be accessed via the usual matrix interface
423     routines, e.g.,
424 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
425 
426     Within each user-defined routine, the user should call
427     MatShellGetContext() to obtain the user-defined context that was
428     set by MatCreateShell().
429 
430 .keywords: matrix, shell, set, operation
431 
432 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
433 @*/
434 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
435 {
436   PetscErrorCode ierr;
437   PetscTruth     flg;
438 
439   PetscFunctionBegin;
440   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
441   if (op == MATOP_DESTROY) {
442     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
443     if (flg) {
444        Mat_Shell *shell = (Mat_Shell*)mat->data;
445        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
446     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
447   }
448   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
449   else                       (((void(**)(void))mat->ops)[op]) = f;
450 
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "MatShellGetOperation"
456 /*@C
457     MatShellGetOperation - Gets a matrix function for a shell matrix.
458 
459     Not Collective
460 
461     Input Parameters:
462 +   mat - the shell matrix
463 -   op - the name of the operation
464 
465     Output Parameter:
466 .   f - the function that provides the operation.
467 
468     Level: advanced
469 
470     Notes:
471     See the file include/petscmat.h for a complete list of matrix
472     operations, which all have the form MATOP_<OPERATION>, where
473     <OPERATION> is the name (in all capital letters) of the
474     user interface routine (e.g., MatMult() -> MATOP_MULT).
475 
476     All user-provided functions have the same calling
477     sequence as the usual matrix interface routines, since they
478     are intended to be accessed via the usual matrix interface
479     routines, e.g.,
480 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
481 
482     Within each user-defined routine, the user should call
483     MatShellGetContext() to obtain the user-defined context that was
484     set by MatCreateShell().
485 
486 .keywords: matrix, shell, set, operation
487 
488 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
489 @*/
490 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
491 {
492   PetscErrorCode ierr;
493   PetscTruth     flg;
494 
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
497   if (op == MATOP_DESTROY) {
498     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
499     if (flg) {
500       Mat_Shell *shell = (Mat_Shell*)mat->data;
501       *f = (void(*)(void))shell->destroy;
502     } else {
503       *f = (void(*)(void))mat->ops->destroy;
504     }
505   } else if (op == MATOP_VIEW) {
506     *f = (void(*)(void))mat->ops->view;
507   } else {
508     *f = (((void(**)(void))mat->ops)[op]);
509   }
510 
511   PetscFunctionReturn(0);
512 }
513 
514