1 #include <petscdmadaptor.h> /*I "petscdmadaptor.h" I*/ 2 #include <petscdmplex.h> 3 #include <petscdmforest.h> 4 #include <petscds.h> 5 #include <petscblaslapack.h> 6 #include <petscsnes.h> 7 #include <petscdraw.h> 8 9 #include <petsc/private/dmadaptorimpl.h> 10 #include <petsc/private/dmpleximpl.h> 11 #include <petsc/private/petscfeimpl.h> 12 13 PetscClassId DMADAPTOR_CLASSID; 14 15 PetscFunctionList DMAdaptorList = NULL; 16 PetscBool DMAdaptorRegisterAllCalled = PETSC_FALSE; 17 18 PetscFunctionList DMAdaptorMonitorList = NULL; 19 PetscFunctionList DMAdaptorMonitorCreateList = NULL; 20 PetscFunctionList DMAdaptorMonitorDestroyList = NULL; 21 PetscBool DMAdaptorMonitorRegisterAllCalled = PETSC_FALSE; 22 23 const char *const DMAdaptationCriteria[] = {"NONE", "REFINE", "LABEL", "METRIC", "DMAdaptationCriterion", "DM_ADAPTATION_", NULL}; 24 25 /*@C 26 DMAdaptorRegister - Adds a new adaptor component implementation 27 28 Not Collective 29 30 Input Parameters: 31 + name - The name of a new user-defined creation routine 32 - create_func - The creation routine 33 34 Example Usage: 35 .vb 36 DMAdaptorRegister("my_adaptor", MyAdaptorCreate); 37 .ve 38 39 Then, your adaptor type can be chosen with the procedural interface via 40 .vb 41 DMAdaptorCreate(MPI_Comm, DMAdaptor *); 42 DMAdaptorSetType(DMAdaptor, "my_adaptor"); 43 .ve 44 or at runtime via the option 45 .vb 46 -adaptor_type my_adaptor 47 .ve 48 49 Level: advanced 50 51 Note: 52 `DMAdaptorRegister()` may be called multiple times to add several user-defined adaptors 53 54 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorRegisterAll()`, `DMAdaptorRegisterDestroy()` 55 @*/ 56 PetscErrorCode DMAdaptorRegister(const char name[], PetscErrorCode (*create_func)(DMAdaptor)) 57 { 58 PetscFunctionBegin; 59 PetscCall(DMInitializePackage()); 60 PetscCall(PetscFunctionListAdd(&DMAdaptorList, name, create_func)); 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor); 65 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor); 66 67 /*@C 68 DMAdaptorRegisterAll - Registers all of the adaptor components in the `DM` package. 69 70 Not Collective 71 72 Level: advanced 73 74 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptorType`, `DMRegisterAll()`, `DMAdaptorRegisterDestroy()` 75 @*/ 76 PetscErrorCode DMAdaptorRegisterAll(void) 77 { 78 PetscFunctionBegin; 79 if (DMAdaptorRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 80 DMAdaptorRegisterAllCalled = PETSC_TRUE; 81 82 PetscCall(DMAdaptorRegister(DMADAPTORGRADIENT, DMAdaptorCreate_Gradient)); 83 PetscCall(DMAdaptorRegister(DMADAPTORFLUX, DMAdaptorCreate_Flux)); 84 PetscFunctionReturn(PETSC_SUCCESS); 85 } 86 87 /*@C 88 DMAdaptorRegisterDestroy - This function destroys the registered `DMAdaptorType`. It is called from `PetscFinalize()`. 89 90 Not collective 91 92 Level: developer 93 94 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptorRegisterAll()`, `DMAdaptorType`, `PetscFinalize()` 95 @*/ 96 PetscErrorCode DMAdaptorRegisterDestroy(void) 97 { 98 PetscFunctionBegin; 99 PetscCall(PetscFunctionListDestroy(&DMAdaptorList)); 100 DMAdaptorRegisterAllCalled = PETSC_FALSE; 101 PetscFunctionReturn(PETSC_SUCCESS); 102 } 103 104 static PetscErrorCode DMAdaptorMonitorMakeKey_Internal(const char name[], PetscViewerType vtype, PetscViewerFormat format, char key[]) 105 { 106 PetscFunctionBegin; 107 PetscCall(PetscStrncpy(key, name, PETSC_MAX_PATH_LEN)); 108 PetscCall(PetscStrlcat(key, ":", PETSC_MAX_PATH_LEN)); 109 PetscCall(PetscStrlcat(key, vtype, PETSC_MAX_PATH_LEN)); 110 PetscCall(PetscStrlcat(key, ":", PETSC_MAX_PATH_LEN)); 111 PetscCall(PetscStrlcat(key, PetscViewerFormats[format], PETSC_MAX_PATH_LEN)); 112 PetscFunctionReturn(PETSC_SUCCESS); 113 } 114 115 /*@C 116 DMAdaptorMonitorRegister - Registers a mesh adaptation monitor routine that may be accessed with `DMAdaptorMonitorSetFromOptions()` 117 118 Not Collective 119 120 Input Parameters: 121 + name - name of a new monitor routine 122 . vtype - A `PetscViewerType` for the output 123 . format - A `PetscViewerFormat` for the output 124 . monitor - Monitor routine 125 . create - Creation routine, or `NULL` 126 - destroy - Destruction routine, or `NULL` 127 128 Level: advanced 129 130 Note: 131 `DMAdaptorMonitorRegister()` may be called multiple times to add several user-defined monitors. 132 133 Example Usage: 134 .vb 135 DMAdaptorMonitorRegister("my_monitor", PETSCVIEWERASCII, PETSC_VIEWER_ASCII_INFO_DETAIL, MyMonitor, NULL, NULL); 136 .ve 137 138 Then, your monitor can be chosen with the procedural interface via 139 .vb 140 DMAdaptorMonitorSetFromOptions(ksp, "-adaptor_monitor_my_monitor", "my_monitor", NULL) 141 .ve 142 or at runtime via the option `-adaptor_monitor_my_monitor` 143 144 .seealso: [](ch_snes), `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorRegisterAll()`, `DMAdaptorMonitorSetFromOptions()` 145 @*/ 146 PetscErrorCode DMAdaptorMonitorRegister(const char name[], PetscViewerType vtype, PetscViewerFormat format, PetscErrorCode (*monitor)(DMAdaptor, PetscInt, DM, DM, PetscInt, PetscReal[], Vec, PetscViewerAndFormat *), PetscErrorCode (*create)(PetscViewer, PetscViewerFormat, void *, PetscViewerAndFormat **), PetscErrorCode (*destroy)(PetscViewerAndFormat **)) 147 { 148 char key[PETSC_MAX_PATH_LEN]; 149 150 PetscFunctionBegin; 151 PetscCall(SNESInitializePackage()); 152 PetscCall(DMAdaptorMonitorMakeKey_Internal(name, vtype, format, key)); 153 PetscCall(PetscFunctionListAdd(&DMAdaptorMonitorList, key, monitor)); 154 if (create) PetscCall(PetscFunctionListAdd(&DMAdaptorMonitorCreateList, key, create)); 155 if (destroy) PetscCall(PetscFunctionListAdd(&DMAdaptorMonitorDestroyList, key, destroy)); 156 PetscFunctionReturn(PETSC_SUCCESS); 157 } 158 159 /*@C 160 DMAdaptorMonitorRegisterDestroy - This function destroys the registered monitors for `DMAdaptor`. It is called from `PetscFinalize()`. 161 162 Not collective 163 164 Level: developer 165 166 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptorMonitorRegisterAll()`, `DMAdaptor`, `PetscFinalize()` 167 @*/ 168 PetscErrorCode DMAdaptorMonitorRegisterDestroy(void) 169 { 170 PetscFunctionBegin; 171 PetscCall(PetscFunctionListDestroy(&DMAdaptorMonitorList)); 172 PetscCall(PetscFunctionListDestroy(&DMAdaptorMonitorCreateList)); 173 PetscCall(PetscFunctionListDestroy(&DMAdaptorMonitorDestroyList)); 174 DMAdaptorMonitorRegisterAllCalled = PETSC_FALSE; 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 /*@ 179 DMAdaptorCreate - Create a `DMAdaptor` object. Its purpose is to construct a adaptation `DMLabel` or metric `Vec` that can be used to modify the `DM`. 180 181 Collective 182 183 Input Parameter: 184 . comm - The communicator for the `DMAdaptor` object 185 186 Output Parameter: 187 . adaptor - The `DMAdaptor` object 188 189 Level: beginner 190 191 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorDestroy()`, `DMAdaptorAdapt()`, `PetscConvEst`, `PetscConvEstCreate()` 192 @*/ 193 PetscErrorCode DMAdaptorCreate(MPI_Comm comm, DMAdaptor *adaptor) 194 { 195 VecTaggerBox refineBox, coarsenBox; 196 197 PetscFunctionBegin; 198 PetscAssertPointer(adaptor, 2); 199 PetscCall(PetscSysInitializePackage()); 200 201 PetscCall(PetscHeaderCreate(*adaptor, DMADAPTOR_CLASSID, "DMAdaptor", "DM Adaptor", "DMAdaptor", comm, DMAdaptorDestroy, DMAdaptorView)); 202 (*adaptor)->adaptCriterion = DM_ADAPTATION_NONE; 203 (*adaptor)->numSeq = 1; 204 (*adaptor)->Nadapt = -1; 205 (*adaptor)->refinementFactor = 2.0; 206 refineBox.min = refineBox.max = PETSC_MAX_REAL; 207 PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->refineTag)); 208 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->refineTag, "refine_")); 209 PetscCall(VecTaggerSetType((*adaptor)->refineTag, VECTAGGERABSOLUTE)); 210 PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->refineTag, &refineBox)); 211 coarsenBox.min = coarsenBox.max = PETSC_MAX_REAL; 212 PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->coarsenTag)); 213 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->coarsenTag, "coarsen_")); 214 PetscCall(VecTaggerSetType((*adaptor)->coarsenTag, VECTAGGERABSOLUTE)); 215 PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->coarsenTag, &coarsenBox)); 216 PetscFunctionReturn(PETSC_SUCCESS); 217 } 218 219 /*@ 220 DMAdaptorDestroy - Destroys a `DMAdaptor` object 221 222 Collective 223 224 Input Parameter: 225 . adaptor - The `DMAdaptor` object 226 227 Level: beginner 228 229 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 230 @*/ 231 PetscErrorCode DMAdaptorDestroy(DMAdaptor *adaptor) 232 { 233 PetscFunctionBegin; 234 if (!*adaptor) PetscFunctionReturn(PETSC_SUCCESS); 235 PetscValidHeaderSpecific(*adaptor, DMADAPTOR_CLASSID, 1); 236 if (--((PetscObject)*adaptor)->refct > 0) { 237 *adaptor = NULL; 238 PetscFunctionReturn(PETSC_SUCCESS); 239 } 240 PetscCall(VecTaggerDestroy(&(*adaptor)->refineTag)); 241 PetscCall(VecTaggerDestroy(&(*adaptor)->coarsenTag)); 242 PetscCall(PetscFree2((*adaptor)->exactSol, (*adaptor)->exactCtx)); 243 PetscCall(DMAdaptorMonitorCancel(*adaptor)); 244 PetscCall(PetscHeaderDestroy(adaptor)); 245 PetscFunctionReturn(PETSC_SUCCESS); 246 } 247 248 /*@ 249 DMAdaptorSetType - Sets the particular implementation for a adaptor. 250 251 Collective 252 253 Input Parameters: 254 + adaptor - The `DMAdaptor` 255 - method - The name of the adaptor type 256 257 Options Database Key: 258 . -adaptor_type <type> - Sets the adaptor type; see `DMAdaptorType` 259 260 Level: intermediate 261 262 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorGetType()`, `DMAdaptorCreate()` 263 @*/ 264 PetscErrorCode DMAdaptorSetType(DMAdaptor adaptor, DMAdaptorType method) 265 { 266 PetscErrorCode (*r)(DMAdaptor); 267 PetscBool match; 268 269 PetscFunctionBegin; 270 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 271 PetscCall(PetscObjectTypeCompare((PetscObject)adaptor, method, &match)); 272 if (match) PetscFunctionReturn(PETSC_SUCCESS); 273 274 PetscCall(DMAdaptorRegisterAll()); 275 PetscCall(PetscFunctionListFind(DMAdaptorList, method, &r)); 276 PetscCheck(r, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMAdaptor type: %s", method); 277 278 PetscTryTypeMethod(adaptor, destroy); 279 PetscCall(PetscMemzero(adaptor->ops, sizeof(*adaptor->ops))); 280 PetscCall(PetscObjectChangeTypeName((PetscObject)adaptor, method)); 281 PetscCall((*r)(adaptor)); 282 PetscFunctionReturn(PETSC_SUCCESS); 283 } 284 285 /*@ 286 DMAdaptorGetType - Gets the type name (as a string) from the adaptor. 287 288 Not Collective 289 290 Input Parameter: 291 . adaptor - The `DMAdaptor` 292 293 Output Parameter: 294 . type - The `DMAdaptorType` name 295 296 Level: intermediate 297 298 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorSetType()`, `DMAdaptorCreate()` 299 @*/ 300 PetscErrorCode DMAdaptorGetType(DMAdaptor adaptor, DMAdaptorType *type) 301 { 302 PetscFunctionBegin; 303 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 304 PetscAssertPointer(type, 2); 305 PetscCall(DMAdaptorRegisterAll()); 306 *type = ((PetscObject)adaptor)->type_name; 307 PetscFunctionReturn(PETSC_SUCCESS); 308 } 309 310 static PetscErrorCode PetscViewerAndFormatCreate_Internal(PetscViewer viewer, PetscViewerFormat format, void *ctx, PetscViewerAndFormat **vf) 311 { 312 PetscFunctionBegin; 313 PetscCall(PetscViewerAndFormatCreate(viewer, format, vf)); 314 (*vf)->data = ctx; 315 PetscFunctionReturn(PETSC_SUCCESS); 316 } 317 318 /*@C 319 DMAdaptorMonitorSet - Sets an ADDITIONAL function to be called at every iteration to monitor 320 the error etc. 321 322 Logically Collective 323 324 Input Parameters: 325 + adaptor - the `DMAdaptor` 326 . monitor - pointer to function (if this is `NULL`, it turns off monitoring 327 . ctx - [optional] context for private data for the monitor routine (use `NULL` if no context is needed) 328 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for its calling sequence 329 330 Calling sequence of `monitor`: 331 + adaptor - the `DMAdaptor` 332 . it - iteration number 333 . odm - the original `DM` 334 . adm - the adapted `DM` 335 . Nf - number of fields 336 . enorms - (estimated) 2-norm of the error for each field 337 . error - `Vec` of cellwise errors 338 - ctx - optional monitoring context, as set by `DMAdaptorMonitorSet()` 339 340 Options Database Keys: 341 + -adaptor_monitor_size - sets `DMAdaptorMonitorSize()` 342 . -adaptor_monitor_error - sets `DMAdaptorMonitorError()` 343 . -adaptor_monitor_error draw - sets `DMAdaptorMonitorErrorDraw()` and plots error 344 . -adaptor_monitor_error draw::draw_lg - sets `DMAdaptorMonitorErrorDrawLG()` and plots error 345 - -dm_adaptor_monitor_cancel - Cancels all monitors that have been hardwired into a code by calls to `DMAdaptorMonitorSet()`, but does not cancel those set via the options database. 346 347 Level: beginner 348 349 .seealso: [](ch_snes), `DMAdaptorMonitorError()`, `DMAdaptor`, `PetscCtxDestroyFn` 350 @*/ 351 PetscErrorCode DMAdaptorMonitorSet(DMAdaptor adaptor, PetscErrorCode (*monitor)(DMAdaptor adaptor, PetscInt it, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error, void *ctx), void *ctx, PetscCtxDestroyFn *monitordestroy) 352 { 353 PetscBool identical; 354 355 PetscFunctionBegin; 356 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 357 for (PetscInt i = 0; i < adaptor->numbermonitors; i++) { 358 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))monitor, ctx, monitordestroy, (PetscErrorCode (*)(void))adaptor->monitor[i], adaptor->monitorcontext[i], adaptor->monitordestroy[i], &identical)); 359 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 360 } 361 PetscCheck(adaptor->numbermonitors < MAXDMADAPTORMONITORS, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_OUTOFRANGE, "Too many DMAdaptor monitors set"); 362 adaptor->monitor[adaptor->numbermonitors] = monitor; 363 adaptor->monitordestroy[adaptor->numbermonitors] = monitordestroy; 364 adaptor->monitorcontext[adaptor->numbermonitors++] = ctx; 365 PetscFunctionReturn(PETSC_SUCCESS); 366 } 367 368 /*@ 369 DMAdaptorMonitorCancel - Clears all monitors for a `DMAdaptor` object. 370 371 Logically Collective 372 373 Input Parameter: 374 . adaptor - the `DMAdaptor` 375 376 Options Database Key: 377 . -dm_adaptor_monitor_cancel - Cancels all monitors that have been hardwired into a code by calls to `DMAdaptorMonitorSet()`, but does not cancel those set via the options database. 378 379 Level: intermediate 380 381 .seealso: [](ch_snes), `DMAdaptorMonitorError()`, `DMAdaptorMonitorSet()`, `DMAdaptor` 382 @*/ 383 PetscErrorCode DMAdaptorMonitorCancel(DMAdaptor adaptor) 384 { 385 PetscFunctionBegin; 386 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 387 for (PetscInt i = 0; i < adaptor->numbermonitors; ++i) { 388 if (adaptor->monitordestroy[i]) PetscCall((*adaptor->monitordestroy[i])(&adaptor->monitorcontext[i])); 389 } 390 adaptor->numbermonitors = 0; 391 PetscFunctionReturn(PETSC_SUCCESS); 392 } 393 394 /*@C 395 DMAdaptorMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user in the options database 396 397 Collective 398 399 Input Parameters: 400 + adaptor - `DMadaptor` object you wish to monitor 401 . opt - the command line option for this monitor 402 . name - the monitor type one is seeking 403 - ctx - An optional user context for the monitor, or `NULL` 404 405 Level: developer 406 407 .seealso: [](ch_snes), `DMAdaptorMonitorRegister()`, `DMAdaptorMonitorSet()`, `PetscOptionsGetViewer()` 408 @*/ 409 PetscErrorCode DMAdaptorMonitorSetFromOptions(DMAdaptor adaptor, const char opt[], const char name[], void *ctx) 410 { 411 PetscErrorCode (*mfunc)(DMAdaptor, PetscInt, DM, DM, PetscInt, PetscReal[], Vec, void *); 412 PetscErrorCode (*cfunc)(PetscViewer, PetscViewerFormat, void *, PetscViewerAndFormat **); 413 PetscErrorCode (*dfunc)(PetscViewerAndFormat **); 414 PetscViewerAndFormat *vf; 415 PetscViewer viewer; 416 PetscViewerFormat format; 417 PetscViewerType vtype; 418 char key[PETSC_MAX_PATH_LEN]; 419 PetscBool flg; 420 const char *prefix = NULL; 421 422 PetscFunctionBegin; 423 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)adaptor, &prefix)); 424 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)adaptor), ((PetscObject)adaptor)->options, prefix, opt, &viewer, &format, &flg)); 425 if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 426 427 PetscCall(PetscViewerGetType(viewer, &vtype)); 428 PetscCall(DMAdaptorMonitorMakeKey_Internal(name, vtype, format, key)); 429 PetscCall(PetscFunctionListFind(DMAdaptorMonitorList, key, &mfunc)); 430 PetscCall(PetscFunctionListFind(DMAdaptorMonitorCreateList, key, &cfunc)); 431 PetscCall(PetscFunctionListFind(DMAdaptorMonitorDestroyList, key, &dfunc)); 432 if (!cfunc) cfunc = PetscViewerAndFormatCreate_Internal; 433 if (!dfunc) dfunc = PetscViewerAndFormatDestroy; 434 435 PetscCall((*cfunc)(viewer, format, ctx, &vf)); 436 PetscCall(PetscViewerDestroy(&viewer)); 437 PetscCall(DMAdaptorMonitorSet(adaptor, mfunc, vf, (PetscCtxDestroyFn *)dfunc)); 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 /*@ 442 DMAdaptorSetOptionsPrefix - Sets the prefix used for searching for all `DMAdaptor` options in the database. 443 444 Logically Collective 445 446 Input Parameters: 447 + adaptor - the `DMAdaptor` 448 - prefix - the prefix to prepend to all option names 449 450 Level: advanced 451 452 Note: 453 A hyphen (-) must NOT be given at the beginning of the prefix name. 454 The first character of all runtime options is AUTOMATICALLY the hyphen. 455 456 .seealso: [](ch_snes), `DMAdaptor`, `SNESSetOptionsPrefix()`, `DMAdaptorSetFromOptions()` 457 @*/ 458 PetscErrorCode DMAdaptorSetOptionsPrefix(DMAdaptor adaptor, const char prefix[]) 459 { 460 PetscFunctionBegin; 461 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 462 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)adaptor, prefix)); 463 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)adaptor->refineTag, prefix)); 464 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)adaptor->refineTag, "refine_")); 465 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)adaptor->coarsenTag, prefix)); 466 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)adaptor->coarsenTag, "coarsen_")); 467 PetscFunctionReturn(PETSC_SUCCESS); 468 } 469 470 /*@ 471 DMAdaptorSetFromOptions - Sets properties of a `DMAdaptor` object from values in the options database 472 473 Collective 474 475 Input Parameter: 476 . adaptor - The `DMAdaptor` object 477 478 Options Database Keys: 479 + -adaptor_monitor_size - Monitor the mesh size 480 . -adaptor_monitor_error - Monitor the solution error 481 . -adaptor_sequence_num <num> - Number of adaptations to generate an optimal grid 482 . -adaptor_target_num <num> - Set the target number of vertices N_adapt, -1 for automatic determination 483 . -adaptor_refinement_factor <r> - Set r such that N_adapt = r^dim N_orig 484 - -adaptor_mixed_setup_function <func> - Set the function func that sets up the mixed problem 485 486 Level: beginner 487 488 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 489 @*/ 490 PetscErrorCode DMAdaptorSetFromOptions(DMAdaptor adaptor) 491 { 492 char typeName[PETSC_MAX_PATH_LEN]; 493 const char *defName = DMADAPTORGRADIENT; 494 char funcname[PETSC_MAX_PATH_LEN]; 495 DMAdaptationCriterion criterion = DM_ADAPTATION_NONE; 496 PetscBool flg; 497 498 PetscFunctionBegin; 499 PetscObjectOptionsBegin((PetscObject)adaptor); 500 PetscCall(PetscOptionsFList("-adaptor_type", "DMAdaptor", "DMAdaptorSetType", DMAdaptorList, defName, typeName, 1024, &flg)); 501 if (flg) PetscCall(DMAdaptorSetType(adaptor, typeName)); 502 else if (!((PetscObject)adaptor)->type_name) PetscCall(DMAdaptorSetType(adaptor, defName)); 503 PetscCall(PetscOptionsEnum("-adaptor_criterion", "Criterion used to drive adaptation", "", DMAdaptationCriteria, (PetscEnum)criterion, (PetscEnum *)&criterion, &flg)); 504 if (flg) PetscCall(DMAdaptorSetCriterion(adaptor, criterion)); 505 PetscCall(PetscOptionsInt("-adaptor_sequence_num", "Number of adaptations to generate an optimal grid", "DMAdaptorSetSequenceLength", adaptor->numSeq, &adaptor->numSeq, NULL)); 506 PetscCall(PetscOptionsInt("-adaptor_target_num", "Set the target number of vertices N_adapt, -1 for automatic determination", "DMAdaptor", adaptor->Nadapt, &adaptor->Nadapt, NULL)); 507 PetscCall(PetscOptionsReal("-adaptor_refinement_factor", "Set r such that N_adapt = r^dim N_orig", "DMAdaptor", adaptor->refinementFactor, &adaptor->refinementFactor, NULL)); 508 PetscCall(PetscOptionsString("-adaptor_mixed_setup_function", "Function to setup the mixed problem", "DMAdaptorSetMixedSetupFunction", funcname, funcname, sizeof(funcname), &flg)); 509 if (flg) { 510 PetscErrorCode (*setupFunc)(DMAdaptor, DM); 511 512 PetscCall(PetscDLSym(NULL, funcname, (void **)&setupFunc)); 513 PetscCheck(setupFunc, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname); 514 PetscCall(DMAdaptorSetMixedSetupFunction(adaptor, setupFunc)); 515 } 516 PetscCall(DMAdaptorMonitorSetFromOptions(adaptor, "-adaptor_monitor_size", "size", adaptor)); 517 PetscCall(DMAdaptorMonitorSetFromOptions(adaptor, "-adaptor_monitor_error", "error", adaptor)); 518 PetscOptionsEnd(); 519 PetscCall(VecTaggerSetFromOptions(adaptor->refineTag)); 520 PetscCall(VecTaggerSetFromOptions(adaptor->coarsenTag)); 521 PetscFunctionReturn(PETSC_SUCCESS); 522 } 523 524 /*@ 525 DMAdaptorView - Views a `DMAdaptor` object 526 527 Collective 528 529 Input Parameters: 530 + adaptor - The `DMAdaptor` object 531 - viewer - The `PetscViewer` object 532 533 Level: beginner 534 535 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 536 @*/ 537 PetscErrorCode DMAdaptorView(DMAdaptor adaptor, PetscViewer viewer) 538 { 539 PetscFunctionBegin; 540 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)adaptor, viewer)); 541 PetscCall(PetscViewerASCIIPrintf(viewer, "DM Adaptor\n")); 542 PetscCall(PetscViewerASCIIPrintf(viewer, " sequence length: %" PetscInt_FMT "\n", adaptor->numSeq)); 543 PetscCall(VecTaggerView(adaptor->refineTag, viewer)); 544 PetscCall(VecTaggerView(adaptor->coarsenTag, viewer)); 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 /*@ 549 DMAdaptorGetSolver - Gets the solver used to produce discrete solutions 550 551 Not Collective 552 553 Input Parameter: 554 . adaptor - The `DMAdaptor` object 555 556 Output Parameter: 557 . snes - The solver 558 559 Level: intermediate 560 561 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 562 @*/ 563 PetscErrorCode DMAdaptorGetSolver(DMAdaptor adaptor, SNES *snes) 564 { 565 PetscFunctionBegin; 566 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 567 PetscAssertPointer(snes, 2); 568 *snes = adaptor->snes; 569 PetscFunctionReturn(PETSC_SUCCESS); 570 } 571 572 /*@ 573 DMAdaptorSetSolver - Sets the solver used to produce discrete solutions 574 575 Not Collective 576 577 Input Parameters: 578 + adaptor - The `DMAdaptor` object 579 - snes - The solver, this MUST have an attached `DM`/`PetscDS`, so that the exact solution can be computed 580 581 Level: intermediate 582 583 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorGetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 584 @*/ 585 PetscErrorCode DMAdaptorSetSolver(DMAdaptor adaptor, SNES snes) 586 { 587 PetscFunctionBegin; 588 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 589 PetscValidHeaderSpecific(snes, SNES_CLASSID, 2); 590 adaptor->snes = snes; 591 PetscCall(SNESGetDM(adaptor->snes, &adaptor->idm)); 592 PetscFunctionReturn(PETSC_SUCCESS); 593 } 594 595 /*@ 596 DMAdaptorGetSequenceLength - Gets the number of sequential adaptations used by an adapter 597 598 Not Collective 599 600 Input Parameter: 601 . adaptor - The `DMAdaptor` object 602 603 Output Parameter: 604 . num - The number of adaptations 605 606 Level: intermediate 607 608 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorSetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 609 @*/ 610 PetscErrorCode DMAdaptorGetSequenceLength(DMAdaptor adaptor, PetscInt *num) 611 { 612 PetscFunctionBegin; 613 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 614 PetscAssertPointer(num, 2); 615 *num = adaptor->numSeq; 616 PetscFunctionReturn(PETSC_SUCCESS); 617 } 618 619 /*@ 620 DMAdaptorSetSequenceLength - Sets the number of sequential adaptations 621 622 Not Collective 623 624 Input Parameters: 625 + adaptor - The `DMAdaptor` object 626 - num - The number of adaptations 627 628 Level: intermediate 629 630 .seealso: [](ch_dmbase), `DMAdaptorGetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 631 @*/ 632 PetscErrorCode DMAdaptorSetSequenceLength(DMAdaptor adaptor, PetscInt num) 633 { 634 PetscFunctionBegin; 635 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 636 adaptor->numSeq = num; 637 PetscFunctionReturn(PETSC_SUCCESS); 638 } 639 640 static PetscErrorCode DMAdaptorTransferSolution_Exact_Private(DMAdaptor adaptor, DM dm, Vec u, DM adm, Vec au, void *ctx) 641 { 642 PetscFunctionBeginUser; 643 PetscCall(DMProjectFunction(adm, 0.0, adaptor->exactSol, adaptor->exactCtx, INSERT_ALL_VALUES, au)); 644 PetscFunctionReturn(PETSC_SUCCESS); 645 } 646 647 /*@ 648 DMAdaptorSetUp - After the solver is specified, creates data structures for controlling adaptivity 649 650 Collective 651 652 Input Parameter: 653 . adaptor - The `DMAdaptor` object 654 655 Level: beginner 656 657 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 658 @*/ 659 PetscErrorCode DMAdaptorSetUp(DMAdaptor adaptor) 660 { 661 PetscDS prob; 662 PetscInt Nf, f; 663 664 PetscFunctionBegin; 665 PetscCall(DMGetDS(adaptor->idm, &prob)); 666 PetscCall(VecTaggerSetUp(adaptor->refineTag)); 667 PetscCall(VecTaggerSetUp(adaptor->coarsenTag)); 668 PetscCall(PetscDSGetNumFields(prob, &Nf)); 669 PetscCall(PetscMalloc2(Nf, &adaptor->exactSol, Nf, &adaptor->exactCtx)); 670 for (f = 0; f < Nf; ++f) { 671 PetscCall(PetscDSGetExactSolution(prob, f, &adaptor->exactSol[f], &adaptor->exactCtx[f])); 672 /* TODO Have a flag that forces projection rather than using the exact solution */ 673 if (adaptor->exactSol[0]) PetscCall(DMAdaptorSetTransferFunction(adaptor, DMAdaptorTransferSolution_Exact_Private)); 674 } 675 PetscTryTypeMethod(adaptor, setup); 676 PetscFunctionReturn(PETSC_SUCCESS); 677 } 678 679 PetscErrorCode DMAdaptorGetTransferFunction(DMAdaptor adaptor, PetscErrorCode (**tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *)) 680 { 681 PetscFunctionBegin; 682 *tfunc = adaptor->ops->transfersolution; 683 PetscFunctionReturn(PETSC_SUCCESS); 684 } 685 686 PetscErrorCode DMAdaptorSetTransferFunction(DMAdaptor adaptor, PetscErrorCode (*tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *)) 687 { 688 PetscFunctionBegin; 689 adaptor->ops->transfersolution = tfunc; 690 PetscFunctionReturn(PETSC_SUCCESS); 691 } 692 693 static PetscErrorCode DMAdaptorPreAdapt(DMAdaptor adaptor, Vec locX) 694 { 695 DM plex; 696 PetscDS prob; 697 PetscObject obj; 698 PetscClassId id; 699 PetscBool isForest; 700 701 PetscFunctionBegin; 702 PetscCall(DMConvert(adaptor->idm, DMPLEX, &plex)); 703 PetscCall(DMGetDS(adaptor->idm, &prob)); 704 PetscCall(PetscDSGetDiscretization(prob, 0, &obj)); 705 PetscCall(PetscObjectGetClassId(obj, &id)); 706 PetscCall(DMIsForest(adaptor->idm, &isForest)); 707 if (adaptor->adaptCriterion == DM_ADAPTATION_NONE) { 708 if (isForest) { 709 adaptor->adaptCriterion = DM_ADAPTATION_LABEL; 710 } 711 #if defined(PETSC_HAVE_PRAGMATIC) 712 else { 713 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 714 } 715 #elif defined(PETSC_HAVE_MMG) 716 else { 717 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 718 } 719 #elif defined(PETSC_HAVE_PARMMG) 720 else { 721 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 722 } 723 #else 724 else { 725 adaptor->adaptCriterion = DM_ADAPTATION_LABEL; 726 } 727 #endif 728 } 729 if (id == PETSCFV_CLASSID) { 730 adaptor->femType = PETSC_FALSE; 731 } else { 732 adaptor->femType = PETSC_TRUE; 733 } 734 if (adaptor->femType) { 735 /* Compute local solution bc */ 736 PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL)); 737 } else { 738 PetscFV fvm = (PetscFV)obj; 739 PetscLimiter noneLimiter; 740 Vec grad; 741 742 PetscCall(PetscFVGetComputeGradients(fvm, &adaptor->computeGradient)); 743 PetscCall(PetscFVSetComputeGradients(fvm, PETSC_TRUE)); 744 /* Use no limiting when reconstructing gradients for adaptivity */ 745 PetscCall(PetscFVGetLimiter(fvm, &adaptor->limiter)); 746 PetscCall(PetscObjectReference((PetscObject)adaptor->limiter)); 747 PetscCall(PetscLimiterCreate(PetscObjectComm((PetscObject)fvm), &noneLimiter)); 748 PetscCall(PetscLimiterSetType(noneLimiter, PETSCLIMITERNONE)); 749 PetscCall(PetscFVSetLimiter(fvm, noneLimiter)); 750 /* Get FVM data */ 751 PetscCall(DMPlexGetDataFVM(plex, fvm, &adaptor->cellGeom, &adaptor->faceGeom, &adaptor->gradDM)); 752 PetscCall(VecGetDM(adaptor->cellGeom, &adaptor->cellDM)); 753 PetscCall(VecGetArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray)); 754 /* Compute local solution bc */ 755 PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL)); 756 /* Compute gradients */ 757 PetscCall(DMCreateGlobalVector(adaptor->gradDM, &grad)); 758 PetscCall(DMPlexReconstructGradientsFVM(plex, locX, grad)); 759 PetscCall(DMGetLocalVector(adaptor->gradDM, &adaptor->cellGrad)); 760 PetscCall(DMGlobalToLocalBegin(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad)); 761 PetscCall(DMGlobalToLocalEnd(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad)); 762 PetscCall(VecDestroy(&grad)); 763 PetscCall(VecGetArrayRead(adaptor->cellGrad, &adaptor->cellGradArray)); 764 } 765 PetscCall(DMDestroy(&plex)); 766 PetscFunctionReturn(PETSC_SUCCESS); 767 } 768 769 static PetscErrorCode DMAdaptorTransferSolution(DMAdaptor adaptor, DM dm, Vec x, DM adm, Vec ax) 770 { 771 PetscReal time = 0.0; 772 Mat interp; 773 void *ctx; 774 775 PetscFunctionBegin; 776 PetscCall(DMGetApplicationContext(dm, &ctx)); 777 if (adaptor->ops->transfersolution) PetscUseTypeMethod(adaptor, transfersolution, dm, x, adm, ax, ctx); 778 else { 779 switch (adaptor->adaptCriterion) { 780 case DM_ADAPTATION_LABEL: 781 PetscCall(DMForestTransferVec(dm, x, adm, ax, PETSC_TRUE, time)); 782 break; 783 case DM_ADAPTATION_REFINE: 784 case DM_ADAPTATION_METRIC: 785 PetscCall(DMCreateInterpolation(dm, adm, &interp, NULL)); 786 PetscCall(MatInterpolate(interp, x, ax)); 787 PetscCall(DMInterpolate(dm, interp, adm)); 788 PetscCall(MatDestroy(&interp)); 789 break; 790 default: 791 SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_SUP, "No built-in projection for this adaptation criterion: %d", adaptor->adaptCriterion); 792 } 793 } 794 PetscFunctionReturn(PETSC_SUCCESS); 795 } 796 797 static PetscErrorCode DMAdaptorPostAdapt(DMAdaptor adaptor) 798 { 799 PetscDS prob; 800 PetscObject obj; 801 PetscClassId id; 802 803 PetscFunctionBegin; 804 PetscCall(DMGetDS(adaptor->idm, &prob)); 805 PetscCall(PetscDSGetDiscretization(prob, 0, &obj)); 806 PetscCall(PetscObjectGetClassId(obj, &id)); 807 if (id == PETSCFV_CLASSID) { 808 PetscFV fvm = (PetscFV)obj; 809 810 PetscCall(PetscFVSetComputeGradients(fvm, adaptor->computeGradient)); 811 /* Restore original limiter */ 812 PetscCall(PetscFVSetLimiter(fvm, adaptor->limiter)); 813 814 PetscCall(VecRestoreArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray)); 815 PetscCall(VecRestoreArrayRead(adaptor->cellGrad, &adaptor->cellGradArray)); 816 PetscCall(DMRestoreLocalVector(adaptor->gradDM, &adaptor->cellGrad)); 817 } 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 /* 822 DMAdaptorComputeCellErrorIndicator_Gradient - Use the integrated gradient as an error indicator in the `DMAdaptor` 823 824 Input Parameters: 825 + adaptor - The `DMAdaptor` object 826 . dim - The topological dimension 827 . cell - The cell 828 . field - The field integrated over the cell 829 . gradient - The gradient integrated over the cell 830 . cg - A `PetscFVCellGeom` struct 831 - ctx - A user context 832 833 Output Parameter: 834 . errInd - The error indicator 835 836 Developer Note: 837 Some of the input arguments are absurdly specialized to special situations, it is not clear this is a good general API 838 839 .seealso: [](ch_dmbase), `DMAdaptor` 840 */ 841 static PetscErrorCode DMAdaptorComputeCellErrorIndicator_Gradient(DMAdaptor adaptor, PetscInt dim, PetscInt Nc, const PetscScalar *field, const PetscScalar *gradient, const PetscFVCellGeom *cg, PetscReal *errInd, void *ctx) 842 { 843 PetscReal err = 0.; 844 PetscInt c, d; 845 846 PetscFunctionBeginHot; 847 for (c = 0; c < Nc; c++) { 848 for (d = 0; d < dim; ++d) err += PetscSqr(PetscRealPart(gradient[c * dim + d])); 849 } 850 *errInd = cg->volume * err; 851 PetscFunctionReturn(PETSC_SUCCESS); 852 } 853 854 static PetscErrorCode DMAdaptorComputeErrorIndicator_Gradient(DMAdaptor adaptor, Vec locX, Vec errVec) 855 { 856 DM dm, plex, edm, eplex; 857 PetscDS ds; 858 PetscObject obj; 859 PetscClassId id; 860 void *ctx; 861 PetscQuadrature quad; 862 PetscScalar *earray; 863 PetscReal minMaxInd[2] = {PETSC_MAX_REAL, PETSC_MIN_REAL}, minMaxIndGlobal[2]; 864 PetscInt dim, cdim, cStart, cEnd, Nf, Nc; 865 866 PetscFunctionBegin; 867 PetscCall(VecGetDM(locX, &dm)); 868 PetscCall(DMConvert(dm, DMPLEX, &plex)); 869 PetscCall(VecGetDM(errVec, &edm)); 870 PetscCall(DMConvert(edm, DMPLEX, &eplex)); 871 PetscCall(DMGetDimension(plex, &dim)); 872 PetscCall(DMGetCoordinateDim(plex, &cdim)); 873 PetscCall(DMGetApplicationContext(plex, &ctx)); 874 PetscCall(DMGetDS(plex, &ds)); 875 PetscCall(PetscDSGetNumFields(ds, &Nf)); 876 PetscCall(PetscDSGetDiscretization(ds, 0, &obj)); 877 PetscCall(PetscObjectGetClassId(obj, &id)); 878 879 PetscCall(VecGetArray(errVec, &earray)); 880 PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd)); 881 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 882 PetscScalar *eval; 883 PetscReal errInd = 0.; 884 885 if (id == PETSCFV_CLASSID) { 886 PetscFV fv = (PetscFV)obj; 887 const PetscScalar *pointSols; 888 const PetscScalar *pointSol; 889 const PetscScalar *pointGrad; 890 PetscFVCellGeom *cg; 891 892 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 893 PetscCall(VecGetArrayRead(locX, &pointSols)); 894 PetscCall(DMPlexPointLocalRead(plex, cell, pointSols, (void *)&pointSol)); 895 PetscCall(DMPlexPointLocalRead(adaptor->gradDM, cell, adaptor->cellGradArray, (void *)&pointGrad)); 896 PetscCall(DMPlexPointLocalRead(adaptor->cellDM, cell, adaptor->cellGeomArray, &cg)); 897 PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, pointSol, pointGrad, cg, &errInd, ctx); 898 PetscCall(VecRestoreArrayRead(locX, &pointSols)); 899 } else { 900 PetscFE fe = (PetscFE)obj; 901 PetscScalar *x = NULL, *field, *gradient, *interpolant, *interpolantGrad; 902 PetscFVCellGeom cg; 903 PetscFEGeom fegeom; 904 const PetscReal *quadWeights; 905 PetscReal *coords; 906 PetscInt Nb, Nq, qNc; 907 908 fegeom.dim = dim; 909 fegeom.dimEmbed = cdim; 910 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 911 PetscCall(PetscFEGetQuadrature(fe, &quad)); 912 PetscCall(PetscFEGetDimension(fe, &Nb)); 913 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 914 PetscCall(PetscCalloc6(Nc, &field, cdim * Nc, &gradient, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 915 PetscCall(PetscMalloc2(Nc, &interpolant, cdim * Nc, &interpolantGrad)); 916 PetscCall(DMPlexComputeCellGeometryFEM(plex, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 917 PetscCall(DMPlexComputeCellGeometryFVM(plex, cell, &cg.volume, NULL, NULL)); 918 PetscCall(PetscArrayzero(gradient, cdim * Nc)); 919 PetscCall(DMPlexVecGetClosure(plex, NULL, locX, cell, NULL, &x)); 920 for (PetscInt f = 0; f < Nf; ++f) { 921 PetscInt qc = 0; 922 923 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 924 PetscCall(PetscArrayzero(interpolant, Nc)); 925 PetscCall(PetscArrayzero(interpolantGrad, cdim * Nc)); 926 for (PetscInt q = 0; q < Nq; ++q) { 927 PetscCall(PetscFEInterpolateFieldAndGradient_Static((PetscFE)obj, 1, x, &fegeom, q, interpolant, interpolantGrad)); 928 for (PetscInt fc = 0; fc < Nc; ++fc) { 929 const PetscReal wt = quadWeights[q * qNc + qc + fc]; 930 931 field[fc] += interpolant[fc] * wt * fegeom.detJ[q]; 932 for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] += interpolantGrad[fc * dim + d] * wt * fegeom.detJ[q]; 933 } 934 } 935 qc += Nc; 936 } 937 PetscCall(PetscFree2(interpolant, interpolantGrad)); 938 PetscCall(DMPlexVecRestoreClosure(plex, NULL, locX, cell, NULL, &x)); 939 for (PetscInt fc = 0; fc < Nc; ++fc) { 940 field[fc] /= cg.volume; 941 for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] /= cg.volume; 942 } 943 PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, field, gradient, &cg, &errInd, ctx); 944 PetscCall(PetscFree6(field, gradient, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 945 } 946 PetscCall(DMPlexPointGlobalRef(eplex, cell, earray, (void *)&eval)); 947 eval[0] = errInd; 948 minMaxInd[0] = PetscMin(minMaxInd[0], errInd); 949 minMaxInd[1] = PetscMax(minMaxInd[1], errInd); 950 } 951 PetscCall(VecRestoreArray(errVec, &earray)); 952 PetscCall(DMDestroy(&plex)); 953 PetscCall(DMDestroy(&eplex)); 954 PetscCall(PetscGlobalMinMaxReal(PetscObjectComm((PetscObject)adaptor), minMaxInd, minMaxIndGlobal)); 955 PetscCall(PetscInfo(adaptor, "DMAdaptor: error indicator range (%g, %g)\n", (double)minMaxIndGlobal[0], (double)minMaxIndGlobal[1])); 956 PetscFunctionReturn(PETSC_SUCCESS); 957 } 958 959 static PetscErrorCode DMAdaptorComputeErrorIndicator_Flux(DMAdaptor adaptor, Vec lu, Vec errVec) 960 { 961 DM dm, mdm; 962 SNES msnes; 963 Vec mu, lmu; 964 void *ctx; 965 const char *prefix; 966 967 PetscFunctionBegin; 968 PetscCall(VecGetDM(lu, &dm)); 969 970 // Set up and solve mixed problem 971 PetscCall(DMClone(dm, &mdm)); 972 PetscCall(SNESCreate(PetscObjectComm((PetscObject)mdm), &msnes)); 973 PetscCall(SNESSetDM(msnes, mdm)); 974 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)adaptor, &prefix)); 975 PetscCall(SNESSetOptionsPrefix(msnes, prefix)); 976 PetscCall(SNESAppendOptionsPrefix(msnes, "mixed_")); 977 978 PetscTryTypeMethod(adaptor, mixedsetup, mdm); 979 PetscCall(DMGetApplicationContext(dm, &ctx)); 980 PetscCall(DMPlexSetSNESLocalFEM(mdm, PETSC_FALSE, ctx)); 981 PetscCall(SNESSetFromOptions(msnes)); 982 983 PetscCall(DMCreateGlobalVector(mdm, &mu)); 984 PetscCall(PetscObjectSetName((PetscObject)mu, "Mixed Solution")); 985 PetscCall(VecSet(mu, 0.0)); 986 PetscCall(SNESSolve(msnes, NULL, mu)); 987 PetscCall(VecViewFromOptions(mu, (PetscObject)adaptor, "-adapt_mixed_sol_vec_view")); 988 989 PetscCall(DMGetLocalVector(mdm, &lmu)); 990 PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu)); 991 PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL)); 992 PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, 0, lmu, 0, errVec)); 993 PetscCall(DMRestoreLocalVector(mdm, &lmu)); 994 PetscCall(VecDestroy(&mu)); 995 PetscCall(SNESDestroy(&msnes)); 996 PetscCall(DMDestroy(&mdm)); 997 PetscFunctionReturn(PETSC_SUCCESS); 998 } 999 1000 /*@ 1001 DMAdaptorMonitor - runs the user provided monitor routines, if they exist 1002 1003 Collective 1004 1005 Input Parameters: 1006 + adaptor - the `DMAdaptor` 1007 . it - iteration number 1008 . odm - the original `DM` 1009 . adm - the adapted `DM` 1010 . Nf - the number of fields 1011 . enorms - the 2-norm error values for each field 1012 - error - `Vec` of cellwise errors 1013 1014 Level: developer 1015 1016 Note: 1017 This routine is called by the `DMAdaptor` implementations. 1018 It does not typically need to be called by the user. 1019 1020 .seealso: [](ch_snes), `DMAdaptorMonitorSet()` 1021 @*/ 1022 PetscErrorCode DMAdaptorMonitor(DMAdaptor adaptor, PetscInt it, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error) 1023 { 1024 PetscFunctionBegin; 1025 for (PetscInt i = 0; i < adaptor->numbermonitors; ++i) PetscCall((*adaptor->monitor[i])(adaptor, it, odm, adm, Nf, enorms, error, adaptor->monitorcontext[i])); 1026 PetscFunctionReturn(PETSC_SUCCESS); 1027 } 1028 1029 /*@C 1030 DMAdaptorMonitorSize - Prints the mesh sizes at each iteration of an adaptation loop. 1031 1032 Collective 1033 1034 Input Parameters: 1035 + adaptor - the `DMAdaptor` 1036 . n - iteration number 1037 . odm - the original `DM` 1038 . adm - the adapted `DM` 1039 . Nf - number of fields 1040 . enorms - 2-norm error values for each field (may be estimated). 1041 . error - `Vec` of cellwise errors 1042 - vf - The viewer context 1043 1044 Options Database Key: 1045 . -adaptor_monitor_size - Activates `DMAdaptorMonitorSize()` 1046 1047 Level: intermediate 1048 1049 Note: 1050 This is not called directly by users, rather one calls `DMAdaptorMonitorSet()`, with this function as an argument, to cause the monitor 1051 to be used during the adaptation loop. 1052 1053 .seealso: [](ch_snes), `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorError()`, `DMAdaptorMonitorErrorDraw()`, `DMAdaptorMonitorErrorDrawLG()` 1054 @*/ 1055 PetscErrorCode DMAdaptorMonitorSize(DMAdaptor adaptor, PetscInt n, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error, PetscViewerAndFormat *vf) 1056 { 1057 PetscViewer viewer = vf->viewer; 1058 PetscViewerFormat format = vf->format; 1059 PetscInt tablevel, cStart, cEnd, acStart, acEnd; 1060 const char *prefix; 1061 PetscMPIInt rank; 1062 1063 PetscFunctionBegin; 1064 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1065 PetscCall(PetscObjectGetTabLevel((PetscObject)adaptor, &tablevel)); 1066 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)adaptor, &prefix)); 1067 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)adaptor), &rank)); 1068 PetscCall(DMPlexGetHeightStratum(odm, 0, &cStart, &cEnd)); 1069 PetscCall(DMPlexGetHeightStratum(adm, 0, &acStart, &acEnd)); 1070 1071 PetscCall(PetscViewerPushFormat(viewer, format)); 1072 PetscCall(PetscViewerASCIIAddTab(viewer, tablevel)); 1073 if (n == 0 && prefix) PetscCall(PetscViewerASCIIPrintf(viewer, " Sizes for %s adaptation.\n", prefix)); 1074 PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " DMAdaptor rank %d N_orig: %" PetscInt_FMT " N_adapt: %" PetscInt_FMT "\n", n, rank, cEnd - cStart, acEnd - acStart)); 1075 PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel)); 1076 PetscCall(PetscViewerPopFormat(viewer)); 1077 PetscFunctionReturn(PETSC_SUCCESS); 1078 } 1079 1080 /*@C 1081 DMAdaptorMonitorError - Prints the error norm at each iteration of an adaptation loop. 1082 1083 Collective 1084 1085 Input Parameters: 1086 + adaptor - the `DMAdaptor` 1087 . n - iteration number 1088 . odm - the original `DM` 1089 . adm - the adapted `DM` 1090 . Nf - number of fields 1091 . enorms - 2-norm error values for each field (may be estimated). 1092 . error - `Vec` of cellwise errors 1093 - vf - The viewer context 1094 1095 Options Database Key: 1096 . -adaptor_monitor_error - Activates `DMAdaptorMonitorError()` 1097 1098 Level: intermediate 1099 1100 Note: 1101 This is not called directly by users, rather one calls `DMAdaptorMonitorSet()`, with this function as an argument, to cause the monitor 1102 to be used during the adaptation loop. 1103 1104 .seealso: [](ch_snes), `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorErrorDraw()`, `DMAdaptorMonitorErrorDrawLG()` 1105 @*/ 1106 PetscErrorCode DMAdaptorMonitorError(DMAdaptor adaptor, PetscInt n, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error, PetscViewerAndFormat *vf) 1107 { 1108 PetscViewer viewer = vf->viewer; 1109 PetscViewerFormat format = vf->format; 1110 PetscInt tablevel, cStart, cEnd, acStart, acEnd; 1111 const char *prefix; 1112 1113 PetscFunctionBegin; 1114 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1115 PetscCall(PetscObjectGetTabLevel((PetscObject)adaptor, &tablevel)); 1116 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)adaptor, &prefix)); 1117 1118 PetscCall(PetscViewerPushFormat(viewer, format)); 1119 PetscCall(PetscViewerASCIIAddTab(viewer, tablevel)); 1120 if (n == 0 && prefix) PetscCall(PetscViewerASCIIPrintf(viewer, " Error norms for %s adaptation.\n", prefix)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " DMAdaptor Error norm %s", n, Nf > 1 ? "[" : "")); 1122 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1123 for (PetscInt f = 0; f < Nf; ++f) { 1124 if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1125 PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)enorms[f])); 1126 } 1127 PetscCall(DMPlexGetHeightStratum(odm, 0, &cStart, &cEnd)); 1128 PetscCall(DMPlexGetHeightStratum(adm, 0, &acStart, &acEnd)); 1129 PetscCall(PetscViewerASCIIPrintf(viewer, " N: %" PetscInt_FMT " Nadapt: %" PetscInt_FMT "\n", cEnd - cStart, acEnd - acStart)); 1130 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1131 PetscCall(PetscViewerASCIISubtractTab(viewer, tablevel)); 1132 PetscCall(PetscViewerPopFormat(viewer)); 1133 PetscFunctionReturn(PETSC_SUCCESS); 1134 } 1135 1136 /*@C 1137 DMAdaptorMonitorErrorDraw - Plots the error at each iteration of an iterative solver. 1138 1139 Collective 1140 1141 Input Parameters: 1142 + adaptor - the `DMAdaptor` 1143 . n - iteration number 1144 . odm - the original `DM` 1145 . adm - the adapted `DM` 1146 . Nf - number of fields 1147 . enorms - 2-norm error values for each field (may be estimated). 1148 . error - `Vec` of cellwise errors 1149 - vf - The viewer context 1150 1151 Options Database Key: 1152 . -adaptor_monitor_error draw - Activates `DMAdaptorMonitorErrorDraw()` 1153 1154 Level: intermediate 1155 1156 Note: 1157 This is not called directly by users, rather one calls `DMAdaptorMonitorSet()`, with this function as an argument, to cause the monitor 1158 to be used during the adaptation loop. 1159 1160 .seealso: [](ch_snes), `PETSCVIEWERDRAW`, `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorErrorDrawLG()` 1161 @*/ 1162 PetscErrorCode DMAdaptorMonitorErrorDraw(DMAdaptor adaptor, PetscInt n, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error, PetscViewerAndFormat *vf) 1163 { 1164 PetscViewer viewer = vf->viewer; 1165 PetscViewerFormat format = vf->format; 1166 1167 PetscFunctionBegin; 1168 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1169 PetscCall(PetscViewerPushFormat(viewer, format)); 1170 PetscCall(PetscObjectSetName((PetscObject)error, "Error Estimator")); 1171 PetscCall(PetscObjectCompose((PetscObject)error, "__Vec_bc_zero__", (PetscObject)adaptor)); 1172 PetscCall(VecView(error, viewer)); 1173 PetscCall(PetscObjectCompose((PetscObject)error, "__Vec_bc_zero__", NULL)); 1174 PetscCall(PetscViewerPopFormat(viewer)); 1175 PetscFunctionReturn(PETSC_SUCCESS); 1176 } 1177 1178 /*@C 1179 DMAdaptorMonitorErrorDrawLGCreate - Creates the context for the error plotter `DMAdaptorMonitorErrorDrawLG()` 1180 1181 Collective 1182 1183 Input Parameters: 1184 + viewer - The `PetscViewer` 1185 . format - The viewer format 1186 - ctx - An optional user context 1187 1188 Output Parameter: 1189 . vf - The viewer context 1190 1191 Level: intermediate 1192 1193 .seealso: [](ch_snes), `PETSCVIEWERDRAW`, `PetscViewerMonitorGLSetUp()`, `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorErrorDrawLG()` 1194 @*/ 1195 PetscErrorCode DMAdaptorMonitorErrorDrawLGCreate(PetscViewer viewer, PetscViewerFormat format, void *ctx, PetscViewerAndFormat **vf) 1196 { 1197 DMAdaptor adaptor = (DMAdaptor)ctx; 1198 char **names; 1199 PetscInt Nf; 1200 1201 PetscFunctionBegin; 1202 PetscCall(DMGetNumFields(adaptor->idm, &Nf)); 1203 PetscCall(PetscMalloc1(Nf + 1, &names)); 1204 for (PetscInt f = 0; f < Nf; ++f) { 1205 PetscObject disc; 1206 const char *fname; 1207 char lname[PETSC_MAX_PATH_LEN]; 1208 1209 PetscCall(DMGetField(adaptor->idm, f, NULL, &disc)); 1210 PetscCall(PetscObjectGetName(disc, &fname)); 1211 PetscCall(PetscStrncpy(lname, fname, PETSC_MAX_PATH_LEN)); 1212 PetscCall(PetscStrlcat(lname, " Error", PETSC_MAX_PATH_LEN)); 1213 PetscCall(PetscStrallocpy(lname, &names[f])); 1214 } 1215 PetscCall(PetscViewerAndFormatCreate(viewer, format, vf)); 1216 (*vf)->data = ctx; 1217 PetscCall(PetscViewerMonitorLGSetUp(viewer, NULL, NULL, "Log Error Norm", Nf, (const char **)names, PETSC_DECIDE, PETSC_DECIDE, 400, 300)); 1218 for (PetscInt f = 0; f < Nf; ++f) PetscCall(PetscFree(names[f])); 1219 PetscCall(PetscFree(names)); 1220 PetscFunctionReturn(PETSC_SUCCESS); 1221 } 1222 1223 /*@C 1224 DMAdaptorMonitorErrorDrawLG - Plots the error norm at each iteration of an adaptive loop. 1225 1226 Collective 1227 1228 Input Parameters: 1229 + adaptor - the `DMAdaptor` 1230 . n - iteration number 1231 . odm - the original `DM` 1232 . adm - the adapted `DM` 1233 . Nf - number of fields 1234 . enorms - 2-norm error values for each field (may be estimated). 1235 . error - `Vec` of cellwise errors 1236 - vf - The viewer context, obtained via `DMAdaptorMonitorErrorDrawLGCreate()` 1237 1238 Options Database Key: 1239 . -adaptor_error draw::draw_lg - Activates `DMAdaptorMonitorErrorDrawLG()` 1240 1241 Level: intermediate 1242 1243 Notes: 1244 This is not called directly by users, rather one calls `DMAdaptorMonitorSet()`, with this function as an argument, to cause the monitor 1245 to be used during the adaptation loop. 1246 1247 Call `DMAdaptorMonitorErrorDrawLGCreate()` to create the context needed for this monitor 1248 1249 .seealso: [](ch_snes), `PETSCVIEWERDRAW`, `DMAdaptor`, `DMAdaptorMonitorSet()`, `DMAdaptorMonitorErrorDraw()`, `DMAdaptorMonitorError()`, 1250 `DMAdaptorMonitorTrueResidualDrawLGCreate()` 1251 @*/ 1252 PetscErrorCode DMAdaptorMonitorErrorDrawLG(DMAdaptor adaptor, PetscInt n, DM odm, DM adm, PetscInt Nf, PetscReal enorms[], Vec error, PetscViewerAndFormat *vf) 1253 { 1254 PetscViewer viewer = vf->viewer; 1255 PetscViewerFormat format = vf->format; 1256 PetscDrawLG lg; 1257 PetscReal *x, *e; 1258 1259 PetscFunctionBegin; 1260 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 8); 1261 PetscCall(PetscViewerDrawGetDrawLG(viewer, 0, &lg)); 1262 PetscCall(PetscCalloc2(Nf, &x, Nf, &e)); 1263 PetscCall(PetscViewerPushFormat(viewer, format)); 1264 if (!n) PetscCall(PetscDrawLGReset(lg)); 1265 for (PetscInt f = 0; f < Nf; ++f) { 1266 x[f] = (PetscReal)n; 1267 e[f] = enorms[f] > 0.0 ? PetscLog10Real(enorms[f]) : -15.; 1268 } 1269 PetscCall(PetscDrawLGAddPoint(lg, x, e)); 1270 PetscCall(PetscDrawLGDraw(lg)); 1271 PetscCall(PetscDrawLGSave(lg)); 1272 PetscCall(PetscViewerPopFormat(viewer)); 1273 PetscCall(PetscFree2(x, e)); 1274 PetscFunctionReturn(PETSC_SUCCESS); 1275 } 1276 1277 /*@C 1278 DMAdaptorMonitorRegisterAll - Registers all of the mesh adaptation monitors in the `SNES` package. 1279 1280 Not Collective 1281 1282 Level: advanced 1283 1284 .seealso: [](ch_snes), `SNES`, `DM`, `DMAdaptorMonitorRegister()`, `DMAdaptorRegister()` 1285 @*/ 1286 PetscErrorCode DMAdaptorMonitorRegisterAll(void) 1287 { 1288 PetscFunctionBegin; 1289 if (DMAdaptorMonitorRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 1290 DMAdaptorMonitorRegisterAllCalled = PETSC_TRUE; 1291 1292 PetscCall(DMAdaptorMonitorRegister("size", PETSCVIEWERASCII, PETSC_VIEWER_DEFAULT, DMAdaptorMonitorSize, NULL, NULL)); 1293 PetscCall(DMAdaptorMonitorRegister("error", PETSCVIEWERASCII, PETSC_VIEWER_DEFAULT, DMAdaptorMonitorError, NULL, NULL)); 1294 PetscCall(DMAdaptorMonitorRegister("error", PETSCVIEWERDRAW, PETSC_VIEWER_DEFAULT, DMAdaptorMonitorErrorDraw, NULL, NULL)); 1295 PetscCall(DMAdaptorMonitorRegister("error", PETSCVIEWERDRAW, PETSC_VIEWER_DRAW_LG, DMAdaptorMonitorErrorDrawLG, DMAdaptorMonitorErrorDrawLGCreate, NULL)); 1296 PetscFunctionReturn(PETSC_SUCCESS); 1297 } 1298 1299 static void identity(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]) 1300 { 1301 const PetscInt Nc = uOff[1] - uOff[0]; 1302 1303 for (PetscInt i = 0; i < Nc; ++i) f[i] = u[i]; 1304 } 1305 1306 static void identityFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]) 1307 { 1308 for (PetscInt i = 0; i < dim; ++i) { 1309 for (PetscInt j = 0; j < dim; ++j) f[i + dim * j] = u[i + dim * j]; 1310 } 1311 } 1312 1313 static PetscErrorCode DMAdaptorAdapt_Sequence_Private(DMAdaptor adaptor, Vec inx, PetscBool doSolve, DM *adm, Vec *ax) 1314 { 1315 PetscDS ds; 1316 PetscReal errorNorm = 0.; 1317 PetscInt numAdapt = adaptor->numSeq, adaptIter; 1318 PetscInt dim, coordDim, Nf; 1319 void *ctx; 1320 MPI_Comm comm; 1321 1322 PetscFunctionBegin; 1323 PetscCall(DMViewFromOptions(adaptor->idm, NULL, "-dm_adapt_pre_view")); 1324 PetscCall(VecViewFromOptions(inx, NULL, "-sol_adapt_pre_view")); 1325 PetscCall(PetscObjectGetComm((PetscObject)adaptor, &comm)); 1326 PetscCall(DMGetDimension(adaptor->idm, &dim)); 1327 PetscCall(DMGetCoordinateDim(adaptor->idm, &coordDim)); 1328 PetscCall(DMGetApplicationContext(adaptor->idm, &ctx)); 1329 PetscCall(DMGetDS(adaptor->idm, &ds)); 1330 PetscCall(PetscDSGetNumFields(ds, &Nf)); 1331 PetscCheck(Nf != 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot refine with no fields present!"); 1332 1333 /* Adapt until nothing changes */ 1334 /* Adapt for a specified number of iterates */ 1335 for (adaptIter = 0; adaptIter < numAdapt - 1; ++adaptIter) PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_(comm))); 1336 for (adaptIter = 0; adaptIter < numAdapt; ++adaptIter) { 1337 PetscBool adapted = PETSC_FALSE; 1338 DM dm = adaptIter ? *adm : adaptor->idm, odm; 1339 Vec x = adaptIter ? *ax : inx, locX, ox; 1340 Vec error = NULL; 1341 1342 PetscCall(DMGetLocalVector(dm, &locX)); 1343 PetscCall(DMAdaptorPreAdapt(adaptor, locX)); 1344 if (doSolve) { 1345 SNES snes; 1346 1347 PetscCall(DMAdaptorGetSolver(adaptor, &snes)); 1348 PetscCall(SNESSolve(snes, NULL, adaptIter ? *ax : x)); 1349 } 1350 PetscCall(DMGlobalToLocalBegin(dm, adaptIter ? *ax : x, INSERT_VALUES, locX)); 1351 PetscCall(DMGlobalToLocalEnd(dm, adaptIter ? *ax : x, INSERT_VALUES, locX)); 1352 PetscCall(VecViewFromOptions(adaptIter ? *ax : x, (PetscObject)adaptor, "-adapt_primal_sol_vec_view")); 1353 switch (adaptor->adaptCriterion) { 1354 case DM_ADAPTATION_REFINE: 1355 PetscCall(DMRefine(dm, comm, &odm)); 1356 PetscCheck(odm, comm, PETSC_ERR_ARG_INCOMP, "DMRefine() did not perform any refinement, cannot continue grid sequencing"); 1357 adapted = PETSC_TRUE; 1358 PetscCall(DMAdaptorMonitor(adaptor, adaptIter, dm, dm, 1, &errorNorm, NULL)); 1359 break; 1360 case DM_ADAPTATION_LABEL: { 1361 /* Adapt DM 1362 Create local solution 1363 Reconstruct gradients (FVM) or solve adjoint equation (FEM) 1364 Produce cellwise error indicator */ 1365 DM edm, plex; 1366 PetscDS ds; 1367 PetscFE efe; 1368 DMLabel adaptLabel; 1369 IS refineIS, coarsenIS; 1370 DMPolytopeType ct; 1371 PetscScalar errorVal; 1372 PetscInt nRefine, nCoarsen, cStart; 1373 1374 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "adapt", &adaptLabel)); 1375 1376 // TODO Move this creation to PreAdapt 1377 PetscCall(DMClone(dm, &edm)); 1378 PetscCall(DMConvert(edm, DMPLEX, &plex)); 1379 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 1380 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 1381 PetscCall(DMDestroy(&plex)); 1382 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, 0, PETSC_DEFAULT, &efe)); 1383 PetscCall(PetscObjectSetName((PetscObject)efe, "Error")); 1384 PetscCall(DMSetField(edm, 0, NULL, (PetscObject)efe)); 1385 PetscCall(PetscFEDestroy(&efe)); 1386 PetscCall(DMCreateDS(edm)); 1387 PetscCall(DMGetGlobalVector(edm, &error)); 1388 PetscCall(PetscObjectSetName((PetscObject)error, "Error Estimator")); 1389 1390 PetscUseTypeMethod(adaptor, computeerrorindicator, locX, error); 1391 PetscCall(VecViewFromOptions(error, (PetscObject)adaptor, "-adapt_error_vec_view")); 1392 PetscCall(DMGetDS(edm, &ds)); 1393 PetscCall(PetscDSSetObjective(ds, 0, identity)); 1394 PetscCall(DMPlexComputeIntegralFEM(edm, error, &errorVal, NULL)); 1395 errorNorm = PetscRealPart(errorVal); 1396 1397 // Compute IS from VecTagger 1398 PetscCall(VecTaggerComputeIS(adaptor->refineTag, error, &refineIS, NULL)); 1399 PetscCall(VecTaggerComputeIS(adaptor->coarsenTag, error, &coarsenIS, NULL)); 1400 PetscCall(ISViewFromOptions(refineIS, (PetscObject)adaptor->refineTag, "-is_view")); 1401 PetscCall(ISViewFromOptions(coarsenIS, (PetscObject)adaptor->coarsenTag, "-is_view")); 1402 PetscCall(ISGetSize(refineIS, &nRefine)); 1403 PetscCall(ISGetSize(coarsenIS, &nCoarsen)); 1404 PetscCall(PetscInfo(adaptor, "DMAdaptor: numRefine %" PetscInt_FMT ", numCoarsen %" PetscInt_FMT "\n", nRefine, nCoarsen)); 1405 if (nRefine) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE, refineIS)); 1406 if (nCoarsen) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_COARSEN, coarsenIS)); 1407 PetscCall(ISDestroy(&coarsenIS)); 1408 PetscCall(ISDestroy(&refineIS)); 1409 // Adapt DM from label 1410 if (nRefine || nCoarsen) { 1411 char oprefix[PETSC_MAX_PATH_LEN]; 1412 const char *p; 1413 PetscBool flg; 1414 1415 PetscCall(PetscOptionsHasName(NULL, adaptor->hdr.prefix, "-adapt_vec_view", &flg)); 1416 if (flg) { 1417 Vec ref; 1418 1419 PetscCall(DMPlexCreateLabelField(dm, adaptLabel, &ref)); 1420 PetscCall(VecViewFromOptions(ref, (PetscObject)adaptor, "-adapt_vec_view")); 1421 PetscCall(VecDestroy(&ref)); 1422 } 1423 1424 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &p)); 1425 PetscCall(PetscStrncpy(oprefix, p, PETSC_MAX_PATH_LEN)); 1426 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "adapt_")); 1427 PetscCall(DMAdaptLabel(dm, adaptLabel, &odm)); 1428 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oprefix)); 1429 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)odm, oprefix)); 1430 PetscCall(DMAdaptorMonitor(adaptor, adaptIter, dm, odm, 1, &errorNorm, error)); 1431 adapted = PETSC_TRUE; 1432 } else { 1433 PetscCall(DMAdaptorMonitor(adaptor, adaptIter, dm, dm, 1, &errorNorm, error)); 1434 } 1435 PetscCall(DMLabelDestroy(&adaptLabel)); 1436 PetscCall(DMRestoreGlobalVector(edm, &error)); 1437 PetscCall(DMDestroy(&edm)); 1438 } break; 1439 case DM_ADAPTATION_METRIC: { 1440 DM dmGrad, dmHess, dmMetric, dmDet; 1441 Vec xGrad, xHess, metric, determinant; 1442 PetscReal N; 1443 DMLabel bdLabel = NULL, rgLabel = NULL; 1444 PetscBool higherOrder = PETSC_FALSE; 1445 PetscInt Nd = coordDim * coordDim, f, vStart, vEnd; 1446 void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 1447 1448 PetscCall(PetscMalloc(1, &funcs)); 1449 funcs[0] = identityFunc; 1450 1451 /* Setup finite element spaces */ 1452 PetscCall(DMClone(dm, &dmGrad)); 1453 PetscCall(DMClone(dm, &dmHess)); 1454 PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple fields not yet considered"); // TODO 1455 for (f = 0; f < Nf; ++f) { 1456 PetscFE fe, feGrad, feHess; 1457 PetscDualSpace Q; 1458 PetscSpace space; 1459 DM K; 1460 PetscQuadrature q; 1461 PetscInt Nc, qorder, p; 1462 const char *prefix; 1463 1464 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 1465 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1466 PetscCheck(Nc <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple components not yet considered"); // TODO 1467 PetscCall(PetscFEGetBasisSpace(fe, &space)); 1468 PetscCall(PetscSpaceGetDegree(space, NULL, &p)); 1469 if (p > 1) higherOrder = PETSC_TRUE; 1470 PetscCall(PetscFEGetDualSpace(fe, &Q)); 1471 PetscCall(PetscDualSpaceGetDM(Q, &K)); 1472 PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd)); 1473 PetscCall(PetscFEGetQuadrature(fe, &q)); 1474 PetscCall(PetscQuadratureGetOrder(q, &qorder)); 1475 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)fe, &prefix)); 1476 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmGrad), dim, Nc * coordDim, PETSC_TRUE, prefix, qorder, &feGrad)); 1477 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmHess), dim, Nc * Nd, PETSC_TRUE, prefix, qorder, &feHess)); 1478 PetscCall(DMSetField(dmGrad, f, NULL, (PetscObject)feGrad)); 1479 PetscCall(DMSetField(dmHess, f, NULL, (PetscObject)feHess)); 1480 PetscCall(DMCreateDS(dmGrad)); 1481 PetscCall(DMCreateDS(dmHess)); 1482 PetscCall(PetscFEDestroy(&feGrad)); 1483 PetscCall(PetscFEDestroy(&feHess)); 1484 } 1485 /* Compute vertexwise gradients from cellwise gradients */ 1486 PetscCall(DMCreateLocalVector(dmGrad, &xGrad)); 1487 PetscCall(VecViewFromOptions(locX, NULL, "-sol_adapt_loc_pre_view")); 1488 PetscCall(DMPlexComputeGradientClementInterpolant(dm, locX, xGrad)); 1489 PetscCall(VecViewFromOptions(xGrad, NULL, "-adapt_gradient_view")); 1490 /* Compute vertexwise Hessians from cellwise Hessians */ 1491 PetscCall(DMCreateLocalVector(dmHess, &xHess)); 1492 PetscCall(DMPlexComputeGradientClementInterpolant(dmGrad, xGrad, xHess)); 1493 PetscCall(VecViewFromOptions(xHess, NULL, "-adapt_hessian_view")); 1494 PetscCall(VecDestroy(&xGrad)); 1495 PetscCall(DMDestroy(&dmGrad)); 1496 /* Compute L-p normalized metric */ 1497 PetscCall(DMClone(dm, &dmMetric)); 1498 N = adaptor->Nadapt >= 0 ? adaptor->Nadapt : PetscPowRealInt(adaptor->refinementFactor, dim) * ((PetscReal)(vEnd - vStart)); 1499 // TODO This was where the old monitor was, figure out how to show metric and target N 1500 PetscCall(DMPlexMetricSetTargetComplexity(dmMetric, N)); 1501 if (higherOrder) { 1502 /* Project Hessian into P1 space, if required */ 1503 PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric)); 1504 PetscCall(DMProjectFieldLocal(dmMetric, 0.0, xHess, funcs, INSERT_ALL_VALUES, metric)); 1505 PetscCall(VecDestroy(&xHess)); 1506 xHess = metric; 1507 } 1508 PetscCall(PetscFree(funcs)); 1509 PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric)); 1510 PetscCall(DMPlexMetricDeterminantCreate(dmMetric, 0, &determinant, &dmDet)); 1511 PetscCall(DMPlexMetricNormalize(dmMetric, xHess, PETSC_TRUE, PETSC_TRUE, metric, determinant)); 1512 PetscCall(VecDestroy(&determinant)); 1513 PetscCall(DMDestroy(&dmDet)); 1514 PetscCall(VecDestroy(&xHess)); 1515 PetscCall(DMDestroy(&dmHess)); 1516 /* Adapt DM from metric */ 1517 PetscCall(DMGetLabel(dm, "marker", &bdLabel)); 1518 PetscCall(DMAdaptMetric(dm, metric, bdLabel, rgLabel, &odm)); 1519 PetscCall(DMAdaptorMonitor(adaptor, adaptIter, dm, odm, 1, &errorNorm, NULL)); 1520 adapted = PETSC_TRUE; 1521 /* Cleanup */ 1522 PetscCall(VecDestroy(&metric)); 1523 PetscCall(DMDestroy(&dmMetric)); 1524 } break; 1525 default: 1526 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid adaptation type: %d", adaptor->adaptCriterion); 1527 } 1528 PetscCall(DMAdaptorPostAdapt(adaptor)); 1529 PetscCall(DMRestoreLocalVector(dm, &locX)); 1530 /* If DM was adapted, replace objects and recreate solution */ 1531 if (adapted) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1535 PetscCall(PetscObjectSetName((PetscObject)odm, name)); 1536 /* Reconfigure solver */ 1537 PetscCall(SNESReset(adaptor->snes)); 1538 PetscCall(SNESSetDM(adaptor->snes, odm)); 1539 PetscCall(DMAdaptorSetSolver(adaptor, adaptor->snes)); 1540 PetscCall(DMPlexSetSNESLocalFEM(odm, PETSC_FALSE, ctx)); 1541 PetscCall(SNESSetFromOptions(adaptor->snes)); 1542 /* Transfer system */ 1543 PetscCall(DMCopyDisc(dm, odm)); 1544 /* Transfer solution */ 1545 PetscCall(DMCreateGlobalVector(odm, &ox)); 1546 PetscCall(PetscObjectGetName((PetscObject)x, &name)); 1547 PetscCall(PetscObjectSetName((PetscObject)ox, name)); 1548 PetscCall(DMAdaptorTransferSolution(adaptor, dm, x, odm, ox)); 1549 /* Cleanup adaptivity info */ 1550 if (adaptIter > 0) PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_(comm))); 1551 PetscCall(DMForestSetAdaptivityForest(dm, NULL)); /* clear internal references to the previous dm */ 1552 PetscCall(DMDestroy(&dm)); 1553 PetscCall(VecDestroy(&x)); 1554 *adm = odm; 1555 *ax = ox; 1556 } else { 1557 *adm = dm; 1558 *ax = x; 1559 adaptIter = numAdapt; 1560 } 1561 if (adaptIter < numAdapt - 1) { 1562 PetscCall(DMViewFromOptions(odm, NULL, "-dm_adapt_iter_view")); 1563 PetscCall(VecViewFromOptions(ox, NULL, "-sol_adapt_iter_view")); 1564 } 1565 } 1566 PetscCall(DMViewFromOptions(*adm, NULL, "-dm_adapt_view")); 1567 PetscCall(VecViewFromOptions(*ax, NULL, "-sol_adapt_view")); 1568 PetscFunctionReturn(PETSC_SUCCESS); 1569 } 1570 1571 /*@ 1572 DMAdaptorAdapt - Creates a new `DM` that is adapted to the problem 1573 1574 Not Collective 1575 1576 Input Parameters: 1577 + adaptor - The `DMAdaptor` object 1578 . x - The global approximate solution 1579 - strategy - The adaptation strategy, see `DMAdaptationStrategy` 1580 1581 Output Parameters: 1582 + adm - The adapted `DM` 1583 - ax - The adapted solution 1584 1585 Options Database Keys: 1586 + -snes_adapt <strategy> - initial, sequential, multigrid 1587 . -adapt_gradient_view - View the Clement interpolant of the solution gradient 1588 . -adapt_hessian_view - View the Clement interpolant of the solution Hessian 1589 - -adapt_metric_view - View the metric tensor for adaptive mesh refinement 1590 1591 Level: intermediate 1592 1593 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptationStrategy`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()` 1594 @*/ 1595 PetscErrorCode DMAdaptorAdapt(DMAdaptor adaptor, Vec x, DMAdaptationStrategy strategy, DM *adm, Vec *ax) 1596 { 1597 PetscFunctionBegin; 1598 switch (strategy) { 1599 case DM_ADAPTATION_INITIAL: 1600 PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_FALSE, adm, ax)); 1601 break; 1602 case DM_ADAPTATION_SEQUENTIAL: 1603 PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_TRUE, adm, ax)); 1604 break; 1605 default: 1606 SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Unrecognized adaptation strategy %d", strategy); 1607 } 1608 PetscFunctionReturn(PETSC_SUCCESS); 1609 } 1610 1611 /*@C 1612 DMAdaptorGetMixedSetupFunction - Get the function setting up the mixed problem, if it exists 1613 1614 Not Collective 1615 1616 Input Parameter: 1617 . adaptor - the `DMAdaptor` 1618 1619 Output Parameter: 1620 . setupFunc - the function setting up the mixed problem, or `NULL` 1621 1622 Level: advanced 1623 1624 .seealso: `DMAdaptor`, `DMAdaptorSetMixedSetupFunction()`, `DMAdaptorAdapt()` 1625 @*/ 1626 PetscErrorCode DMAdaptorGetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (**setupFunc)(DMAdaptor, DM)) 1627 { 1628 PetscFunctionBegin; 1629 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1630 PetscAssertPointer(setupFunc, 2); 1631 *setupFunc = adaptor->ops->mixedsetup; 1632 PetscFunctionReturn(PETSC_SUCCESS); 1633 } 1634 1635 /*@C 1636 DMAdaptorSetMixedSetupFunction - Set the function setting up the mixed problem 1637 1638 Not Collective 1639 1640 Input Parameters: 1641 + adaptor - the `DMAdaptor` 1642 - setupFunc - the function setting up the mixed problem 1643 1644 Level: advanced 1645 1646 .seealso: `DMAdaptor`, `DMAdaptorGetMixedSetupFunction()`, `DMAdaptorAdapt()` 1647 @*/ 1648 PetscErrorCode DMAdaptorSetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (*setupFunc)(DMAdaptor, DM)) 1649 { 1650 PetscFunctionBegin; 1651 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1652 PetscValidFunction(setupFunc, 2); 1653 adaptor->ops->mixedsetup = setupFunc; 1654 PetscFunctionReturn(PETSC_SUCCESS); 1655 } 1656 1657 /*@ 1658 DMAdaptorGetCriterion - Get the adaptation criterion 1659 1660 Not Collective 1661 1662 Input Parameter: 1663 . adaptor - the `DMAdaptor` 1664 1665 Output Parameter: 1666 . criterion - the criterion for adaptation 1667 1668 Level: advanced 1669 1670 .seealso: `DMAdaptor`, `DMAdaptorSetCriterion()`, `DMAdaptationCriterion` 1671 @*/ 1672 PetscErrorCode DMAdaptorGetCriterion(DMAdaptor adaptor, DMAdaptationCriterion *criterion) 1673 { 1674 PetscFunctionBegin; 1675 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1676 PetscAssertPointer(criterion, 2); 1677 *criterion = adaptor->adaptCriterion; 1678 PetscFunctionReturn(PETSC_SUCCESS); 1679 } 1680 1681 /*@ 1682 DMAdaptorSetCriterion - Set the adaptation criterion 1683 1684 Not Collective 1685 1686 Input Parameters: 1687 + adaptor - the `DMAdaptor` 1688 - criterion - the adaptation criterion 1689 1690 Level: advanced 1691 1692 .seealso: `DMAdaptor`, `DMAdaptorGetCriterion()`, `DMAdaptationCriterion` 1693 @*/ 1694 PetscErrorCode DMAdaptorSetCriterion(DMAdaptor adaptor, DMAdaptationCriterion criterion) 1695 { 1696 PetscFunctionBegin; 1697 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1698 adaptor->adaptCriterion = criterion; 1699 PetscFunctionReturn(PETSC_SUCCESS); 1700 } 1701 1702 static PetscErrorCode DMAdaptorInitialize_Gradient(DMAdaptor adaptor) 1703 { 1704 PetscFunctionBegin; 1705 adaptor->ops->computeerrorindicator = DMAdaptorComputeErrorIndicator_Gradient; 1706 adaptor->ops->computecellerrorindicator = DMAdaptorComputeCellErrorIndicator_Gradient; 1707 PetscFunctionReturn(PETSC_SUCCESS); 1708 } 1709 1710 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor adaptor) 1711 { 1712 PetscFunctionBegin; 1713 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1714 adaptor->data = NULL; 1715 1716 PetscCall(DMAdaptorInitialize_Gradient(adaptor)); 1717 PetscFunctionReturn(PETSC_SUCCESS); 1718 } 1719 1720 static PetscErrorCode DMAdaptorInitialize_Flux(DMAdaptor adaptor) 1721 { 1722 PetscFunctionBegin; 1723 adaptor->ops->computeerrorindicator = DMAdaptorComputeErrorIndicator_Flux; 1724 PetscFunctionReturn(PETSC_SUCCESS); 1725 } 1726 1727 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor adaptor) 1728 { 1729 PetscFunctionBegin; 1730 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1731 adaptor->data = NULL; 1732 1733 PetscCall(DMAdaptorInitialize_Flux(adaptor)); 1734 PetscFunctionReturn(PETSC_SUCCESS); 1735 } 1736