1 /* 2 Provides utility routines for manipulating any type of PETSc object. 3 */ 4 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 5 #include <petscviewer.h> 6 7 PETSC_INTERN PetscObject *PetscObjects; 8 PETSC_INTERN PetscInt PetscObjectsCounts; 9 PETSC_INTERN PetscInt PetscObjectsMaxCounts; 10 PETSC_INTERN PetscBool PetscObjectsLog; 11 12 PetscObject *PetscObjects = NULL; 13 PetscInt PetscObjectsCounts = 0, PetscObjectsMaxCounts = 0; 14 PetscBool PetscObjectsLog = PETSC_FALSE; 15 16 PetscObjectId PetscObjectNewId_Internal(void) 17 { 18 static PetscObjectId idcnt = 1; 19 return idcnt++; 20 } 21 22 PetscErrorCode PetscHeaderCreate_Function(PetscErrorCode ierr, PetscObject *h, PetscClassId classid, const char class_name[], const char descr[], const char mansec[], MPI_Comm comm, PetscObjectDestroyFunction destroy, PetscObjectViewFunction view) 23 { 24 if (ierr) return ierr; 25 PetscFunctionBegin; 26 PetscCall(PetscHeaderCreate_Private(*h, classid, class_name, descr, mansec, comm, destroy, view)); 27 PetscCall(PetscLogObjectCreate(*h)); 28 PetscFunctionReturn(PETSC_SUCCESS); 29 } 30 31 /* 32 PetscHeaderCreate_Private - Fills in the default values. 33 */ 34 PetscErrorCode PetscHeaderCreate_Private(PetscObject h, PetscClassId classid, const char class_name[], const char descr[], const char mansec[], MPI_Comm comm, PetscObjectDestroyFunction destroy, PetscObjectViewFunction view) 35 { 36 void *get_tmp; 37 PetscInt64 *cidx; 38 PetscMPIInt flg; 39 40 PetscFunctionBegin; 41 h->classid = classid; 42 h->class_name = (char *)class_name; 43 h->description = (char *)descr; 44 h->mansec = (char *)mansec; 45 h->refct = 1; 46 h->non_cyclic_references = NULL; 47 h->id = PetscObjectNewId_Internal(); 48 h->bops->destroy = destroy; 49 h->bops->view = view; 50 51 PetscCall(PetscCommDuplicate(comm, &h->comm, &h->tag)); 52 53 /* Increment and store current object creation index */ 54 PetscCallMPI(MPI_Comm_get_attr(h->comm, Petsc_CreationIdx_keyval, &get_tmp, &flg)); 55 PetscCheck(flg, h->comm, PETSC_ERR_ARG_CORRUPT, "MPI_Comm does not have an object creation index"); 56 cidx = (PetscInt64 *)get_tmp; 57 h->cidx = (*cidx)++; 58 PetscCallMPI(MPI_Comm_set_attr(h->comm, Petsc_CreationIdx_keyval, cidx)); 59 60 /* Keep a record of object created */ 61 if (PetscDefined(USE_LOG) && PetscObjectsLog) { 62 PetscObject *newPetscObjects; 63 PetscInt newPetscObjectsMaxCounts; 64 65 PetscObjectsCounts++; 66 for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) { 67 if (!PetscObjects[i]) { 68 PetscObjects[i] = h; 69 PetscFunctionReturn(PETSC_SUCCESS); 70 } 71 } 72 /* Need to increase the space for storing PETSc objects */ 73 if (!PetscObjectsMaxCounts) newPetscObjectsMaxCounts = 100; 74 else newPetscObjectsMaxCounts = 2 * PetscObjectsMaxCounts; 75 PetscCall(PetscCalloc1(newPetscObjectsMaxCounts, &newPetscObjects)); 76 PetscCall(PetscArraycpy(newPetscObjects, PetscObjects, PetscObjectsMaxCounts)); 77 PetscCall(PetscFree(PetscObjects)); 78 79 PetscObjects = newPetscObjects; 80 PetscObjects[PetscObjectsMaxCounts] = h; 81 PetscObjectsMaxCounts = newPetscObjectsMaxCounts; 82 } 83 PetscFunctionReturn(PETSC_SUCCESS); 84 } 85 86 PETSC_INTERN PetscBool PetscMemoryCollectMaximumUsage; 87 PETSC_INTERN PetscLogDouble PetscMemoryMaximumUsage; 88 89 PetscErrorCode PetscHeaderDestroy_Function(PetscObject *h) 90 { 91 PetscFunctionBegin; 92 PetscCall(PetscLogObjectDestroy(*h)); 93 PetscCall(PetscHeaderDestroy_Private(*h, PETSC_FALSE)); 94 PetscCall(PetscFree(*h)); 95 PetscFunctionReturn(PETSC_SUCCESS); 96 } 97 98 /* 99 PetscHeaderDestroy_Private - Destroys a base PETSc object header. Called by 100 the macro PetscHeaderDestroy(). 101 */ 102 PetscErrorCode PetscHeaderDestroy_Private(PetscObject obj, PetscBool clear_for_reuse) 103 { 104 PetscFunctionBegin; 105 PetscValidHeader(obj, 1); 106 PetscCall(PetscComposedQuantitiesDestroy(obj)); 107 if (PetscMemoryCollectMaximumUsage) { 108 PetscLogDouble usage; 109 110 PetscCall(PetscMemoryGetCurrentUsage(&usage)); 111 if (usage > PetscMemoryMaximumUsage) PetscMemoryMaximumUsage = usage; 112 } 113 /* first destroy things that could execute arbitrary code */ 114 if (obj->python_destroy) { 115 void *python_context = obj->python_context; 116 PetscErrorCode (*python_destroy)(void *) = obj->python_destroy; 117 118 obj->python_context = NULL; 119 obj->python_destroy = NULL; 120 PetscCall((*python_destroy)(python_context)); 121 } 122 PetscCall(PetscObjectDestroyOptionsHandlers(obj)); 123 PetscCall(PetscObjectListDestroy(&obj->olist)); 124 125 /* destroy allocated quantities */ 126 if (PetscPrintFunctionList) PetscCall(PetscFunctionListPrintNonEmpty(obj->qlist)); 127 PetscCheck(--(obj->refct) <= 0, obj->comm, PETSC_ERR_PLIB, "Destroying a PetscObject (%s) with reference count %" PetscInt_FMT " >= 1", obj->name ? obj->name : "unnamed", obj->refct); 128 PetscCall(PetscFree(obj->name)); 129 PetscCall(PetscFree(obj->prefix)); 130 PetscCall(PetscFree(obj->type_name)); 131 132 if (clear_for_reuse) { 133 /* we will assume that obj->bops->view and destroy are safe to leave as-is */ 134 135 /* reset quantities, in order of appearance in _p_PetscObject */ 136 obj->id = PetscObjectNewId_Internal(); 137 obj->refct = 1; 138 obj->tablevel = 0; 139 obj->state = 0; 140 /* don't deallocate, zero these out instead */ 141 PetscCall(PetscFunctionListClear(obj->qlist)); 142 PetscCall(PetscArrayzero(obj->fortran_func_pointers, obj->num_fortran_func_pointers)); 143 PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS])); 144 PetscCall(PetscArrayzero(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE], obj->num_fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE])); 145 obj->optionsprinted = PETSC_FALSE; 146 #if PetscDefined(HAVE_SAWS) 147 obj->amsmem = PETSC_FALSE; 148 obj->amspublishblock = PETSC_FALSE; 149 #endif 150 obj->options = NULL; 151 obj->donotPetscObjectPrintClassNamePrefixType = PETSC_FALSE; 152 } else { 153 PetscCall(PetscFunctionListDestroy(&obj->qlist)); 154 PetscCall(PetscFree(obj->fortran_func_pointers)); 155 PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_CLASS])); 156 PetscCall(PetscFree(obj->fortrancallback[PETSC_FORTRAN_CALLBACK_SUBTYPE])); 157 PetscCall(PetscCommDestroy(&obj->comm)); 158 obj->classid = PETSCFREEDHEADER; 159 160 if (PetscDefined(USE_LOG) && PetscObjectsLog) { 161 /* Record object removal from list of all objects */ 162 for (PetscInt i = 0; i < PetscObjectsMaxCounts; ++i) { 163 if (PetscObjects[i] == obj) { 164 PetscObjects[i] = NULL; 165 --PetscObjectsCounts; 166 break; 167 } 168 } 169 if (!PetscObjectsCounts) { 170 PetscCall(PetscFree(PetscObjects)); 171 PetscObjectsMaxCounts = 0; 172 } 173 } 174 } 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 /* 179 PetscHeaderReset_Internal - "Reset" a PetscObject header. This is tantamount to destroying 180 the object but does not free all resources. The object retains its: 181 182 - classid 183 - bops->view 184 - bops->destroy 185 - comm 186 - tag 187 - class_name 188 - description 189 - mansec 190 - cpp 191 192 Note that while subclass information is lost, superclass info remains. Thus this function is 193 intended to be used to reuse a PetscObject within the same class to avoid reallocating its 194 resources. 195 */ 196 PetscErrorCode PetscHeaderReset_Internal(PetscObject obj) 197 { 198 PetscFunctionBegin; 199 PetscCall(PetscHeaderDestroy_Private(obj, PETSC_TRUE)); 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 /*@C 204 PetscObjectCopyFortranFunctionPointers - Copy function pointers to another object 205 206 Logically Collective 207 208 Input Parameters: 209 + src - source object 210 - dest - destination object 211 212 Level: developer 213 214 Note: 215 Both objects must have the same class. 216 217 This is used to help manage user callback functions that were provided in Fortran 218 219 .seealso: `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()` 220 @*/ 221 PetscErrorCode PetscObjectCopyFortranFunctionPointers(PetscObject src, PetscObject dest) 222 { 223 PetscFortranCallbackId cbtype, numcb[PETSC_FORTRAN_CALLBACK_MAXTYPE]; 224 225 PetscFunctionBegin; 226 PetscValidHeader(src, 1); 227 PetscValidHeader(dest, 2); 228 PetscCheck(src->classid == dest->classid, src->comm, PETSC_ERR_ARG_INCOMP, "Objects must be of the same class"); 229 230 PetscCall(PetscFree(dest->fortran_func_pointers)); 231 PetscCall(PetscMalloc(src->num_fortran_func_pointers * sizeof(void (*)(void)), &dest->fortran_func_pointers)); 232 PetscCall(PetscMemcpy(dest->fortran_func_pointers, src->fortran_func_pointers, src->num_fortran_func_pointers * sizeof(void (*)(void)))); 233 234 dest->num_fortran_func_pointers = src->num_fortran_func_pointers; 235 236 PetscCall(PetscFortranCallbackGetSizes(src->classid, &numcb[PETSC_FORTRAN_CALLBACK_CLASS], &numcb[PETSC_FORTRAN_CALLBACK_SUBTYPE])); 237 for (cbtype = PETSC_FORTRAN_CALLBACK_CLASS; cbtype < PETSC_FORTRAN_CALLBACK_MAXTYPE; cbtype++) { 238 PetscCall(PetscFree(dest->fortrancallback[cbtype])); 239 PetscCall(PetscCalloc1(numcb[cbtype], &dest->fortrancallback[cbtype])); 240 PetscCall(PetscMemcpy(dest->fortrancallback[cbtype], src->fortrancallback[cbtype], src->num_fortrancallback[cbtype] * sizeof(PetscFortranCallback))); 241 dest->num_fortrancallback[cbtype] = src->num_fortrancallback[cbtype]; 242 } 243 PetscFunctionReturn(PETSC_SUCCESS); 244 } 245 246 /*@C 247 PetscObjectSetFortranCallback - set fortran callback function pointer and context 248 249 Logically Collective 250 251 Input Parameters: 252 + obj - object on which to set callback 253 . cbtype - callback type (class or subtype) 254 . cid - address of callback Id, updated if not yet initialized (zero) 255 . func - Fortran function 256 - ctx - Fortran context 257 258 Level: developer 259 260 Note: 261 This is used to help manage user callback functions that were provided in Fortran 262 263 .seealso: `PetscObjectGetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()` 264 @*/ 265 PetscErrorCode PetscObjectSetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId *cid, void (*func)(void), void *ctx) 266 { 267 const char *subtype = NULL; 268 269 PetscFunctionBegin; 270 PetscValidHeader(obj, 1); 271 if (cbtype == PETSC_FORTRAN_CALLBACK_SUBTYPE) subtype = obj->type_name; 272 if (!*cid) PetscCall(PetscFortranCallbackRegister(obj->classid, subtype, cid)); 273 if (*cid >= PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype]) { 274 PetscFortranCallbackId oldnum = obj->num_fortrancallback[cbtype]; 275 PetscFortranCallbackId newnum = PetscMax(*cid - PETSC_SMALLEST_FORTRAN_CALLBACK + 1, 2 * oldnum); 276 PetscFortranCallback *callback; 277 PetscCall(PetscMalloc1(newnum, &callback)); 278 PetscCall(PetscMemcpy(callback, obj->fortrancallback[cbtype], oldnum * sizeof(*obj->fortrancallback[cbtype]))); 279 PetscCall(PetscFree(obj->fortrancallback[cbtype])); 280 281 obj->fortrancallback[cbtype] = callback; 282 obj->num_fortrancallback[cbtype] = newnum; 283 } 284 obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].func = func; 285 obj->fortrancallback[cbtype][*cid - PETSC_SMALLEST_FORTRAN_CALLBACK].ctx = ctx; 286 PetscFunctionReturn(PETSC_SUCCESS); 287 } 288 289 /*@C 290 PetscObjectGetFortranCallback - get fortran callback function pointer and context 291 292 Logically Collective 293 294 Input Parameters: 295 + obj - object on which to get callback 296 . cbtype - callback type 297 - cid - address of callback Id 298 299 Output Parameters: 300 + func - Fortran function (or `NULL` if not needed) 301 - ctx - Fortran context (or `NULL` if not needed) 302 303 Level: developer 304 305 Note: 306 This is used to help manage user callback functions that were provided in Fortran 307 308 .seealso: `PetscObjectSetFortranCallback()`, `PetscFortranCallbackRegister()`, `PetscFortranCallbackGetSizes()` 309 @*/ 310 PetscErrorCode PetscObjectGetFortranCallback(PetscObject obj, PetscFortranCallbackType cbtype, PetscFortranCallbackId cid, void (**func)(void), void **ctx) 311 { 312 PetscFortranCallback *cb; 313 314 PetscFunctionBegin; 315 PetscValidHeader(obj, 1); 316 PetscCheck(cid >= PETSC_SMALLEST_FORTRAN_CALLBACK, obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback Id invalid"); 317 PetscCheck(cid < PETSC_SMALLEST_FORTRAN_CALLBACK + obj->num_fortrancallback[cbtype], obj->comm, PETSC_ERR_ARG_CORRUPT, "Fortran callback not set on this object"); 318 cb = &obj->fortrancallback[cbtype][cid - PETSC_SMALLEST_FORTRAN_CALLBACK]; 319 if (func) *func = cb->func; 320 if (ctx) *ctx = cb->ctx; 321 PetscFunctionReturn(PETSC_SUCCESS); 322 } 323 324 #if defined(PETSC_USE_LOG) 325 /*@C 326 PetscObjectsDump - Prints all the currently existing objects. 327 328 On rank 0 of `PETSC_COMM_WORLD` prints the values 329 330 Input Parameters: 331 + fd - file pointer 332 - all - by default only tries to display objects created explicitly by the user, if all is `PETSC_TRUE` then lists all outstanding objects 333 334 Options Database Key: 335 . -objects_dump <all> - print information about all the objects that exist at the end of the programs run 336 337 Level: advanced 338 339 .seealso: `PetscObject` 340 @*/ 341 PetscErrorCode PetscObjectsDump(FILE *fd, PetscBool all) 342 { 343 PetscInt i, j, k = 0; 344 PetscObject h; 345 346 PetscFunctionBegin; 347 if (PetscObjectsCounts) { 348 PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "The following objects were never freed\n")); 349 PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "-----------------------------------------\n")); 350 for (i = 0; i < PetscObjectsMaxCounts; i++) { 351 if ((h = PetscObjects[i])) { 352 PetscCall(PetscObjectName(h)); 353 { 354 PetscStack *stack = NULL; 355 char *create = NULL, *rclass = NULL; 356 357 /* if the PETSc function the user calls is not a create then this object was NOT directly created by them */ 358 PetscCall(PetscMallocGetStack(h, &stack)); 359 if (stack) { 360 k = stack->currentsize - 2; 361 if (!all) { 362 k = 0; 363 while (!stack->petscroutine[k]) k++; 364 PetscCall(PetscStrstr(stack->function[k], "Create", &create)); 365 if (!create) PetscCall(PetscStrstr(stack->function[k], "Get", &create)); 366 PetscCall(PetscStrstr(stack->function[k], h->class_name, &rclass)); 367 if (!create) continue; 368 if (!rclass) continue; 369 } 370 } 371 372 PetscCall(PetscFPrintf(PETSC_COMM_WORLD, fd, "[%d] %s %s %s\n", PetscGlobalRank, h->class_name, h->type_name, h->name)); 373 374 PetscCall(PetscMallocGetStack(h, &stack)); 375 if (stack) { 376 for (j = k; j >= 0; j--) fprintf(fd, " [%d] %s() in %s\n", PetscGlobalRank, stack->function[j], stack->file[j]); 377 } 378 } 379 } 380 } 381 } 382 PetscFunctionReturn(PETSC_SUCCESS); 383 } 384 385 /*@C 386 PetscObjectsView - Prints the currently existing objects. 387 388 Logically Collective 389 390 Input Parameter: 391 . viewer - must be an `PETSCVIEWERASCII` viewer 392 393 Level: advanced 394 395 .seealso: `PetscObject` 396 @*/ 397 PetscErrorCode PetscObjectsView(PetscViewer viewer) 398 { 399 PetscBool isascii; 400 FILE *fd; 401 402 PetscFunctionBegin; 403 if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD; 404 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 405 PetscCheck(isascii, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Only supports ASCII viewer"); 406 PetscCall(PetscViewerASCIIGetPointer(viewer, &fd)); 407 PetscCall(PetscObjectsDump(fd, PETSC_TRUE)); 408 PetscFunctionReturn(PETSC_SUCCESS); 409 } 410 411 /*@C 412 PetscObjectsGetObject - Get a pointer to a named object 413 414 Not Collective 415 416 Input Parameter: 417 . name - the name of an object 418 419 Output Parameters: 420 + obj - the object or `NULL` if there is no object 421 - classname - the name of the class 422 423 Level: advanced 424 425 .seealso: `PetscObject` 426 @*/ 427 PetscErrorCode PetscObjectsGetObject(const char *name, PetscObject *obj, char **classname) 428 { 429 PetscInt i; 430 PetscObject h; 431 PetscBool flg; 432 433 PetscFunctionBegin; 434 PetscAssertPointer(name, 1); 435 PetscAssertPointer(obj, 2); 436 *obj = NULL; 437 for (i = 0; i < PetscObjectsMaxCounts; i++) { 438 if ((h = PetscObjects[i])) { 439 PetscCall(PetscObjectName(h)); 440 PetscCall(PetscStrcmp(h->name, name, &flg)); 441 if (flg) { 442 *obj = h; 443 if (classname) *classname = h->class_name; 444 PetscFunctionReturn(PETSC_SUCCESS); 445 } 446 } 447 } 448 PetscFunctionReturn(PETSC_SUCCESS); 449 } 450 #endif 451 452 /*@ 453 PetscObjectSetPrintedOptions - indicate to an object that it should behave as if it has already printed the help for its options so it will not display the help message 454 455 Input Parameter: 456 . obj - the `PetscObject` 457 458 Level: developer 459 460 Developer Notes: 461 This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by 462 `PCBJACOBI` from all printing the same help messages to the screen 463 464 .seealso: `PetscOptionsInsert()`, `PetscObject` 465 @*/ 466 PetscErrorCode PetscObjectSetPrintedOptions(PetscObject obj) 467 { 468 PetscFunctionBegin; 469 PetscAssertPointer(obj, 1); 470 obj->optionsprinted = PETSC_TRUE; 471 PetscFunctionReturn(PETSC_SUCCESS); 472 } 473 474 /*@ 475 PetscObjectInheritPrintedOptions - If the child object is not on the rank 0 process of the parent object and the child is sequential then the child gets it set. 476 477 Input Parameters: 478 + pobj - the parent object 479 - obj - the `PetscObject` 480 481 Level: developer 482 483 Developer Notes: 484 This is used, for example to prevent sequential objects that are created from a parallel object; such as the `KSP` created by 485 `PCBJACOBI` from all printing the same help messages to the screen 486 487 This will not handle more complicated situations like with `PCGASM` where children may live on any subset of the parent's processes and overlap 488 489 .seealso: `PetscOptionsInsert()`, `PetscObjectSetPrintedOptions()`, `PetscObject` 490 @*/ 491 PetscErrorCode PetscObjectInheritPrintedOptions(PetscObject pobj, PetscObject obj) 492 { 493 PetscMPIInt prank, size; 494 495 PetscFunctionBegin; 496 PetscValidHeader(pobj, 1); 497 PetscValidHeader(obj, 2); 498 PetscCallMPI(MPI_Comm_rank(pobj->comm, &prank)); 499 PetscCallMPI(MPI_Comm_size(obj->comm, &size)); 500 if (size == 1 && prank > 0) obj->optionsprinted = PETSC_TRUE; 501 PetscFunctionReturn(PETSC_SUCCESS); 502 } 503 504 /*@C 505 PetscObjectAddOptionsHandler - Adds an additional function to check for options when `XXXSetFromOptions()` is called. 506 507 Not Collective 508 509 Input Parameters: 510 + obj - the PETSc object 511 . handle - function that checks for options 512 . destroy - function to destroy context if provided 513 - ctx - optional context for check function 514 515 Level: developer 516 517 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectProcessOptionsHandlers()`, `PetscObjectDestroyOptionsHandlers()`, 518 `PetscObject` 519 @*/ 520 PetscErrorCode PetscObjectAddOptionsHandler(PetscObject obj, PetscErrorCode (*handle)(PetscObject, PetscOptionItems *, void *), PetscErrorCode (*destroy)(PetscObject, void *), void *ctx) 521 { 522 PetscFunctionBegin; 523 PetscValidHeader(obj, 1); 524 PetscCheck(obj->noptionhandler < PETSC_MAX_OPTIONS_HANDLER, obj->comm, PETSC_ERR_ARG_OUTOFRANGE, "To many options handlers added"); 525 obj->optionhandler[obj->noptionhandler] = handle; 526 obj->optiondestroy[obj->noptionhandler] = destroy; 527 obj->optionctx[obj->noptionhandler++] = ctx; 528 PetscFunctionReturn(PETSC_SUCCESS); 529 } 530 531 /*@C 532 PetscObjectProcessOptionsHandlers - Calls all the options handlers attached to an object 533 534 Not Collective 535 536 Input Parameters: 537 + obj - the PETSc object 538 - PetscOptionsObject - the options context 539 540 Level: developer 541 542 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectDestroyOptionsHandlers()`, 543 `PetscObject` 544 @*/ 545 PetscErrorCode PetscObjectProcessOptionsHandlers(PetscObject obj, PetscOptionItems *PetscOptionsObject) 546 { 547 PetscFunctionBegin; 548 PetscValidHeader(obj, 1); 549 for (PetscInt i = 0; i < obj->noptionhandler; i++) PetscCall((*obj->optionhandler[i])(obj, PetscOptionsObject, obj->optionctx[i])); 550 PetscFunctionReturn(PETSC_SUCCESS); 551 } 552 553 /*@C 554 PetscObjectDestroyOptionsHandlers - Destroys all the option handlers attached to an object 555 556 Not Collective 557 558 Input Parameter: 559 . obj - the PETSc object 560 561 Level: developer 562 563 .seealso: `KSPSetFromOptions()`, `PCSetFromOptions()`, `SNESSetFromOptions()`, `PetscObjectAddOptionsHandler()`, `PetscObjectProcessOptionsHandlers()`, 564 `PetscObject` 565 @*/ 566 PetscErrorCode PetscObjectDestroyOptionsHandlers(PetscObject obj) 567 { 568 PetscFunctionBegin; 569 PetscValidHeader(obj, 1); 570 for (PetscInt i = 0; i < obj->noptionhandler; i++) { 571 if (obj->optiondestroy[i]) PetscCall((*obj->optiondestroy[i])(obj, obj->optionctx[i])); 572 } 573 obj->noptionhandler = 0; 574 PetscFunctionReturn(PETSC_SUCCESS); 575 } 576 577 /*@C 578 PetscObjectReference - Indicates to any `PetscObject` that it is being 579 referenced by another `PetscObject`. This increases the reference 580 count for that object by one. 581 582 Logically Collective 583 584 Input Parameter: 585 . obj - the PETSc object. This must be cast with (`PetscObject`), for example, 586 `PetscObjectReference`((`PetscObject`)mat); 587 588 Level: advanced 589 590 .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObject` 591 @*/ 592 PetscErrorCode PetscObjectReference(PetscObject obj) 593 { 594 PetscFunctionBegin; 595 if (!obj) PetscFunctionReturn(PETSC_SUCCESS); 596 PetscValidHeader(obj, 1); 597 obj->refct++; 598 PetscFunctionReturn(PETSC_SUCCESS); 599 } 600 601 /*@C 602 PetscObjectGetReference - Gets the current reference count for 603 any PETSc object. 604 605 Not Collective 606 607 Input Parameter: 608 . obj - the PETSc object; this must be cast with (`PetscObject`), for example, 609 `PetscObjectGetReference`((`PetscObject`)mat,&cnt); 610 611 Output Parameter: 612 . cnt - the reference count 613 614 Level: advanced 615 616 .seealso: `PetscObjectCompose()`, `PetscObjectDereference()`, `PetscObjectReference()`, `PetscObject` 617 @*/ 618 PetscErrorCode PetscObjectGetReference(PetscObject obj, PetscInt *cnt) 619 { 620 PetscFunctionBegin; 621 PetscValidHeader(obj, 1); 622 PetscAssertPointer(cnt, 2); 623 *cnt = obj->refct; 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 /*@C 628 PetscObjectDereference - Indicates to any `PetscObject` that it is being 629 referenced by one less `PetscObject`. This decreases the reference 630 count for that object by one. 631 632 Collective on obj if reference reaches 0 otherwise Logically Collective 633 634 Input Parameter: 635 . obj - the PETSc object; this must be cast with (`PetscObject`), for example, 636 `PetscObjectDereference`((`PetscObject`)mat); 637 638 Level: advanced 639 640 Note: 641 `PetscObjectDestroy()` sets the obj pointer to null after the call, this routine does not. 642 643 .seealso: `PetscObjectCompose()`, `PetscObjectReference()`, `PetscObjectDestroy()`, `PetscObject` 644 @*/ 645 PetscErrorCode PetscObjectDereference(PetscObject obj) 646 { 647 PetscFunctionBegin; 648 if (!obj) PetscFunctionReturn(PETSC_SUCCESS); 649 PetscValidHeader(obj, 1); 650 if (obj->bops->destroy) PetscCall((*obj->bops->destroy)(&obj)); 651 else PetscCheck(--(obj->refct), PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic destroy routine"); 652 PetscFunctionReturn(PETSC_SUCCESS); 653 } 654 655 /* 656 The following routines are the versions private to the PETSc object 657 data structures. 658 */ 659 PetscErrorCode PetscObjectRemoveReference(PetscObject obj, const char name[]) 660 { 661 PetscFunctionBegin; 662 PetscValidHeader(obj, 1); 663 PetscCall(PetscObjectListRemoveReference(&obj->olist, name)); 664 PetscFunctionReturn(PETSC_SUCCESS); 665 } 666 667 /*@C 668 PetscObjectCompose - Associates another PETSc object with a given PETSc object. 669 670 Not Collective 671 672 Input Parameters: 673 + obj - the PETSc object; this must be cast with (`PetscObject`), for example, 674 `PetscObjectCompose`((`PetscObject`)mat,...); 675 . name - name associated with the child object 676 - ptr - the other PETSc object to associate with the PETSc object; this must also be 677 cast with (`PetscObject`) 678 679 Level: advanced 680 681 Notes: 682 The second objects reference count is automatically increased by one when it is 683 composed. 684 685 Replaces any previous object that had the same name. 686 687 If ptr is null and name has previously been composed using an object, then that 688 entry is removed from the obj. 689 690 `PetscObjectCompose()` can be used with any PETSc object (such as 691 `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object. 692 693 `PetscContainerCreate()` can be used to create an object from a 694 user-provided pointer that may then be composed with PETSc objects using `PetscObjectCompose()` 695 696 .seealso: `PetscObjectQuery()`, `PetscContainerCreate()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer`, 697 `PetscContainerSetPointer()`, `PetscObject` 698 @*/ 699 PetscErrorCode PetscObjectCompose(PetscObject obj, const char name[], PetscObject ptr) 700 { 701 PetscFunctionBegin; 702 PetscValidHeader(obj, 1); 703 PetscAssertPointer(name, 2); 704 if (ptr) PetscValidHeader(ptr, 3); 705 PetscCheck(obj != ptr, PetscObjectComm((PetscObject)obj), PETSC_ERR_SUP, "Cannot compose object with itself"); 706 if (ptr) { 707 char *tname; 708 PetscBool skipreference; 709 710 PetscCall(PetscObjectListReverseFind(ptr->olist, obj, &tname, &skipreference)); 711 if (tname) PetscCheck(skipreference, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "An object cannot be composed with an object that was composed with it"); 712 } 713 PetscCall(PetscObjectListAdd(&obj->olist, name, ptr)); 714 PetscFunctionReturn(PETSC_SUCCESS); 715 } 716 717 /*@C 718 PetscObjectQuery - Gets a PETSc object associated with a given object that was composed with `PetscObjectCompose()` 719 720 Not Collective 721 722 Input Parameters: 723 + obj - the PETSc object 724 Thus must be cast with a (`PetscObject`), for example, 725 `PetscObjectCompose`((`PetscObject`)mat,...); 726 . name - name associated with child object 727 - ptr - the other PETSc object associated with the PETSc object, this must be 728 cast with (`PetscObject`*) 729 730 Level: advanced 731 732 Note: 733 The reference count of neither object is increased in this call 734 735 .seealso: `PetscObjectCompose()`, `PetscObjectComposeFunction()`, `PetscObjectQueryFunction()`, `PetscContainer` 736 `PetscContainerGetPointer()`, `PetscObject` 737 @*/ 738 PetscErrorCode PetscObjectQuery(PetscObject obj, const char name[], PetscObject *ptr) 739 { 740 PetscFunctionBegin; 741 PetscValidHeader(obj, 1); 742 PetscAssertPointer(name, 2); 743 PetscAssertPointer(ptr, 3); 744 PetscCall(PetscObjectListFind(obj->olist, name, ptr)); 745 PetscFunctionReturn(PETSC_SUCCESS); 746 } 747 748 /*MC 749 PetscObjectComposeFunction - Associates a function with a given PETSc object. 750 751 Synopsis: 752 #include <petscsys.h> 753 PetscErrorCode PetscObjectComposeFunction(PetscObject obj, const char name[], void (*fptr)(void)) 754 755 Logically Collective 756 757 Input Parameters: 758 + obj - the PETSc object; this must be cast with a (`PetscObject`), for example, 759 `PetscObjectCompose`((`PetscObject`)mat,...); 760 . name - name associated with the child function 761 - fptr - function pointer 762 763 Level: advanced 764 765 Notes: 766 When the first argument of `fptr` is (or is derived from) a `PetscObject` then `PetscTryMethod()` and `PetscUseMethod()` 767 can be used to call the function directly with error checking. 768 769 To remove a registered routine, pass in `NULL` for `fptr`. 770 771 `PetscObjectComposeFunction()` can be used with any PETSc object (such as 772 `Mat`, `Vec`, `KSP`, `SNES`, etc.) or any user-provided object. 773 774 `PetscUseTypeMethod()` and `PetscTryTypeMethod()` are used to call a function that is stored in the objects `obj->ops` table. 775 776 .seealso: `PetscObjectQueryFunction()`, `PetscContainerCreate()` `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscTryMethod()`, `PetscUseMethod()`, 777 `PetscUseTypeMethod()`, `PetscTryTypeMethod()`, `PetscObject` 778 M*/ 779 PetscErrorCode PetscObjectComposeFunction_Private(PetscObject obj, const char name[], void (*fptr)(void)) 780 { 781 PetscFunctionBegin; 782 PetscValidHeader(obj, 1); 783 PetscAssertPointer(name, 2); 784 PetscCall(PetscFunctionListAdd(&obj->qlist, name, fptr)); 785 PetscFunctionReturn(PETSC_SUCCESS); 786 } 787 788 /*MC 789 PetscObjectQueryFunction - Gets a function associated with a given object. 790 791 Synopsis: 792 #include <petscsys.h> 793 PetscErrorCode PetscObjectQueryFunction(PetscObject obj, const char name[], void (**fptr)(void)) 794 795 Logically Collective 796 797 Input Parameters: 798 + obj - the PETSc object; this must be cast with (`PetscObject`), for example, 799 `PetscObjectQueryFunction`((`PetscObject`)ksp,...); 800 - name - name associated with the child function 801 802 Output Parameter: 803 . fptr - function pointer 804 805 Level: advanced 806 807 .seealso: `PetscObjectComposeFunction()`, `PetscFunctionListFind()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject` 808 M*/ 809 PETSC_EXTERN PetscErrorCode PetscObjectQueryFunction_Private(PetscObject obj, const char name[], void (**fptr)(void)) 810 { 811 PetscFunctionBegin; 812 PetscValidHeader(obj, 1); 813 PetscAssertPointer(name, 2); 814 PetscCall(PetscFunctionListFind(obj->qlist, name, fptr)); 815 PetscFunctionReturn(PETSC_SUCCESS); 816 } 817 818 struct _p_PetscContainer { 819 PETSCHEADER(int); 820 void *ptr; 821 PetscErrorCode (*userdestroy)(void *); 822 }; 823 824 /*@C 825 PetscContainerUserDestroyDefault - Default destroy routine for user-provided data that simply calls `PetscFree()` in the data 826 provided with `PetscContainerSetPointer()` 827 828 Logically Collective on the `PetscContainer` containing the user data 829 830 Input Parameter: 831 . ctx - pointer to user-provided data 832 833 Level: advanced 834 835 .seealso: `PetscContainerDestroy()`, `PetscContainerSetUserDestroy()`, `PetscObject` 836 @*/ 837 PetscErrorCode PetscContainerUserDestroyDefault(void *ctx) 838 { 839 PetscFunctionBegin; 840 PetscCall(PetscFree(ctx)); 841 PetscFunctionReturn(PETSC_SUCCESS); 842 } 843 844 /*@C 845 PetscContainerGetPointer - Gets the pointer value contained in the container that was provided with `PetscContainerSetPointer()` 846 847 Not Collective 848 849 Input Parameter: 850 . obj - the object created with `PetscContainerCreate()` 851 852 Output Parameter: 853 . ptr - the pointer value 854 855 Level: advanced 856 857 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObject`, 858 `PetscContainerSetPointer()` 859 @*/ 860 PetscErrorCode PetscContainerGetPointer(PetscContainer obj, void **ptr) 861 { 862 PetscFunctionBegin; 863 PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1); 864 PetscAssertPointer(ptr, 2); 865 *ptr = obj->ptr; 866 PetscFunctionReturn(PETSC_SUCCESS); 867 } 868 869 /*@C 870 PetscContainerSetPointer - Sets the pointer value contained in the container. 871 872 Logically Collective 873 874 Input Parameters: 875 + obj - the object created with `PetscContainerCreate()` 876 - ptr - the pointer value 877 878 Level: advanced 879 880 .seealso: `PetscContainerCreate()`, `PetscContainerDestroy()`, `PetscObjectCompose()`, `PetscObjectQuery()`, `PetscObject`, 881 `PetscContainerGetPointer()` 882 @*/ 883 PetscErrorCode PetscContainerSetPointer(PetscContainer obj, void *ptr) 884 { 885 PetscFunctionBegin; 886 PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1); 887 if (ptr) PetscAssertPointer(ptr, 2); 888 obj->ptr = ptr; 889 PetscFunctionReturn(PETSC_SUCCESS); 890 } 891 892 /*@C 893 PetscContainerDestroy - Destroys a PETSc container object. 894 895 Collective 896 897 Input Parameter: 898 . obj - an object that was created with `PetscContainerCreate()` 899 900 Level: advanced 901 902 Note: 903 If `PetscContainerSetUserDestroy()` was used to provide a user destroy object for the data provided with `PetscContainerSetPointer()` 904 then that function is called to destroy the data. 905 906 .seealso: `PetscContainerCreate()`, `PetscContainerSetUserDestroy()`, `PetscObject` 907 @*/ 908 PetscErrorCode PetscContainerDestroy(PetscContainer *obj) 909 { 910 PetscFunctionBegin; 911 if (!*obj) PetscFunctionReturn(PETSC_SUCCESS); 912 PetscValidHeaderSpecific(*obj, PETSC_CONTAINER_CLASSID, 1); 913 if (--((PetscObject)(*obj))->refct > 0) { 914 *obj = NULL; 915 PetscFunctionReturn(PETSC_SUCCESS); 916 } 917 if ((*obj)->userdestroy) PetscCall((*(*obj)->userdestroy)((*obj)->ptr)); 918 PetscCall(PetscHeaderDestroy(obj)); 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 /*@C 923 PetscContainerSetUserDestroy - Sets name of the user destroy function for the data provided to the `PetscContainer` with `PetscContainerSetPointer()` 924 925 Logically Collective 926 927 Input Parameters: 928 + obj - an object that was created with `PetscContainerCreate()` 929 - des - name of the user destroy function 930 931 Level: advanced 932 933 Note: 934 Use `PetscContainerUserDestroyDefault()` if the memory was obtained by calling `PetscMalloc()` or one of its variants for single memory allocation. 935 936 .seealso: `PetscContainerDestroy()`, `PetscContainerUserDestroyDefault()`, `PetscMalloc()`, `PetscMalloc1()`, `PetscCalloc()`, `PetscCalloc1()`, `PetscObject` 937 @*/ 938 PetscErrorCode PetscContainerSetUserDestroy(PetscContainer obj, PetscErrorCode (*des)(void *)) 939 { 940 PetscFunctionBegin; 941 PetscValidHeaderSpecific(obj, PETSC_CONTAINER_CLASSID, 1); 942 obj->userdestroy = des; 943 PetscFunctionReturn(PETSC_SUCCESS); 944 } 945 946 PetscClassId PETSC_CONTAINER_CLASSID; 947 948 /*@C 949 PetscContainerCreate - Creates a PETSc object that has room to hold a single pointer. 950 951 Collective 952 953 Input Parameter: 954 . comm - MPI communicator that shares the object 955 956 Output Parameter: 957 . container - the container created 958 959 Level: advanced 960 961 Notes: 962 This allows one to attach any type of data (accessible through a pointer) with the 963 `PetscObjectCompose()` function to a `PetscObject`. The data item itself is attached by a 964 call to `PetscContainerSetPointer()`. 965 966 .seealso: `PetscContainerDestroy()`, `PetscContainerSetPointer()`, `PetscContainerGetPointer()`, `PetscObjectCompose()`, `PetscObjectQuery()`, 967 `PetscContainerSetUserDestroy()`, `PetscObject` 968 @*/ 969 PetscErrorCode PetscContainerCreate(MPI_Comm comm, PetscContainer *container) 970 { 971 PetscFunctionBegin; 972 PetscAssertPointer(container, 2); 973 PetscCall(PetscSysInitializePackage()); 974 PetscCall(PetscHeaderCreate(*container, PETSC_CONTAINER_CLASSID, "PetscContainer", "Container", "Sys", comm, PetscContainerDestroy, NULL)); 975 PetscFunctionReturn(PETSC_SUCCESS); 976 } 977 978 /*@ 979 PetscObjectSetFromOptions - Sets generic parameters from user options. 980 981 Collective 982 983 Input Parameter: 984 . obj - the `PetscObject` 985 986 Level: beginner 987 988 Note: 989 We have no generic options at present, so this does nothing 990 991 .seealso: `PetscObjectSetOptionsPrefix()`, `PetscObjectGetOptionsPrefix()`, `PetscObject` 992 @*/ 993 PetscErrorCode PetscObjectSetFromOptions(PetscObject obj) 994 { 995 PetscFunctionBegin; 996 PetscValidHeader(obj, 1); 997 PetscFunctionReturn(PETSC_SUCCESS); 998 } 999 1000 /*@ 1001 PetscObjectSetUp - Sets up the internal data structures for the later use. 1002 1003 Collective 1004 1005 Input Parameter: 1006 . obj - the `PetscObject` 1007 1008 Level: advanced 1009 1010 Note: 1011 This does nothing at present. 1012 1013 .seealso: `PetscObjectDestroy()`, `PetscObject` 1014 @*/ 1015 PetscErrorCode PetscObjectSetUp(PetscObject obj) 1016 { 1017 PetscFunctionBegin; 1018 PetscValidHeader(obj, 1); 1019 PetscFunctionReturn(PETSC_SUCCESS); 1020 } 1021