xref: /petsc/src/mat/impls/shell/shell.c (revision a7cc72af8dae79365b4ec1ba6d96bf0305bf6125)
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   ierr    = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr);
273   A->data = (void*)b;
274 
275   if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) {
276     SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix");
277   }
278 
279   ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr);
280   ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr);
281 
282   ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr);
283   ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr);
284 
285   b->ctx          = 0;
286   b->scale        = PETSC_FALSE;
287   b->shift        = PETSC_FALSE;
288   b->vshift       = 0.0;
289   b->vscale       = 1.0;
290   b->mult         = 0;
291   A->assembled    = PETSC_TRUE;
292   A->preallocated = PETSC_TRUE;
293   PetscFunctionReturn(0);
294 }
295 EXTERN_C_END
296 
297 #undef __FUNCT__
298 #define __FUNCT__ "MatCreateShell"
299 /*@C
300    MatCreateShell - Creates a new matrix class for use with a user-defined
301    private data storage format.
302 
303   Collective on MPI_Comm
304 
305    Input Parameters:
306 +  comm - MPI communicator
307 .  m - number of local rows (must be given)
308 .  n - number of local columns (must be given)
309 .  M - number of global rows (may be PETSC_DETERMINE)
310 .  N - number of global columns (may be PETSC_DETERMINE)
311 -  ctx - pointer to data needed by the shell matrix routines
312 
313    Output Parameter:
314 .  A - the matrix
315 
316    Level: advanced
317 
318   Usage:
319 $    extern int mult(Mat,Vec,Vec);
320 $    MatCreateShell(comm,m,n,M,N,ctx,&mat);
321 $    MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
322 $    [ Use matrix for operations that have been set ]
323 $    MatDestroy(mat);
324 
325    Notes:
326    The shell matrix type is intended to provide a simple class to use
327    with KSP (such as, for use with matrix-free methods). You should not
328    use the shell type if you plan to define a complete matrix class.
329 
330    PETSc requires that matrices and vectors being used for certain
331    operations are partitioned accordingly.  For example, when
332    creating a shell matrix, A, that supports parallel matrix-vector
333    products using MatMult(A,x,y) the user should set the number
334    of local matrix rows to be the number of local elements of the
335    corresponding result vector, y. Note that this is information is
336    required for use of the matrix interface routines, even though
337    the shell matrix may not actually be physically partitioned.
338    For example,
339 
340 $
341 $     Vec x, y
342 $     extern int mult(Mat,Vec,Vec);
343 $     Mat A
344 $
345 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
346 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
347 $     VecGetLocalSize(y,&m);
348 $     VecGetLocalSize(x,&n);
349 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
350 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
351 $     MatMult(A,x,y);
352 $     MatDestroy(A);
353 $     VecDestroy(y); VecDestroy(x);
354 $
355 
356 .keywords: matrix, shell, create
357 
358 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
359 @*/
360 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
361 {
362   PetscErrorCode ierr;
363 
364   PetscFunctionBegin;
365   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
366   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
367   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
368   PetscFunctionReturn(0);
369 }
370 
371 #undef __FUNCT__
372 #define __FUNCT__ "MatShellSetContext"
373 /*@C
374     MatShellSetContext - sets the context for a shell matrix
375 
376    Collective on Mat
377 
378     Input Parameters:
379 +   mat - the shell matrix
380 -   ctx - the context
381 
382    Level: advanced
383 
384 
385 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
386 @*/
387 PetscErrorCode MatShellSetContext(Mat mat,void *ctx)
388 {
389   Mat_Shell      *shell = (Mat_Shell*)mat->data;
390   PetscErrorCode ierr;
391   PetscTruth     flg;
392 
393   PetscFunctionBegin;
394   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
395   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
396   if (flg) {
397     shell->ctx = ctx;
398   }
399   PetscFunctionReturn(0);
400 }
401 
402 #undef __FUNCT__
403 #define __FUNCT__ "MatShellSetOperation"
404 /*@C
405     MatShellSetOperation - Allows user to set a matrix operation for
406                            a shell matrix.
407 
408    Collective on Mat
409 
410     Input Parameters:
411 +   mat - the shell matrix
412 .   op - the name of the operation
413 -   f - the function that provides the operation.
414 
415    Level: advanced
416 
417     Usage:
418 $      extern int usermult(Mat,Vec,Vec);
419 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
420 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
421 
422     Notes:
423     See the file include/petscmat.h for a complete list of matrix
424     operations, which all have the form MATOP_<OPERATION>, where
425     <OPERATION> is the name (in all capital letters) of the
426     user interface routine (e.g., MatMult() -> MATOP_MULT).
427 
428     All user-provided functions should have the same calling
429     sequence as the usual matrix interface routines, since they
430     are intended to be accessed via the usual matrix interface
431     routines, e.g.,
432 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
433 
434     Within each user-defined routine, the user should call
435     MatShellGetContext() to obtain the user-defined context that was
436     set by MatCreateShell().
437 
438 .keywords: matrix, shell, set, operation
439 
440 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
441 @*/
442 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
443 {
444   PetscErrorCode ierr;
445   PetscTruth     flg;
446 
447   PetscFunctionBegin;
448   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
449   if (op == MATOP_DESTROY) {
450     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
451     if (flg) {
452        Mat_Shell *shell = (Mat_Shell*)mat->data;
453        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
454     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
455   }
456   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
457   else                       (((void(**)(void))mat->ops)[op]) = f;
458 
459   PetscFunctionReturn(0);
460 }
461 
462 #undef __FUNCT__
463 #define __FUNCT__ "MatShellGetOperation"
464 /*@C
465     MatShellGetOperation - Gets a matrix function for a shell matrix.
466 
467     Not Collective
468 
469     Input Parameters:
470 +   mat - the shell matrix
471 -   op - the name of the operation
472 
473     Output Parameter:
474 .   f - the function that provides the operation.
475 
476     Level: advanced
477 
478     Notes:
479     See the file include/petscmat.h for a complete list of matrix
480     operations, which all have the form MATOP_<OPERATION>, where
481     <OPERATION> is the name (in all capital letters) of the
482     user interface routine (e.g., MatMult() -> MATOP_MULT).
483 
484     All user-provided functions have the same calling
485     sequence as the usual matrix interface routines, since they
486     are intended to be accessed via the usual matrix interface
487     routines, e.g.,
488 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
489 
490     Within each user-defined routine, the user should call
491     MatShellGetContext() to obtain the user-defined context that was
492     set by MatCreateShell().
493 
494 .keywords: matrix, shell, set, operation
495 
496 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
497 @*/
498 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
499 {
500   PetscErrorCode ierr;
501   PetscTruth     flg;
502 
503   PetscFunctionBegin;
504   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
505   if (op == MATOP_DESTROY) {
506     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
507     if (flg) {
508       Mat_Shell *shell = (Mat_Shell*)mat->data;
509       *f = (void(*)(void))shell->destroy;
510     } else {
511       *f = (void(*)(void))mat->ops->destroy;
512     }
513   } else if (op == MATOP_VIEW) {
514     *f = (void(*)(void))mat->ops->view;
515   } else {
516     *f = (((void(**)(void))mat->ops)[op]);
517   }
518 
519   PetscFunctionReturn(0);
520 }
521 
522