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