xref: /petsc/doc/developers/objects.md (revision 74df5e01f481fb3fe90b32c3b4345ef0122eb3ce)
1# Basic Object Design and Implementation
2
3PETSc is designed by using strong data encapsulation. Hence, any
4collection of data (for instance, a sparse matrix) is stored in a way
5that is completely private from the application code. The application
6code can manipulate the data only through a well-defined interface,
7since it does *not* "know" how the data is stored internally.
8
9## Introduction
10
11PETSc is designed around several classes including `Vec` (vectors) and
12`Mat` (matrices, both dense and sparse). Each class is implemented by
13using a C `struct` that contains the data and function pointers for
14operations on the data (much like virtual functions in C++ classes).
15Each class consists of three parts:
16
17A (small) common part shared by all PETSc classes (for example, both
18`KSP` and `PC` have this same header).
19
20Another common part shared by all PETSc implementations of the class
21(for example, both `KSPGMRES` and `KSPCG` have this common
22subheader).
23
24A private part used by only one particular implementation written in
25PETSc.
26
27For example, all matrix (`Mat`) classes share a function table of
28operations that may be performed on the matrix; all PETSc matrix
29implementations share some additional data fields, including matrix
30parallel layout, while a particular matrix implementation in PETSc (say
31compressed sparse row) has its own data fields for storing the actual
32matrix values and sparsity pattern. This will be explained in more
33detail in the following sections. New class implementations *must* use
34the PETSc common part.
35
36We will use `<class>_<implementation>` to denote the actual source code
37and data structures used for a particular implementation of an object
38that has the `<class>` interface.
39
40## Organization of the Source Code
41
42Each class has the following organization.
43
44Its own, application-public, include file `include/petsc<class>.h`.
45
46Its own directory, `src/<class>` or `src/<package>/<class>`.
47
48A data structure defined in the file
49`include/petsc/private/<class>impl.h`. This data structure is shared
50by all the different PETSc implementations of the class. For example,
51for matrices it is shared by dense, sparse, parallel, and sequential
52formats.
53
54An abstract interface that defines the application-callable functions
55for the class. These are defined in the directory
56`src/<class>/interface`. This is how polymorphism is supported with
57code that implements the abstract interface to the operations on the
58object. Essentially, these routines do some error checking of arguments
59and logging of profiling information and then call the function
60appropriate for the particular implementation of the object. The name of
61the abstract function is `<class>Operation`, for instance,
62`MatMult()` or `PCCreate(`), while the name of a particular
63implementation is `<class>Operation_<implementation>`, for instance,
64`MatMult_SeqAIJ()` or `PCCreate_ILU()`. These naming conventions are
65used to simplify code maintenance (also see Section [sec:stylenames]).
66
67One or more actual implementations of the class (for example, sparse
68uniprocessor and parallel matrices implemented with the AIJ storage
69format). These are each in a subdirectory of `src/<class>/impls`.
70Except in rare circumstances, data structures defined here should not be
71referenced from outside this directory.
72
73Each type of object (for instance, a vector) is defined in its own
74public include file, by `typedef _p_<class>* <class>`; (for example,
75`typedef _p_Vec* Vec;`). This organization allows the compiler to
76perform type checking on all subroutine calls while at the same time
77completely removing the details of the implementation of `_p_<class>`
78from the application code. This capability is extremely important
79because it allows the library internals to be changed without altering
80or recompiling the application code.
81
82## Common Object Header
83
84All PETSc objects (derived from the base class `PetscObject`) have the following common header structures
85defined in
86<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/include/petsc/private/petscimpl.h.html">include/petsc/private/petscimpl.h</a>
87
88```
89typedef struct {
90  PetscErrorCode (*view)(PetscObject, Viewer);
91  PetscErrorCode (*destroy)(PetscObject);
92} PetscOps;
93```
94
95```
96struct _p_<class> {
97  PetscClassId     classid;
98  PetscOps         *bops;
99  <class>Ops       *ops;
100  MPI_Comm         comm;
101  PetscLogDouble   flops,time,mem;
102  int              id;
103  int              refct;
104  int              tag;
105  DLList           qlist;
106  OList            olist;
107  char             *type_name;
108  PetscObject      parent;
109  char             *name;
110  char             *prefix;
111  void             *cpp;
112  void             **fortran_func_pointers;
113  ..........
114  CLASS-SPECIFIC DATASTRUCTURES
115};
116```
117
118Here `<class>ops` is a function table (like the `PetscOps` above)
119that contains the function pointers for the operations specific to that
120class. For example, the PETSc vector class object operations in
121<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/include/petsc/private/vecimpl.h.html">include/petsc/private/vecimpl.h</a>
122include the following.
123
124```
125typedef struct _VecOps* VecOps;
126struct _VecOps {
127  PetscErrorCode (*duplicate)(Vec,Vec*); /* get single vector */
128  PetscErrorCode (*duplicatevecs)(Vec,PetscInt,Vec**); /* get array of vectors */
129  PetscErrorCode (*destroyvecs)(PetscInt,Vec[]); /* free array of vectors */
130  PetscErrorCode (*dot)(Vec,Vec,PetscScalar*); /* z = x^H * y */
131  PetscErrorCode (*mdot)(Vec,PetscInt,const Vec[],PetscScalar*); /* z[j] = x dot y[j] */
132  PetscErrorCode (*norm)(Vec,NormType,PetscReal*); /* z = sqrt(x^H * x) */
133  PetscErrorCode (*tdot)(Vec,Vec,PetscScalar*); /* x'*y */
134  PetscErrorCode (*mtdot)(Vec,PetscInt,const Vec[],PetscScalar*);/* z[j] = x dot y[j] */
135  PetscErrorCode (*scale)(Vec,PetscScalar);  /* x = alpha * x   */
136  PetscErrorCode (*copy)(Vec,Vec); /* y = x */
137  PetscErrorCode (*set)(Vec,PetscScalar); /* y = alpha  */
138  PetscErrorCode (*swap)(Vec,Vec); /* exchange x and y */
139  PetscErrorCode (*axpy)(Vec,PetscScalar,Vec); /* y = y + alpha * x */
140  PetscErrorCode (*axpby)(Vec,PetscScalar,PetscScalar,Vec); /* y = alpha * x + beta * y*/
141  PetscErrorCode (*maxpy)(Vec,PetscInt,const PetscScalar*,Vec*); /* y = y + alpha[j] x[j] */
142  ... (AND SO ON) ...
143};
144```
145
146```
147struct _p_Vec {
148  PetscClassId           classid;
149  PetscOps               *bops;
150  VecOps                 *ops;
151  MPI_Comm               comm;
152  PetscLogDouble         flops,time,mem;
153  int                    id;
154  int                    refct;
155  int                    tag;
156  DLList                 qlist;
157  OList                  olist;
158  char                   *type_name;
159  PetscObject            parent;
160  char                   *name;
161  char                   *prefix;
162  void                   **fortran_func_pointers;
163  void                   *data;     /* implementation-specific data */
164  PetscLayout            map;
165  ISLocalToGlobalMapping mapping;   /* mapping used in VecSetValuesLocal() */
166};
167```
168
169Each PETSc object begins with a `PetscClassId`, which is used for
170error checking. Each different class of objects has its value for
171`classid`; these are used to distinguish between classes. When a new
172class is created you need to call
173
174```
175PetscClassIdRegister(const char *classname,PetscClassId *classid);
176```
177
178For example,
179
180```
181PetscClassIdRegister("index set",&IS_CLASSID);
182```
183
184you can verify that an object is valid of a particular class with
185`PetscValidHeaderSpecific`, for example,
186
187```
188PetscValidHeaderSpecific(x,VEC_CLASSID,1);
189```
190
191The third argument to this macro indicates the position in the calling
192sequence of the function the object was passed in. This is to generate
193more complete error messages.
194
195To check for an object of any type, use
196
197```
198PetscValidHeader(x,1);
199```
200
201The `obj->ops` functions provide implementations of the standard methods of the object class. Each type
202of the class may have different function pointers in the array. Subtypes sometimes replace some of the
203function pointers of the parent, so they play the role of virtual methods in C++.
204
205PETSc code that calls these function pointers should be done via
206
207```
208PetscUseTypeMethod(obj,method,other arguments);
209PetscTryTypeMethod(obj,method,other arguments);
210```
211
212For example,
213
214```
215PetscErrorCode XXXOp(XXX x,YYY y)
216{
217  PetscFunctionBegin;
218  PetscUseTypeMethod(x,op,y);
219  PetscFunctionReturn(PETSC_SUCCESS);
220}
221```
222
223The `Try` variant skips the function call if the method has not been set while the `Use` version generates an error in that case.
224
225See also, `PetscUseMethod()`, and `PetscTryMethod()`.
226
227## Common Object Functions
228
229Several routines are provided for manipulating data within the header.
230These include the specific functions in the PETSc common function table.
231The function pointers are not called directly; rather you should call
232`PetscObjectFunctionName()`, where `FunctionName` is one of the
233functions listed below with the first letter of each word capitalized.
234
235`PetscObjectGetComm()` calls the `getcomm(PetscObject,MPI_Comm*)` function point which obtains the MPI communicator
236associated with this object.
237
238`PetscObjectView()` calls the `view(PetscObject,PetscViewer)` function point which allows you to store or visualize the
239data inside an object. If the `PetscViewer` is `NULL`, then it should cause the
240object to print information on the object to `stdout`.
241
242`PetscObjectDestroy()` calls the  `destroy(PetscObject)` function pointer which causes the reference count of the object to be
243decreased by one or the object to be destroyed and all memory used by
244the object to be freed when the reference count drops to zero. If the
245object has any other objects composed with it, the `PetscObjectDestroy()` function is called on them.
246
247`PetscObjectCompose()` calls the `compose(PetscObject,const char *name,PetscObject)` function pointer  which associates the
248second object with the first object and increases the reference count of
249the second object. If an object with the same name was previously
250composed, that object is dereferenced and replaced with the new object.
251If the second object is `NULL` and an object with the same name has
252already been composed, that object is dereferenced (the `PetscObjectDestroy()`
253function is called on it, and that object is removed from the first
254object). This is a way to remove, by name, an object that was previously
255composed.
256
257`PetscObjectQuery()` calls the `query(PetscObject,const char *name,PetscObject*)` function pointer which retrieves an object
258that was previously composed with the first object via
259`PetscObjectCompose()`. It retrieves a `NULL` if no object with that
260name was previously composed.
261
262`PetscObjectComposeFunction()` calls the `composefunction(PetscObject,const char *name,void *func)` function pointer which associates
263a function pointer with an object. If the object already had a composed
264function with the same name, the old one is replaced. If `func` is
265`NULL`, the existing function is removed from the object. The string
266`name` is the character string name of the function.
267
268For example, `fname` may be `PCCreate_LU`.
269
270`PetscObjectQueryFunction()` calls the `queryfunction(PetscObject,const char *name,void **func)` function pointer which retrieves a
271function pointer that was associated with the object via
272`PetscObjectComposeFunction()`. If dynamic libraries are used, the
273function is loaded into memory at this time (if it has not been
274previously loaded), not when the `PetscObjectComposeFunction()` routine was
275called.
276
277Since the object composition allows one to compose PETSc objects
278with PETSc objects, PETSc provides the
279convenience object `PetscContainer`, created with the routine
280`PetscContainerCreate(MPI_Comm,PetscContainer*)`, to allow wrapping any
281kind of data into a PETSc object that can then be composed with a PETSc
282object. One can also use `PetscObjectContainerCompose()` and `PetscObjectContainerQuery()` to compose
283arbitrary pointers with a PETSc object.
284
285## Object Function Implementation
286
287This section discusses how PETSc implements the `compose()`,
288`query()`, `composefunction()`, and `queryfunction()` functions
289for its object implementations. Other PETSc-compatible class
290implementations are free to manage these functions in any manner; but
291unless there is a specific reason, they should use the PETSc defaults so
292that the library writer does not have to “reinvent the wheel.”
293
294### Compose and Query Objects
295
296In
297<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/objects/olist.c.html">src/sys/objects/olist.c</a>
298PETSc defines a C `struct`
299
300```
301typedef struct _PetscObjectList* PetscObjectList;
302struct _PetscObjectList {
303    char             name[128];
304    PetscObject      obj;
305    PetscObjectList  next;
306};
307```
308
309from which linked lists of composed objects may be constructed. The
310routines to manipulate these elementary objects are
311
312```
313int PetscObjectListAdd(PetscObjectList *fl,const char *name,PetscObject obj);
314int PetscObjectListDestroy(PetscObjectList *fl);
315int PetscObjectListFind(PetscObjectList fl,const char *name,PetscObject *obj)
316int PetscObjectListDuplicate(PetscObjectList fl,PetscObjectList *nl);
317```
318
319The function `PetscObjectListAdd()` will create the initial
320PetscObjectList if the argument `fl` points to a NULL.
321
322The PETSc object `compose()` and `query()` functions are as follows
323(defined in
324<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/objects/inherit.c.html">src/sys/objects/inherit.c</a>
325
326```
327PetscErrorCode PetscObjectCompose_Petsc(PetscObject obj,const char *name,PetscObject ptr)
328{
329  PetscFunctionBegin;
330  PetscCall(PetscObjectListAdd(&obj->olist,name,ptr));
331  PetscFunctionReturn(PETSC_SUCCESS);
332}
333
334PetscErrorCode PetscObjectQuery_Petsc(PetscObject obj,const char *name,PetscObject *ptr)
335{
336  PetscFunctionBegin;
337  PetscCall(PetscObjectListFind(obj->olist,name,ptr));
338  PetscFunctionReturn(PETSC_SUCCESS);
339}
340```
341
342### Compose and Query Functions
343
344PETSc allows you to compose functions by specifying a name and function
345pointer. In
346<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/dll/reg.c.html">src/sys/dll/reg.c</a>
347PETSc defines the following linked list structure.
348
349```
350struct _n_PetscFunctionList {
351  void              (*routine)(void);    /* the routine */
352  char              *name;               /* string to identify routine */
353  PetscFunctionList next;                /* next pointer */
354  PetscFunctionList next_list;           /* used to maintain list of all lists for freeing */
355};
356```
357
358Each PETSc object contains a `PetscFunctionList` object. The
359`composefunction()` and `queryfunction()` are given by the
360following.
361
362```
363PetscErrorCode PetscObjectComposeFunction_Petsc(PetscObject obj, const char *name, PetscErrorCodeFn *ptr)
364{
365  PetscFunctionBegin;
366  PetscCall(PetscFunctionListAdd(&obj->qlist,name,fname,ptr));
367  PetscFunctionReturn(PETSC_SUCCESS);
368}
369
370PetscErrorCode PetscObjectQueryFunction_Petsc(PetscObject obj, const char *name, PetscErrorCodeFn **ptr)
371{
372  PetscFunctionBegin;
373  PetscCall(PetscFunctionListFind(obj->qlist,name,ptr));
374  PetscFunctionReturn(PETSC_SUCCESS);
375}
376```
377
378In addition to using the `PetscFunctionList` mechanism to compose
379functions into PETSc objects, it is also used to allow registration of
380new class implementations; for example, new preconditioners.
381
382PETSc code that calls composed functions should be done via
383
384```
385PetscUseMethod(obj,"method",(Argument types),(argument variables));
386PetscTryMethod(obj,"method",(Argument types),(argument variables));
387```
388
389For example,
390
391```
392PetscErrorCode  KSPGMRESSetRestart(KSP ksp, PetscInt restart)
393{
394  PetscFunctionBegin;
395  PetscValidLogicalCollectiveInt(ksp,restart,2);
396
397  PetscTryMethod(ksp,"KSPGMRESSetRestart_C",(KSP,PetscInt),(ksp,restart));
398  PetscFunctionReturn(PETSC_SUCCESS);
399}
400```
401
402The `Try` variant skips the function call if the method has not been composed with
403the object while the `Use` version generates an error in that case.
404See also, `PetscUseTypeMethod()`, and `PetscTryTypeMethod()`.
405
406### Simple PETSc Objects
407
408Some simple PETSc objects do not need `PETSCHEADER` and the associated
409functionality. These objects are internally named as `_n_<class>` as
410opposed to `_p_<class>`, for example, `_n_PetscFunctionList` vs `_p_Vec`.
411
412## PETSc Packages
413
414The PETSc source code is divided into the following library-level
415packages: `Sys`, `Vec`, `Mat`, `DM`, `KSP`, `SNES`, `TS`,
416`Tao`. Each of these has a directory under the `src` directory in
417the PETSc tree and, optionally, can be compiled into separate libraries.
418Each package defines one or more classes; for example, the `KSP`
419package defines the `KSP` and `PC` classes, as well as several
420utility classes. In addition, each library-level package may contain
421several class-level packages associated with individual classes in the
422library-level package. In general, most “important” classes in PETSc
423have their own class level package. Each package provides a registration
424function `XXXInitializePackage()`, for example
425`KSPInitializePackage()`, which registers all the classes and events
426for that package. Each package also registers a finalization routine,
427`XXXFinalizePackage()`, that releases all the resources used in
428registering the package, using `PetscRegisterFinalize()`. The
429registration for each package is performed “on demand” the first time a
430class in the package is utilized. This is handled, for example, with
431code such as
432
433```
434PetscErrorCode  VecCreate(MPI_Comm comm, Vec *vec)
435{
436  Vec            v;
437
438  PetscFunctionBegin;
439  PetscAssertPointer(vec,2);
440  *vec = NULL;
441  VecInitializePackage();
442  ...
443```
444