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