1 /* 2 Provides utility routines for manulating any type of PETSc object. 3 */ 4 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 5 #include <petscviewer.h> 6 7 static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state) 8 { 9 void **tmp_star = *composed_star; 10 11 PetscFunctionBegin; 12 for (PetscInt i = 0, imax = *count_star; i < imax; ++i) PetscCall(PetscFree(tmp_star[i])); 13 PetscCall(PetscFree2(*composed_star, *state_star)); 14 PetscCall(PetscFree2(*composed, *state)); 15 *count_star = 0; 16 PetscFunctionReturn(PETSC_SUCCESS); 17 } 18 19 PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj) 20 { 21 PetscFunctionBegin; 22 PetscValidHeader(obj, 1); 23 PetscCall(DestroyComposedData((void ***)&obj->intstarcomposeddata, &obj->intstarcomposedstate, &obj->intstar_idmax, (void **)&obj->intcomposeddata, &obj->intcomposedstate)); 24 PetscCall(DestroyComposedData((void ***)&obj->realstarcomposeddata, &obj->realstarcomposedstate, &obj->realstar_idmax, (void **)&obj->realcomposeddata, &obj->realcomposedstate)); 25 #if PetscDefined(USE_COMPLEX) 26 PetscCall(DestroyComposedData((void ***)&obj->scalarstarcomposeddata, &obj->scalarstarcomposedstate, &obj->scalarstar_idmax, (void **)&obj->scalarcomposeddata, &obj->scalarcomposedstate)); 27 #endif 28 PetscFunctionReturn(PETSC_SUCCESS); 29 } 30 31 /*@ 32 PetscObjectDestroy - Destroys a `PetscObject`, regardless of the type. 33 34 Collective 35 36 Input Parameter: 37 . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 38 This must be cast with a (`PetscObject`*), for example, 39 `PetscObjectDestroy`((`PetscObject`*)&mat); 40 41 Level: beginner 42 43 .seealso: `PetscObject` 44 @*/ 45 PetscErrorCode PetscObjectDestroy(PetscObject *obj) 46 { 47 PetscFunctionBegin; 48 if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS); 49 PetscValidHeader(*obj, 1); 50 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); 51 PetscCall((*(*obj)->bops->destroy)(obj)); 52 PetscFunctionReturn(PETSC_SUCCESS); 53 } 54 55 /*@C 56 PetscObjectView - Views a `PetscObject`, regardless of the type. 57 58 Collective 59 60 Input Parameters: 61 + obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 62 This must be cast with a (`PetscObject`), for example, 63 `PetscObjectView`((`PetscObject`)mat,viewer); 64 - viewer - any PETSc viewer 65 66 Level: intermediate 67 68 .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscViewer` 69 @*/ 70 PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer) 71 { 72 PetscFunctionBegin; 73 PetscValidHeader(obj, 1); 74 PetscCheck(obj->bops->view, PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic viewer routine"); 75 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(obj->comm, &viewer)); 76 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 77 78 PetscCall((*obj->bops->view)(obj, viewer)); 79 PetscFunctionReturn(PETSC_SUCCESS); 80 } 81 82 /*@C 83 PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed. 84 85 Collective 86 87 Input Parameters: 88 + obj - the object 89 . bobj - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used) 90 - optionname - option string that is used to activate viewing 91 92 Options Database Key: 93 . -optionname_view [viewertype]:... - option name and values. In actual usage this would be something like `-mat_coarse_view` 94 95 Level: developer 96 97 Notes: 98 .vb 99 If no value is provided ascii:stdout is used 100 ascii[:[filename][:[format][:append]]] defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab, 101 for example ascii::ascii_info prints just the information about the object not all details 102 unless :append is given filename opens in write mode, overwriting what was already there 103 binary[:[filename][:[format][:append]]] defaults to the file binaryoutput 104 draw[:drawtype[:filename]] for example, draw:tikz, draw:tikz:figure.tex or draw:x 105 socket[:port] defaults to the standard output port 106 saws[:communicatorname] publishes object to the Scientific Application Webserver (SAWs) 107 .ve 108 109 This is not called directly but is called by, for example, `MatViewFromOptions()` 110 111 .seealso: `PetscObject`, `PetscObjectView()`, `PetscOptionsGetViewer()` 112 @*/ 113 PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char optionname[]) 114 { 115 PetscViewer viewer; 116 PetscBool flg; 117 static PetscBool incall = PETSC_FALSE; 118 PetscViewerFormat format; 119 const char *prefix; 120 121 PetscFunctionBegin; 122 PetscValidHeader(obj, 1); 123 if (bobj) PetscValidHeader(bobj, 2); 124 if (incall) PetscFunctionReturn(PETSC_SUCCESS); 125 incall = PETSC_TRUE; 126 prefix = bobj ? bobj->prefix : obj->prefix; 127 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)obj), obj->options, prefix, optionname, &viewer, &format, &flg)); 128 if (flg) { 129 PetscCall(PetscViewerPushFormat(viewer, format)); 130 PetscCall(PetscObjectView(obj, viewer)); 131 PetscCall(PetscViewerFlush(viewer)); 132 PetscCall(PetscViewerPopFormat(viewer)); 133 PetscCall(PetscOptionsRestoreViewer(&viewer)); 134 } 135 incall = PETSC_FALSE; 136 PetscFunctionReturn(PETSC_SUCCESS); 137 } 138 139 /*@C 140 PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type. 141 142 Not Collective 143 144 Input Parameters: 145 + obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. 146 This must be cast with a (`PetscObject`), for example, 147 `PetscObjectTypeCompare`((`PetscObject`)mat); 148 - type_name - string containing a type name 149 150 Output Parameter: 151 . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE` 152 153 Level: intermediate 154 155 .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()` 156 @*/ 157 PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same) 158 { 159 PetscFunctionBegin; 160 PetscAssertPointer(same, 3); 161 if (!obj) *same = (PetscBool)!type_name; 162 else { 163 PetscValidHeader(obj, 1); 164 if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name); 165 else { 166 PetscAssertPointer(type_name, 2); 167 PetscCall(PetscStrcmp(obj->type_name, type_name, same)); 168 } 169 } 170 PetscFunctionReturn(PETSC_SUCCESS); 171 } 172 173 /*@C 174 PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type 175 176 Logically Collective 177 178 Input Parameters: 179 + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`. 180 - obj2 - another PETSc object 181 182 Output Parameter: 183 . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE` 184 185 Level: intermediate 186 187 .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()` 188 189 @*/ 190 PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same) 191 { 192 PetscFunctionBegin; 193 PetscValidHeader(obj1, 1); 194 PetscValidHeader(obj2, 2); 195 PetscAssertPointer(same, 3); 196 PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same)); 197 PetscFunctionReturn(PETSC_SUCCESS); 198 } 199 200 /*@C 201 PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ` 202 203 Not Collective 204 205 Input Parameters: 206 + obj - the matrix 207 - type_name - string containing a type name 208 209 Output Parameter: 210 . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise 211 212 Level: intermediate 213 214 .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()` 215 @*/ 216 PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same) 217 { 218 PetscFunctionBegin; 219 PetscAssertPointer(same, 3); 220 if (!obj) *same = (PetscBool)!type_name; 221 else { 222 PetscValidHeader(obj, 1); 223 if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name); 224 else { 225 PetscAssertPointer(type_name, 2); 226 PetscCall(PetscStrbeginswith(obj->type_name, type_name, same)); 227 } 228 } 229 PetscFunctionReturn(PETSC_SUCCESS); 230 } 231 232 /*@C 233 PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types. 234 235 Not Collective 236 237 Input Parameters: 238 + obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. 239 This must be cast with a (`PetscObject`), for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...); 240 - type_name - array of strings containing type names, pass the empty string "" to terminate the list 241 242 Output Parameter: 243 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE` 244 245 Level: intermediate 246 247 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()` 248 @*/ 249 PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...) 250 { 251 va_list Argp; 252 253 PetscFunctionBegin; 254 PetscAssertPointer(match, 2); 255 *match = PETSC_FALSE; 256 if (!obj) PetscFunctionReturn(PETSC_SUCCESS); 257 va_start(Argp, type_name); 258 while (type_name && type_name[0]) { 259 PetscBool found; 260 PetscCall(PetscObjectTypeCompare(obj, type_name, &found)); 261 if (found) { 262 *match = PETSC_TRUE; 263 break; 264 } 265 type_name = va_arg(Argp, const char *); 266 } 267 va_end(Argp); 268 PetscFunctionReturn(PETSC_SUCCESS); 269 } 270 271 /*@C 272 PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types. 273 274 Not Collective 275 276 Input Parameters: 277 + obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. 278 This must be cast with a (`PetscObject`), for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...); 279 - type_name - array of strings containing type names, pass the empty string "" to terminate the list 280 281 Output Parameter: 282 . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE` 283 284 Level: intermediate 285 286 .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()` 287 @*/ 288 PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...) 289 { 290 va_list Argp; 291 292 PetscFunctionBegin; 293 PetscAssertPointer(match, 2); 294 *match = PETSC_FALSE; 295 va_start(Argp, type_name); 296 while (type_name && type_name[0]) { 297 PetscBool found; 298 PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found)); 299 if (found) { 300 *match = PETSC_TRUE; 301 break; 302 } 303 type_name = va_arg(Argp, const char *); 304 } 305 va_end(Argp); 306 PetscFunctionReturn(PETSC_SUCCESS); 307 } 308 309 typedef struct { 310 PetscErrorCode (*func)(void); 311 } PetscFinalizeFunction; 312 313 typedef struct { 314 PetscErrorCode (*func)(void *); 315 void *ctx; 316 } PetscFinalizeFunctionWithCtx; 317 318 typedef enum { 319 PETSC_FINALIZE_EMPTY, 320 PETSC_FINALIZE_OBJECT, 321 PETSC_FINALIZE_FUNC, 322 PETSC_FINALIZE_FUNC_WITH_CTX 323 } PetscFinalizeType; 324 325 static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR}; 326 327 typedef struct { 328 union ThunkUnion 329 { 330 PetscObject obj; 331 PetscFinalizeFunction fn; 332 PetscFinalizeFunctionWithCtx fnctx; 333 } thunk; 334 PetscFinalizeType type; 335 } PetscFinalizerContainer; 336 337 #define PETSC_MAX_REGISTERED_FINALIZERS 256 338 static int reg_count = 0; 339 static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS]; 340 341 static PetscErrorCode PetscRunRegisteredFinalizers(void) 342 { 343 PetscFunctionBegin; 344 while (reg_count) { 345 PetscFinalizerContainer top = regfin[--reg_count]; 346 347 regfin[reg_count].type = PETSC_FINALIZE_EMPTY; 348 PetscCall(PetscArrayzero(®fin[reg_count].thunk, 1)); 349 switch (top.type) { 350 case PETSC_FINALIZE_OBJECT: 351 top.thunk.obj->persistent = PETSC_FALSE; 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 - a 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