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 (*getcomm)(PetscObject,MPI_Comm*); 91 PetscErrorCode (*view)(PetscObject,Viewer); 92 PetscErrorCode (*destroy)(PetscObject); 93 PetscErrorCode (*query)(PetscObject,const char*,PetscObject*); 94 PetscErrorCode (*compose)(PetscObject,const char*,PetscObject); 95 PetscErrorCode (*composefunction)(PetscObject,const char*,void(*)(void)); 96 PetscErrorCode (*queryfunction)(PetscObject,const char*,void (**)(void)); 97} PetscOps; 98``` 99 100``` 101struct _p_<class> { 102 PetscClassId classid; 103 PetscOps *bops; 104 <class>Ops *ops; 105 MPI_Comm comm; 106 PetscLogDouble flops,time,mem; 107 int id; 108 int refct; 109 int tag; 110 DLList qlist; 111 OList olist; 112 char *type_name; 113 PetscObject parent; 114 char *name; 115 char *prefix; 116 void *cpp; 117 void **fortran_func_pointers; 118 .......... 119 CLASS-SPECIFIC DATASTRUCTURES 120}; 121``` 122 123Here `<class>ops` is a function table (like the `PetscOps` above) 124that contains the function pointers for the operations specific to that 125class. For example, the PETSc vector class object operations in 126<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/include/petsc/private/vecimpl.h.html">include/petsc/private/vecimpl.h</a> 127include the following. 128 129``` 130typedef struct _VecOps* VecOps; 131struct _VecOps { 132 PetscErrorCode (*duplicate)(Vec,Vec*); /* get single vector */ 133 PetscErrorCode (*duplicatevecs)(Vec,PetscInt,Vec**); /* get array of vectors */ 134 PetscErrorCode (*destroyvecs)(PetscInt,Vec[]); /* free array of vectors */ 135 PetscErrorCode (*dot)(Vec,Vec,PetscScalar*); /* z = x^H * y */ 136 PetscErrorCode (*mdot)(Vec,PetscInt,const Vec[],PetscScalar*); /* z[j] = x dot y[j] */ 137 PetscErrorCode (*norm)(Vec,NormType,PetscReal*); /* z = sqrt(x^H * x) */ 138 PetscErrorCode (*tdot)(Vec,Vec,PetscScalar*); /* x'*y */ 139 PetscErrorCode (*mtdot)(Vec,PetscInt,const Vec[],PetscScalar*);/* z[j] = x dot y[j] */ 140 PetscErrorCode (*scale)(Vec,PetscScalar); /* x = alpha * x */ 141 PetscErrorCode (*copy)(Vec,Vec); /* y = x */ 142 PetscErrorCode (*set)(Vec,PetscScalar); /* y = alpha */ 143 PetscErrorCode (*swap)(Vec,Vec); /* exchange x and y */ 144 PetscErrorCode (*axpy)(Vec,PetscScalar,Vec); /* y = y + alpha * x */ 145 PetscErrorCode (*axpby)(Vec,PetscScalar,PetscScalar,Vec); /* y = alpha * x + beta * y*/ 146 PetscErrorCode (*maxpy)(Vec,PetscInt,const PetscScalar*,Vec*); /* y = y + alpha[j] x[j] */ 147 ... (AND SO ON) ... 148}; 149``` 150 151``` 152struct _p_Vec { 153 PetscClassId classid; 154 PetscOps *bops; 155 VecOps *ops; 156 MPI_Comm comm; 157 PetscLogDouble flops,time,mem; 158 int id; 159 int refct; 160 int tag; 161 DLList qlist; 162 OList olist; 163 char *type_name; 164 PetscObject parent; 165 char *name; 166 char *prefix; 167 void **fortran_func_pointers; 168 void *data; /* implementation-specific data */ 169 PetscLayout map; 170 ISLocalToGlobalMapping mapping; /* mapping used in VecSetValuesLocal() */ 171}; 172``` 173 174Each PETSc object begins with a `PetscClassId`, which is used for 175error checking. Each different class of objects has its value for 176`classid`; these are used to distinguish between classes. When a new 177class is created you need to call 178 179``` 180PetscClassIdRegister(const char *classname,PetscClassId *classid); 181``` 182 183For example, 184 185``` 186PetscClassIdRegister("index set",&IS_CLASSID); 187``` 188 189you can verify that an object is valid of a particular class with 190`PetscValidHeaderSpecific`, for example, 191 192``` 193PetscValidHeaderSpecific(x,VEC_CLASSID,1); 194``` 195 196The third argument to this macro indicates the position in the calling 197sequence of the function the object was passed in. This is to generate 198more complete error messages. 199 200To check for an object of any type, use 201 202``` 203PetscValidHeader(x,1); 204``` 205 206The `obj->ops` functions provide implementations of the standard methods of the object class. Each type 207of the class may have different function pointers in the array. Subtypes sometimes replace some of the 208function pointers of the parent, so they play the role of virtual methods in C++. 209 210PETSc code that calls these function pointers should be done via 211 212``` 213PetscUseTypeMethod(obj,method,other arguments); 214PetscTryTypeMethod(obj,method,other arguments); 215``` 216 217For example, 218 219``` 220PetscErrorCode XXXOp(XXX x,YYY y) 221{ 222 PetscFunctionBegin; 223 PetscUseTypeMethod(x,op,y); 224 PetscFunctionReturn(PETSC_SUCCESS); 225} 226``` 227 228The `Try` variant skips the function call if the method has not been set while the `Use` version generates an error in that case. 229 230See also, `PetscUseMethod()`, and `PetscTryMethod()`. 231 232## Common Object Functions 233 234Several routines are provided for manipulating data within the header. 235These include the specific functions in the PETSc common function table. 236The function pointers are not called directly; rather you should call 237`PetscObjectFunctionName()`, where `FunctionName` is one of the 238functions listed below with the first letter of each word capitalized. 239 240`PetscObjectGetComm()` calls the `getcomm(PetscObject,MPI_Comm*)` function point which obtains the MPI communicator 241associated with this object. 242 243`PetscObjectView()` calls the `view(PetscObject,PetscViewer)` function point which allows you to store or visualize the 244data inside an object. If the `PetscViewer` is `NULL`, then it should cause the 245object to print information on the object to `stdout`. 246 247`PetscObjectDestroy()` calls the `destroy(PetscObject)` function pointer which causes the reference count of the object to be 248decreased by one or the object to be destroyed and all memory used by 249the object to be freed when the reference count drops to zero. If the 250object has any other objects composed with it, the `PetscObjectDestroy()` function is called on them. 251 252`PetscObjectCompose()` calls the `compose(PetscObject,const char *name,PetscObject)` function pointer which associates the 253second object with the first object and increases the reference count of 254the second object. If an object with the same name was previously 255composed, that object is dereferenced and replaced with the new object. 256If the second object is `NULL` and an object with the same name has 257already been composed, that object is dereferenced (the `PetscObjectDestroy()` 258function is called on it, and that object is removed from the first 259object). This is a way to remove, by name, an object that was previously 260composed. 261 262`PetscObjectQuery()` calls the `query(PetscObject,const char *name,PetscObject*)` function pointer which retrieves an object 263that was previously composed with the first object via 264`PetscObjectCompose()`. It retrieves a `NULL` if no object with that 265name was previously composed. 266 267`PetscObjectComposeFunction()` calls the `composefunction(PetscObject,const char *name,void *func)` function pointer which associates 268a function pointer with an object. If the object already had a composed 269function with the same name, the old one is replaced. If `func` is 270`NULL`, the existing function is removed from the object. The string 271`name` is the character string name of the function. 272 273For example, `fname` may be `PCCreate_LU`. 274 275`PetscObjectQueryFunction()` calls the `queryfunction(PetscObject,const char *name,void **func)` function pointer which retrieves a 276function pointer that was associated with the object via 277`PetscObjectComposeFunction()`. If dynamic libraries are used, the 278function is loaded into memory at this time (if it has not been 279previously loaded), not when the `PetscObjectComposeFunction()` routine was 280called. 281 282Since the object composition allows one to compose PETSc objects 283with PETSc objects, PETSc provides the 284convenience object `PetscContainer`, created with the routine 285`PetscContainerCreate(MPI_Comm,PetscContainer*)`, to allow wrapping any 286kind of data into a PETSc object that can then be composed with a PETSc 287object. One can also use `PetscObjectContainerCompose()` and `PetscObjectContainerQuery()` to compose 288arbitrary pointers with a PETSc object. 289 290## Object Function Implementation 291 292This section discusses how PETSc implements the `compose()`, 293`query()`, `composefunction()`, and `queryfunction()` functions 294for its object implementations. Other PETSc-compatible class 295implementations are free to manage these functions in any manner; but 296unless there is a specific reason, they should use the PETSc defaults so 297that the library writer does not have to “reinvent the wheel.” 298 299### Compose and Query Objects 300 301In 302<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/objects/olist.c.html">src/sys/objects/olist.c</a> 303PETSc defines a C `struct` 304 305``` 306typedef struct _PetscObjectList* PetscObjectList; 307struct _PetscObjectList { 308 char name[128]; 309 PetscObject obj; 310 PetscObjectList next; 311}; 312``` 313 314from which linked lists of composed objects may be constructed. The 315routines to manipulate these elementary objects are 316 317``` 318int PetscObjectListAdd(PetscObjectList *fl,const char *name,PetscObject obj); 319int PetscObjectListDestroy(PetscObjectList *fl); 320int PetscObjectListFind(PetscObjectList fl,const char *name,PetscObject *obj) 321int PetscObjectListDuplicate(PetscObjectList fl,PetscObjectList *nl); 322``` 323 324The function `PetscObjectListAdd()` will create the initial 325PetscObjectList if the argument `fl` points to a NULL. 326 327The PETSc object `compose()` and `query()` functions are as follows 328(defined in 329<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/objects/inherit.c.html">src/sys/objects/inherit.c</a> 330 331``` 332PetscErrorCode PetscObjectCompose_Petsc(PetscObject obj,const char *name,PetscObject ptr) 333{ 334 PetscFunctionBegin; 335 PetscCall(PetscObjectListAdd(&obj->olist,name,ptr)); 336 PetscFunctionReturn(PETSC_SUCCESS); 337} 338 339PetscErrorCode PetscObjectQuery_Petsc(PetscObject obj,const char *name,PetscObject *ptr) 340{ 341 PetscFunctionBegin; 342 PetscCall(PetscObjectListFind(obj->olist,name,ptr)); 343 PetscFunctionReturn(PETSC_SUCCESS); 344} 345``` 346 347### Compose and Query Functions 348 349PETSc allows you to compose functions by specifying a name and function 350pointer. In 351<a href="PETSC_DOC_OUT_ROOT_PLACEHOLDER/src/sys/dll/reg.c.html">src/sys/dll/reg.c</a> 352PETSc defines the following linked list structure. 353 354``` 355struct _n_PetscFunctionList { 356 void (*routine)(void); /* the routine */ 357 char *name; /* string to identify routine */ 358 PetscFunctionList next; /* next pointer */ 359 PetscFunctionList next_list; /* used to maintain list of all lists for freeing */ 360}; 361``` 362 363Each PETSc object contains a `PetscFunctionList` object. The 364`composefunction()` and `queryfunction()` are given by the 365following. 366 367``` 368PetscErrorCode PetscObjectComposeFunction_Petsc(PetscObject obj,const char *name,void *ptr) 369{ 370 PetscFunctionBegin; 371 PetscCall(PetscFunctionListAdd(&obj->qlist,name,fname,ptr)); 372 PetscFunctionReturn(PETSC_SUCCESS); 373} 374 375PetscErrorCode PetscObjectQueryFunction_Petsc(PetscObject obj,const char *name,void (**ptr)(void)) 376{ 377 PetscFunctionBegin; 378 PetscCall(PetscFunctionListFind(obj->qlist,name,ptr)); 379 PetscFunctionReturn(PETSC_SUCCESS); 380} 381``` 382 383In addition to using the `PetscFunctionList` mechanism to compose 384functions into PETSc objects, it is also used to allow registration of 385new class implementations; for example, new preconditioners. 386 387PETSc code that calls composed functions should be done via 388 389``` 390PetscUseMethod(obj,"method",(Argument types),(argument variables)); 391PetscTryMethod(obj,"method",(Argument types),(argument variables)); 392``` 393 394For example, 395 396``` 397PetscErrorCode KSPGMRESSetRestart(KSP ksp, PetscInt restart) 398{ 399 PetscFunctionBegin; 400 PetscValidLogicalCollectiveInt(ksp,restart,2); 401 402 PetscTryMethod(ksp,"KSPGMRESSetRestart_C",(KSP,PetscInt),(ksp,restart)); 403 PetscFunctionReturn(PETSC_SUCCESS); 404} 405``` 406 407The `Try` variant skips the function call if the method has not been composed with 408the object while the `Use` version generates an error in that case. 409See also, `PetscUseTypeMethod()`, and `PetscTryTypeMethod()`. 410 411### Simple PETSc Objects 412 413Some simple PETSc objects do not need `PETSCHEADER` and the associated 414functionality. These objects are internally named as `_n_<class>` as 415opposed to `_p_<class>`, for example, `_n_PetscFunctionList` vs `_p_Vec`. 416 417## PETSc Packages 418 419The PETSc source code is divided into the following library-level 420packages: `Sys`, `Vec`, `Mat`, `DM`, `KSP`, `SNES`, `TS`, 421`Tao`. Each of these has a directory under the `src` directory in 422the PETSc tree and, optionally, can be compiled into separate libraries. 423Each package defines one or more classes; for example, the `KSP` 424package defines the `KSP` and `PC` classes, as well as several 425utility classes. In addition, each library-level package may contain 426several class-level packages associated with individual classes in the 427library-level package. In general, most “important” classes in PETSc 428have their own class level package. Each package provides a registration 429function `XXXInitializePackage()`, for example 430`KSPInitializePackage()`, which registers all the classes and events 431for that package. Each package also registers a finalization routine, 432`XXXFinalizePackage()`, that releases all the resources used in 433registering the package, using `PetscRegisterFinalize()`. The 434registration for each package is performed “on demand” the first time a 435class in the package is utilized. This is handled, for example, with 436code such as 437 438``` 439PetscErrorCode VecCreate(MPI_Comm comm, Vec *vec) 440{ 441 Vec v; 442 443 PetscFunctionBegin; 444 PetscAssertPointer(vec,2); 445 *vec = NULL; 446 VecInitializePackage(); 447 ... 448``` 449