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