xref: /petsc/src/mat/impls/shell/shell.c (revision bd44253f0c45762e62d62baab7cf1fcb3125de48)
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,MatReuse,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   ierr = PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell));CHKERRQ(ierr);
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    Fortran Notes: The context can only be an integer or a PetscObject
330       unfortunately it cannot be a Fortran array or derived type.
331 
332    PETSc requires that matrices and vectors being used for certain
333    operations are partitioned accordingly.  For example, when
334    creating a shell matrix, A, that supports parallel matrix-vector
335    products using MatMult(A,x,y) the user should set the number
336    of local matrix rows to be the number of local elements of the
337    corresponding result vector, y. Note that this is information is
338    required for use of the matrix interface routines, even though
339    the shell matrix may not actually be physically partitioned.
340    For example,
341 
342 $
343 $     Vec x, y
344 $     extern int mult(Mat,Vec,Vec);
345 $     Mat A
346 $
347 $     VecCreateMPI(comm,PETSC_DECIDE,M,&y);
348 $     VecCreateMPI(comm,PETSC_DECIDE,N,&x);
349 $     VecGetLocalSize(y,&m);
350 $     VecGetLocalSize(x,&n);
351 $     MatCreateShell(comm,m,n,M,N,ctx,&A);
352 $     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult);
353 $     MatMult(A,x,y);
354 $     MatDestroy(A);
355 $     VecDestroy(y); VecDestroy(x);
356 $
357 
358 .keywords: matrix, shell, create
359 
360 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext()
361 @*/
362 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A)
363 {
364   PetscErrorCode ierr;
365 
366   PetscFunctionBegin;
367   ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr);
368   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
369   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
370   PetscFunctionReturn(0);
371 }
372 
373 #undef __FUNCT__
374 #define __FUNCT__ "MatShellSetContext"
375 /*@C
376     MatShellSetContext - sets the context for a shell matrix
377 
378    Collective on Mat
379 
380     Input Parameters:
381 +   mat - the shell matrix
382 -   ctx - the context
383 
384    Level: advanced
385 
386    Fortran Notes: The context can only be an integer or a PetscObject
387       unfortunately it cannot be a Fortran array or derived type.
388 
389 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
390 @*/
391 PetscErrorCode MatShellSetContext(Mat mat,void *ctx)
392 {
393   Mat_Shell      *shell = (Mat_Shell*)mat->data;
394   PetscErrorCode ierr;
395   PetscTruth     flg;
396 
397   PetscFunctionBegin;
398   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
399   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
400   if (flg) {
401     shell->ctx = ctx;
402   }
403   PetscFunctionReturn(0);
404 }
405 
406 #undef __FUNCT__
407 #define __FUNCT__ "MatShellSetOperation"
408 /*@C
409     MatShellSetOperation - Allows user to set a matrix operation for
410                            a shell matrix.
411 
412    Collective on Mat
413 
414     Input Parameters:
415 +   mat - the shell matrix
416 .   op - the name of the operation
417 -   f - the function that provides the operation.
418 
419    Level: advanced
420 
421     Usage:
422 $      extern int usermult(Mat,Vec,Vec);
423 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
424 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
425 
426     Notes:
427     See the file include/petscmat.h for a complete list of matrix
428     operations, which all have the form MATOP_<OPERATION>, where
429     <OPERATION> is the name (in all capital letters) of the
430     user interface routine (e.g., MatMult() -> MATOP_MULT).
431 
432     All user-provided functions should have the same calling
433     sequence as the usual matrix interface routines, since they
434     are intended to be accessed via the usual matrix interface
435     routines, e.g.,
436 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
437 
438     Within each user-defined routine, the user should call
439     MatShellGetContext() to obtain the user-defined context that was
440     set by MatCreateShell().
441 
442 .keywords: matrix, shell, set, operation
443 
444 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
445 @*/
446 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
447 {
448   PetscErrorCode ierr;
449   PetscTruth     flg;
450 
451   PetscFunctionBegin;
452   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
453   if (op == MATOP_DESTROY) {
454     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
455     if (flg) {
456        Mat_Shell *shell = (Mat_Shell*)mat->data;
457        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
458     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
459   }
460   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
461   else                       (((void(**)(void))mat->ops)[op]) = f;
462 
463   PetscFunctionReturn(0);
464 }
465 
466 #undef __FUNCT__
467 #define __FUNCT__ "MatShellGetOperation"
468 /*@C
469     MatShellGetOperation - Gets a matrix function for a shell matrix.
470 
471     Not Collective
472 
473     Input Parameters:
474 +   mat - the shell matrix
475 -   op - the name of the operation
476 
477     Output Parameter:
478 .   f - the function that provides the operation.
479 
480     Level: advanced
481 
482     Notes:
483     See the file include/petscmat.h for a complete list of matrix
484     operations, which all have the form MATOP_<OPERATION>, where
485     <OPERATION> is the name (in all capital letters) of the
486     user interface routine (e.g., MatMult() -> MATOP_MULT).
487 
488     All user-provided functions have the same calling
489     sequence as the usual matrix interface routines, since they
490     are intended to be accessed via the usual matrix interface
491     routines, e.g.,
492 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
493 
494     Within each user-defined routine, the user should call
495     MatShellGetContext() to obtain the user-defined context that was
496     set by MatCreateShell().
497 
498 .keywords: matrix, shell, set, operation
499 
500 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
501 @*/
502 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
503 {
504   PetscErrorCode ierr;
505   PetscTruth     flg;
506 
507   PetscFunctionBegin;
508   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
509   if (op == MATOP_DESTROY) {
510     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
511     if (flg) {
512       Mat_Shell *shell = (Mat_Shell*)mat->data;
513       *f = (void(*)(void))shell->destroy;
514     } else {
515       *f = (void(*)(void))mat->ops->destroy;
516     }
517   } else if (op == MATOP_VIEW) {
518     *f = (void(*)(void))mat->ops->view;
519   } else {
520     *f = (((void(**)(void))mat->ops)[op]);
521   }
522 
523   PetscFunctionReturn(0);
524 }
525 
526