1 2 /* 3 Provides utility routines for manulating any type of PETSc object. 4 */ 5 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 6 #include <petscviewer.h> 7 8 static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state) 9 { 10 void **tmp_star = *composed_star; 11 12 PetscFunctionBegin; 13 for (PetscInt i = 0, imax = *count_star; i < imax; ++i) PetscCall(PetscFree(tmp_star[i])); 14 PetscCall(PetscFree2(*composed_star, *state_star)); 15 PetscCall(PetscFree2(*composed, *state)); 16 *count_star = 0; 17 PetscFunctionReturn(PETSC_SUCCESS); 18 } 19 20 PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj) 21 { 22 PetscFunctionBegin; 23 PetscValidHeader(obj, 1); 24 PetscCall(DestroyComposedData((void ***)&obj->intstarcomposeddata, &obj->intstarcomposedstate, &obj->intstar_idmax, (void **)&obj->intcomposeddata, &obj->intcomposedstate)); 25 PetscCall(DestroyComposedData((void ***)&obj->realstarcomposeddata, &obj->realstarcomposedstate, &obj->realstar_idmax, (void **)&obj->realcomposeddata, &obj->realcomposedstate)); 26 #if PetscDefined(USE_COMPLEX) 27 PetscCall(DestroyComposedData((void ***)&obj->scalarstarcomposeddata, &obj->scalarstarcomposedstate, &obj->scalarstar_idmax, (void **)&obj->scalarcomposeddata, &obj->scalarcomposedstate)); 28 #endif 29 PetscFunctionReturn(PETSC_SUCCESS); 30 } 31 32 /*@ 33 PetscObjectDestroy - Destroys any `PetscObject`, regardless of the type. 34 35 Collective 36 37 Input Parameter: 38 . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 39 This must be cast with a (`PetscObject`*), for example, 40 `PetscObjectDestroy`((`PetscObject`*)&mat); 41 42 Level: beginner 43 44 .seealso: `PetscObject` 45 @*/ 46 PetscErrorCode PetscObjectDestroy(PetscObject *obj) 47 { 48 PetscFunctionBegin; 49 if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS); 50 PetscValidHeader(*obj, 1); 51 PetscCheck((*obj)->bops->destroy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This PETSc object of class %s does not have a generic destroy routine", (*obj)->class_name); 52 PetscCall((*(*obj)->bops->destroy)(obj)); 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 /*@C 57 PetscObjectView - Views any `PetscObject`, regardless of the type. 58 59 Collective 60 61 Input Parameters: 62 + obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 63 This must be cast with a (`PetscObject`), for example, 64 `PetscObjectView`((`PetscObject`)mat,viewer); 65 - viewer - any PETSc viewer 66 67 Level: intermediate 68 69 .seealso: `PetscObject`, `PetscObjectViewFromOptions()` 70 @*/ 71 PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer) 72 { 73 PetscFunctionBegin; 74 PetscValidHeader(obj, 1); 75 PetscCheck(obj->bops->view, PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic viewer routine"); 76 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(obj->comm, &viewer)); 77 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 78 79 PetscCall((*obj->bops->view)(obj, viewer)); 80 PetscFunctionReturn(PETSC_SUCCESS); 81 } 82 83 /*@C 84 PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed. 85 86 Collective 87 88 Input Parameters: 89 + obj - the object 90 . bobj - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used) 91 - optionname - option string that is used to activate viewing 92 93 Options Database Key: 94 . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view` 95 96 Level: developer 97 98 Notes: 99 .vb 100 If no value is provided ascii:stdout is used 101 ascii[:[filename][:[format][:append]]] defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab, 102 for example ascii::ascii_info prints just the information about the object not all details 103 unless :append is given filename opens in write mode, overwriting what was already there 104 binary[:[filename][:[format][:append]]] defaults to the file binaryoutput 105 draw[:drawtype[:filename]] for example, draw:tikz, draw:tikz:figure.tex or draw:x 106 socket[:port] defaults to the standard output port 107 saws[:communicatorname] publishes object to the Scientific Application Webserver (SAWs) 108 .ve 109 110 This is not called directly but is called by, for example, `MatViewFromOptions()` 111 112 .seealso: `PetscObject`, `PetscObjectView()`, `PetscOptionsGetViewer()` 113 @*/ 114 PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char optionname[]) 115 { 116 PetscViewer viewer; 117 PetscBool flg; 118 static PetscBool incall = PETSC_FALSE; 119 PetscViewerFormat format; 120 const char *prefix; 121 122 PetscFunctionBegin; 123 PetscValidHeader(obj, 1); 124 if (bobj) PetscValidHeader(bobj, 2); 125 if (incall) PetscFunctionReturn(PETSC_SUCCESS); 126 incall = PETSC_TRUE; 127 prefix = bobj ? bobj->prefix : obj->prefix; 128 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)obj), obj->options, prefix, optionname, &viewer, &format, &flg)); 129 if (flg) { 130 PetscCall(PetscViewerPushFormat(viewer, format)); 131 PetscCall(PetscObjectView(obj, viewer)); 132 PetscCall(PetscViewerFlush(viewer)); 133 PetscCall(PetscViewerPopFormat(viewer)); 134 PetscCall(PetscViewerDestroy(&viewer)); 135 } 136 incall = PETSC_FALSE; 137 PetscFunctionReturn(PETSC_SUCCESS); 138 } 139 140 /*@C 141 PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type. 142 143 Not Collective 144 145 Input Parameters: 146 + obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 147 This must be cast with a (`PetscObject`), for example, 148 `PetscObjectTypeCompare`((`PetscObject`)mat); 149 - type_name - string containing a type name 150 151 Output Parameter: 152 . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE` 153 154 Level: intermediate 155 156 .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()` 157 @*/ 158 PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same) 159 { 160 PetscFunctionBegin; 161 PetscAssertPointer(same, 3); 162 if (!obj) *same = (PetscBool)!type_name; 163 else { 164 PetscValidHeader(obj, 1); 165 if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name); 166 else { 167 PetscAssertPointer(type_name, 2); 168 PetscCall(PetscStrcmp(obj->type_name, type_name, same)); 169 } 170 } 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 /*@C 175 PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type 176 177 Logically Collective 178 179 Input Parameters: 180 + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 181 - obj2 - another PETSc object 182 183 Output Parameter: 184 . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE` 185 186 Level: intermediate 187 188 .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()` 189 190 @*/ 191 PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same) 192 { 193 PetscFunctionBegin; 194 PetscValidHeader(obj1, 1); 195 PetscValidHeader(obj2, 2); 196 PetscAssertPointer(same, 3); 197 PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same)); 198 PetscFunctionReturn(PETSC_SUCCESS); 199 } 200 201 /*@C 202 PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ` 203 204 Not Collective 205 206 Input Parameters: 207 + obj - the matrix 208 - type_name - string containing a type name 209 210 Output Parameter: 211 . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise 212 213 Level: intermediate 214 215 .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()` 216 @*/ 217 PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same) 218 { 219 PetscFunctionBegin; 220 PetscAssertPointer(same, 3); 221 if (!obj) *same = (PetscBool)!type_name; 222 else { 223 PetscValidHeader(obj, 1); 224 if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name); 225 else { 226 PetscAssertPointer(type_name, 2); 227 PetscCall(PetscStrbeginswith(obj->type_name, type_name, same)); 228 } 229 } 230 PetscFunctionReturn(PETSC_SUCCESS); 231 } 232 233 /*@C 234 PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types. 235 236 Not Collective 237 238 Input Parameters: 239 + obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 240 This must be cast with a (`PetscObject`), for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...); 241 - type_name - array of strings containing type names, pass the empty string "" to terminate the list 242 243 Output Parameter: 244 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE` 245 246 Level: intermediate 247 248 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()` 249 @*/ 250 PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...) 251 { 252 va_list Argp; 253 254 PetscFunctionBegin; 255 PetscAssertPointer(match, 2); 256 *match = PETSC_FALSE; 257 if (!obj) PetscFunctionReturn(PETSC_SUCCESS); 258 va_start(Argp, type_name); 259 while (type_name && type_name[0]) { 260 PetscBool found; 261 PetscCall(PetscObjectTypeCompare(obj, type_name, &found)); 262 if (found) { 263 *match = PETSC_TRUE; 264 break; 265 } 266 type_name = va_arg(Argp, const char *); 267 } 268 va_end(Argp); 269 PetscFunctionReturn(PETSC_SUCCESS); 270 } 271 272 /*@C 273 PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types. 274 275 Not Collective 276 277 Input Parameters: 278 + obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 279 This must be cast with a (`PetscObject`), for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...); 280 - type_name - array of strings containing type names, pass the empty string "" to terminate the list 281 282 Output Parameter: 283 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE` 284 285 Level: intermediate 286 287 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()` 288 @*/ 289 PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...) 290 { 291 va_list Argp; 292 293 PetscFunctionBegin; 294 PetscAssertPointer(match, 2); 295 *match = PETSC_FALSE; 296 va_start(Argp, type_name); 297 while (type_name && type_name[0]) { 298 PetscBool found; 299 PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found)); 300 if (found) { 301 *match = PETSC_TRUE; 302 break; 303 } 304 type_name = va_arg(Argp, const char *); 305 } 306 va_end(Argp); 307 PetscFunctionReturn(PETSC_SUCCESS); 308 } 309 310 typedef struct { 311 PetscErrorCode (*func)(void); 312 } PetscFinalizeFunction; 313 314 typedef struct { 315 PetscErrorCode (*func)(void *); 316 void *ctx; 317 } PetscFinalizeFunctionWithCtx; 318 319 typedef enum { 320 PETSC_FINALIZE_EMPTY, 321 PETSC_FINALIZE_OBJECT, 322 PETSC_FINALIZE_FUNC, 323 PETSC_FINALIZE_FUNC_WITH_CTX 324 } PetscFinalizeType; 325 326 static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR}; 327 328 typedef struct { 329 union ThunkUnion 330 { 331 PetscObject obj; 332 PetscFinalizeFunction fn; 333 PetscFinalizeFunctionWithCtx fnctx; 334 } thunk; 335 PetscFinalizeType type; 336 } PetscFinalizerContainer; 337 338 #define PETSC_MAX_REGISTERED_FINALIZERS 256 339 static int reg_count = 0; 340 static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS]; 341 342 PetscErrorCode PetscRunRegisteredFinalizers(void) 343 { 344 PetscFunctionBegin; 345 while (reg_count) { 346 PetscFinalizerContainer top = regfin[--reg_count]; 347 348 regfin[reg_count].type = PETSC_FINALIZE_EMPTY; 349 PetscCall(PetscArrayzero(®fin[reg_count].thunk, 1)); 350 switch (top.type) { 351 case PETSC_FINALIZE_OBJECT: 352 PetscCall(PetscObjectDestroy(&top.thunk.obj)); 353 break; 354 case PETSC_FINALIZE_FUNC: 355 PetscCall((*top.thunk.fn.func)()); 356 break; 357 case PETSC_FINALIZE_FUNC_WITH_CTX: 358 PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx)); 359 break; 360 case PETSC_FINALIZE_EMPTY: 361 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count); 362 break; 363 } 364 } 365 PetscFunctionReturn(PETSC_SUCCESS); 366 } 367 368 static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b) 369 { 370 if (a->type != b->type) return 0; 371 switch (a->type) { 372 case PETSC_FINALIZE_EMPTY: 373 break; 374 case PETSC_FINALIZE_OBJECT: 375 return a->thunk.obj == b->thunk.obj; 376 case PETSC_FINALIZE_FUNC: 377 return a->thunk.fn.func == b->thunk.fn.func; 378 case PETSC_FINALIZE_FUNC_WITH_CTX: 379 return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx; 380 } 381 return 1; 382 } 383 384 static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container) 385 { 386 PetscFunctionBegin; 387 PetscAssert(reg_count < (int)PETSC_STATIC_ARRAY_LENGTH(regfin), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "No more room in array, limit %zu, recompile %s with larger value for " PetscStringize(regfin), PETSC_STATIC_ARRAY_LENGTH(regfin), __FILE__); 388 PetscAssert(regfin[reg_count].type == PETSC_FINALIZE_EMPTY, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer type (%s) at position %d is not PETSC_FINALIZE_EMPTY!", PetscFinalizeTypes[regfin[reg_count].type], reg_count); 389 if (PetscDefined(USE_DEBUG)) { 390 for (int i = 0; i < reg_count; ++i) PetscCheck(!PetscFinalizerContainerEqual(regfin + i, &container), PETSC_COMM_SELF, PETSC_ERR_ORDER, "Finalizer (of type %s) already registered!", PetscFinalizeTypes[container.type]); 391 } 392 regfin[reg_count++] = container; 393 PetscFunctionReturn(PETSC_SUCCESS); 394 } 395 396 /*@C 397 PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when 398 `PetscFinalize()` is called. 399 400 Logically Collective 401 402 Input Parameter: 403 . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 404 This must be cast with a (`PetscObject`), for example, 405 `PetscObjectRegisterDestroy`((`PetscObject`)mat); 406 407 Level: developer 408 409 Note: 410 This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer 411 when PETSc ends. 412 413 .seealso: `PetscObjectRegisterDestroyAll()` 414 @*/ 415 PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj) 416 { 417 PetscFinalizerContainer container; 418 419 PetscFunctionBegin; 420 PetscValidHeader(obj, 1); 421 container.thunk.obj = obj; 422 container.type = PETSC_FINALIZE_OBJECT; 423 PetscCall(RegisterFinalizer(container)); 424 PetscFunctionReturn(PETSC_SUCCESS); 425 } 426 427 /*@C 428 PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered 429 with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()` 430 431 Logically Collective on the individual `PetscObject`s that are being processed 432 433 Level: developer 434 435 .seealso: `PetscObjectRegisterDestroy()` 436 @*/ 437 PetscErrorCode PetscObjectRegisterDestroyAll(void) 438 { 439 PetscFunctionBegin; 440 PetscCall(PetscRunRegisteredFinalizers()); 441 PetscFunctionReturn(PETSC_SUCCESS); 442 } 443 444 /*@C 445 PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()` 446 447 Not Collective 448 449 Input Parameter: 450 . f - function to be called 451 452 Level: developer 453 454 Notes: 455 This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called 456 457 Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()` 458 459 .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()` 460 @*/ 461 PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void)) 462 { 463 PetscFinalizerContainer container; 464 465 PetscFunctionBegin; 466 PetscValidFunction(f, 1); 467 container.thunk.fn.func = f; 468 container.type = PETSC_FINALIZE_FUNC; 469 PetscCall(RegisterFinalizer(container)); 470 PetscFunctionReturn(PETSC_SUCCESS); 471 } 472 473 /*@C 474 PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()` 475 476 Not Collective unless registered functions are collective 477 478 Level: developer 479 480 .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()` 481 @*/ 482 PetscErrorCode PetscRegisterFinalizeAll(void) 483 { 484 PetscFunctionBegin; 485 PetscCall(PetscRunRegisteredFinalizers()); 486 PetscFunctionReturn(PETSC_SUCCESS); 487 } 488