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