xref: /petsc/src/mat/impls/shell/shell.c (revision f69a0ea3504314d029ee423e0de2950ece2dab86)
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, 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,A);CHKERRQ(ierr);
370   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
371   ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr);
372   ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr);
373   PetscFunctionReturn(0);
374 }
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "MatShellSetContext"
378 /*@C
379     MatShellSetContext - sets the context for a shell matrix
380 
381    Collective on Mat
382 
383     Input Parameters:
384 +   mat - the shell matrix
385 -   ctx - the context
386 
387    Level: advanced
388 
389    Fortran Notes: The context can only be an integer or a PetscObject
390       unfortunately it cannot be a Fortran array or derived type.
391 
392 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation()
393 @*/
394 PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetContext(Mat mat,void *ctx)
395 {
396   Mat_Shell      *shell = (Mat_Shell*)mat->data;
397   PetscErrorCode ierr;
398   PetscTruth     flg;
399 
400   PetscFunctionBegin;
401   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
402   ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
403   if (flg) {
404     shell->ctx = ctx;
405   }
406   PetscFunctionReturn(0);
407 }
408 
409 #undef __FUNCT__
410 #define __FUNCT__ "MatShellSetOperation"
411 /*@C
412     MatShellSetOperation - Allows user to set a matrix operation for
413                            a shell matrix.
414 
415    Collective on Mat
416 
417     Input Parameters:
418 +   mat - the shell matrix
419 .   op - the name of the operation
420 -   f - the function that provides the operation.
421 
422    Level: advanced
423 
424     Usage:
425 $      extern int usermult(Mat,Vec,Vec);
426 $      ierr = MatCreateShell(comm,m,n,M,N,ctx,&A);
427 $      ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult);
428 
429     Notes:
430     See the file include/petscmat.h for a complete list of matrix
431     operations, which all have the form MATOP_<OPERATION>, where
432     <OPERATION> is the name (in all capital letters) of the
433     user interface routine (e.g., MatMult() -> MATOP_MULT).
434 
435     All user-provided functions should have the same calling
436     sequence as the usual matrix interface routines, since they
437     are intended to be accessed via the usual matrix interface
438     routines, e.g.,
439 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
440 
441     Within each user-defined routine, the user should call
442     MatShellGetContext() to obtain the user-defined context that was
443     set by MatCreateShell().
444 
445 .keywords: matrix, shell, set, operation
446 
447 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext()
448 @*/
449 PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void))
450 {
451   PetscErrorCode ierr;
452   PetscTruth     flg;
453 
454   PetscFunctionBegin;
455   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
456   if (op == MATOP_DESTROY) {
457     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
458     if (flg) {
459        Mat_Shell *shell = (Mat_Shell*)mat->data;
460        shell->destroy                 = (PetscErrorCode (*)(Mat)) f;
461     } else mat->ops->destroy          = (PetscErrorCode (*)(Mat)) f;
462   }
463   else if (op == MATOP_VIEW) mat->ops->view  = (PetscErrorCode (*)(Mat,PetscViewer)) f;
464   else                       (((void(**)(void))mat->ops)[op]) = f;
465 
466   PetscFunctionReturn(0);
467 }
468 
469 #undef __FUNCT__
470 #define __FUNCT__ "MatShellGetOperation"
471 /*@C
472     MatShellGetOperation - Gets a matrix function for a shell matrix.
473 
474     Not Collective
475 
476     Input Parameters:
477 +   mat - the shell matrix
478 -   op - the name of the operation
479 
480     Output Parameter:
481 .   f - the function that provides the operation.
482 
483     Level: advanced
484 
485     Notes:
486     See the file include/petscmat.h for a complete list of matrix
487     operations, which all have the form MATOP_<OPERATION>, where
488     <OPERATION> is the name (in all capital letters) of the
489     user interface routine (e.g., MatMult() -> MATOP_MULT).
490 
491     All user-provided functions have the same calling
492     sequence as the usual matrix interface routines, since they
493     are intended to be accessed via the usual matrix interface
494     routines, e.g.,
495 $       MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec)
496 
497     Within each user-defined routine, the user should call
498     MatShellGetContext() to obtain the user-defined context that was
499     set by MatCreateShell().
500 
501 .keywords: matrix, shell, set, operation
502 
503 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext()
504 @*/
505 PetscErrorCode PETSCMAT_DLLEXPORT MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void))
506 {
507   PetscErrorCode ierr;
508   PetscTruth     flg;
509 
510   PetscFunctionBegin;
511   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
512   if (op == MATOP_DESTROY) {
513     ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr);
514     if (flg) {
515       Mat_Shell *shell = (Mat_Shell*)mat->data;
516       *f = (void(*)(void))shell->destroy;
517     } else {
518       *f = (void(*)(void))mat->ops->destroy;
519     }
520   } else if (op == MATOP_VIEW) {
521     *f = (void(*)(void))mat->ops->view;
522   } else {
523     *f = (((void(**)(void))mat->ops)[op]);
524   }
525 
526   PetscFunctionReturn(0);
527 }
528 
529