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