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