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