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 8 #include <petsc/private/dmadaptorimpl.h> 9 #include <petsc/private/dmpleximpl.h> 10 #include <petsc/private/petscfeimpl.h> 11 12 PetscClassId DMADAPTOR_CLASSID; 13 14 PetscFunctionList DMAdaptorList = NULL; 15 PetscBool DMAdaptorRegisterAllCalled = PETSC_FALSE; 16 17 /*@C 18 DMAdaptorRegister - Adds a new adaptor component implementation 19 20 Not Collective 21 22 Input Parameters: 23 + name - The name of a new user-defined creation routine 24 - create_func - The creation routine 25 26 Example Usage: 27 .vb 28 DMAdaptorRegister("my_adaptor", MyAdaptorCreate); 29 .ve 30 31 Then, your adaptor type can be chosen with the procedural interface via 32 .vb 33 DMAdaptorCreate(MPI_Comm, DMAdaptor *); 34 DMAdaptorSetType(DMAdaptor, "my_adaptor"); 35 .ve 36 or at runtime via the option 37 .vb 38 -adaptor_type my_adaptor 39 .ve 40 41 Level: advanced 42 43 Note: 44 `DMAdaptorRegister()` may be called multiple times to add several user-defined adaptors 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorRegisterAll()`, `DMAdaptorRegisterDestroy()` 47 @*/ 48 PetscErrorCode DMAdaptorRegister(const char name[], PetscErrorCode (*create_func)(DMAdaptor)) 49 { 50 PetscFunctionBegin; 51 PetscCall(DMInitializePackage()); 52 PetscCall(PetscFunctionListAdd(&DMAdaptorList, name, create_func)); 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor); 57 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor); 58 59 /*@C 60 DMAdaptorRegisterAll - Registers all of the adaptor components in the `DM` package. 61 62 Not Collective 63 64 Level: advanced 65 66 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptorType`, `DMRegisterAll()`, `DMAdaptorRegisterDestroy()` 67 @*/ 68 PetscErrorCode DMAdaptorRegisterAll(void) 69 { 70 PetscFunctionBegin; 71 if (DMAdaptorRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 72 DMAdaptorRegisterAllCalled = PETSC_TRUE; 73 74 PetscCall(DMAdaptorRegister(DMADAPTORGRADIENT, DMAdaptorCreate_Gradient)); 75 PetscCall(DMAdaptorRegister(DMADAPTORFLUX, DMAdaptorCreate_Flux)); 76 PetscFunctionReturn(PETSC_SUCCESS); 77 } 78 79 /*@C 80 DMAdaptorRegisterDestroy - This function destroys the registered `DMAdaptorType`. It is called from `PetscFinalize()`. 81 82 Not collective 83 84 Level: developer 85 86 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMAdaptorType`, `PetscInitialize()` 87 @*/ 88 PetscErrorCode DMAdaptorRegisterDestroy(void) 89 { 90 PetscFunctionBegin; 91 PetscCall(PetscFunctionListDestroy(&DMAdaptorList)); 92 DMAdaptorRegisterAllCalled = PETSC_FALSE; 93 PetscFunctionReturn(PETSC_SUCCESS); 94 } 95 96 /*@ 97 DMAdaptorCreate - Create a `DMAdaptor` object. Its purpose is to construct a adaptation `DMLabel` or metric `Vec` that can be used to modify the `DM`. 98 99 Collective 100 101 Input Parameter: 102 . comm - The communicator for the `DMAdaptor` object 103 104 Output Parameter: 105 . adaptor - The `DMAdaptor` object 106 107 Level: beginner 108 109 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorDestroy()`, `DMAdaptorAdapt()`, `PetscConvEst`, `PetscConvEstCreate()` 110 @*/ 111 PetscErrorCode DMAdaptorCreate(MPI_Comm comm, DMAdaptor *adaptor) 112 { 113 VecTaggerBox refineBox, coarsenBox; 114 115 PetscFunctionBegin; 116 PetscAssertPointer(adaptor, 2); 117 PetscCall(PetscSysInitializePackage()); 118 119 PetscCall(PetscHeaderCreate(*adaptor, DMADAPTOR_CLASSID, "DMAdaptor", "DM Adaptor", "DMAdaptor", comm, DMAdaptorDestroy, DMAdaptorView)); 120 (*adaptor)->monitor = PETSC_FALSE; 121 (*adaptor)->adaptCriterion = DM_ADAPTATION_NONE; 122 (*adaptor)->numSeq = 1; 123 (*adaptor)->Nadapt = -1; 124 (*adaptor)->refinementFactor = 2.0; 125 refineBox.min = refineBox.max = PETSC_MAX_REAL; 126 PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->refineTag)); 127 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->refineTag, "refine_")); 128 PetscCall(VecTaggerSetType((*adaptor)->refineTag, VECTAGGERABSOLUTE)); 129 PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->refineTag, &refineBox)); 130 coarsenBox.min = coarsenBox.max = PETSC_MAX_REAL; 131 PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->coarsenTag)); 132 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->coarsenTag, "coarsen_")); 133 PetscCall(VecTaggerSetType((*adaptor)->coarsenTag, VECTAGGERABSOLUTE)); 134 PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->coarsenTag, &coarsenBox)); 135 PetscFunctionReturn(PETSC_SUCCESS); 136 } 137 138 /*@ 139 DMAdaptorDestroy - Destroys a `DMAdaptor` object 140 141 Collective 142 143 Input Parameter: 144 . adaptor - The `DMAdaptor` object 145 146 Level: beginner 147 148 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 149 @*/ 150 PetscErrorCode DMAdaptorDestroy(DMAdaptor *adaptor) 151 { 152 PetscFunctionBegin; 153 if (!*adaptor) PetscFunctionReturn(PETSC_SUCCESS); 154 PetscValidHeaderSpecific(*adaptor, DMADAPTOR_CLASSID, 1); 155 if (--((PetscObject)*adaptor)->refct > 0) { 156 *adaptor = NULL; 157 PetscFunctionReturn(PETSC_SUCCESS); 158 } 159 PetscCall(VecTaggerDestroy(&(*adaptor)->refineTag)); 160 PetscCall(VecTaggerDestroy(&(*adaptor)->coarsenTag)); 161 PetscCall(PetscFree2((*adaptor)->exactSol, (*adaptor)->exactCtx)); 162 PetscCall(PetscHeaderDestroy(adaptor)); 163 PetscFunctionReturn(PETSC_SUCCESS); 164 } 165 166 /*@ 167 DMAdaptorSetType - Sets the particular implementation for a adaptor. 168 169 Collective 170 171 Input Parameters: 172 + adaptor - The `DMAdaptor` 173 - method - The name of the adaptor type 174 175 Options Database Key: 176 . -adaptor_type <type> - Sets the adaptor type; see `DMAdaptorType` 177 178 Level: intermediate 179 180 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorGetType()`, `DMAdaptorCreate()` 181 @*/ 182 PetscErrorCode DMAdaptorSetType(DMAdaptor adaptor, DMAdaptorType method) 183 { 184 PetscErrorCode (*r)(DMAdaptor); 185 PetscBool match; 186 187 PetscFunctionBegin; 188 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 189 PetscCall(PetscObjectTypeCompare((PetscObject)adaptor, method, &match)); 190 if (match) PetscFunctionReturn(PETSC_SUCCESS); 191 192 PetscCall(DMAdaptorRegisterAll()); 193 PetscCall(PetscFunctionListFind(DMAdaptorList, method, &r)); 194 PetscCheck(r, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMAdaptor type: %s", method); 195 196 PetscTryTypeMethod(adaptor, destroy); 197 PetscCall(PetscMemzero(adaptor->ops, sizeof(*adaptor->ops))); 198 PetscCall(PetscObjectChangeTypeName((PetscObject)adaptor, method)); 199 PetscCall((*r)(adaptor)); 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 /*@ 204 DMAdaptorGetType - Gets the type name (as a string) from the adaptor. 205 206 Not Collective 207 208 Input Parameter: 209 . adaptor - The `DMAdaptor` 210 211 Output Parameter: 212 . type - The `DMAdaptorType` name 213 214 Level: intermediate 215 216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorSetType()`, `DMAdaptorCreate()` 217 @*/ 218 PetscErrorCode DMAdaptorGetType(DMAdaptor adaptor, DMAdaptorType *type) 219 { 220 PetscFunctionBegin; 221 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 222 PetscAssertPointer(type, 2); 223 PetscCall(DMAdaptorRegisterAll()); 224 *type = ((PetscObject)adaptor)->type_name; 225 PetscFunctionReturn(PETSC_SUCCESS); 226 } 227 228 /*@ 229 DMAdaptorSetFromOptions - Sets properties of a `DMAdaptor` object from values in the options database 230 231 Collective 232 233 Input Parameter: 234 . adaptor - The `DMAdaptor` object 235 236 Options Database Keys: 237 + -adaptor_monitor <bool> - Monitor the adaptation process 238 . -adaptor_sequence_num <num> - Number of adaptations to generate an optimal grid 239 . -adaptor_target_num <num> - Set the target number of vertices N_adapt, -1 for automatic determination 240 . -adaptor_refinement_factor <r> - Set r such that N_adapt = r^dim N_orig 241 - -adaptor_mixed_setup_function <func> - Set the fnction func that sets up the mixed problem 242 243 Level: beginner 244 245 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 246 @*/ 247 PetscErrorCode DMAdaptorSetFromOptions(DMAdaptor adaptor) 248 { 249 char typeName[PETSC_MAX_PATH_LEN]; 250 const char *defName = DMADAPTORGRADIENT; 251 char funcname[PETSC_MAX_PATH_LEN]; 252 PetscBool flg; 253 254 PetscFunctionBegin; 255 PetscObjectOptionsBegin((PetscObject)adaptor); 256 PetscCall(PetscOptionsFList("-adaptor_type", "DMAdaptor", "DMAdaptorSetType", DMAdaptorList, defName, typeName, 1024, &flg)); 257 if (flg) PetscCall(DMAdaptorSetType(adaptor, typeName)); 258 else if (!((PetscObject)adaptor)->type_name) PetscCall(DMAdaptorSetType(adaptor, defName)); 259 PetscCall(PetscOptionsBool("-adaptor_monitor", "Monitor the adaptation process", "DMAdaptorMonitor", adaptor->monitor, &adaptor->monitor, NULL)); 260 PetscCall(PetscOptionsInt("-adaptor_sequence_num", "Number of adaptations to generate an optimal grid", "DMAdaptorSetSequenceLength", adaptor->numSeq, &adaptor->numSeq, NULL)); 261 PetscCall(PetscOptionsInt("-adaptor_target_num", "Set the target number of vertices N_adapt, -1 for automatic determination", "DMAdaptor", adaptor->Nadapt, &adaptor->Nadapt, NULL)); 262 PetscCall(PetscOptionsReal("-adaptor_refinement_factor", "Set r such that N_adapt = r^dim N_orig", "DMAdaptor", adaptor->refinementFactor, &adaptor->refinementFactor, NULL)); 263 PetscCall(PetscOptionsString("-adaptor_mixed_setup_function", "Function to setup the mixed problem", "DMAdaptorSetMixedSetupFunction", funcname, funcname, sizeof(funcname), &flg)); 264 if (flg) { 265 PetscErrorCode (*setupFunc)(DMAdaptor, DM); 266 267 PetscCall(PetscDLSym(NULL, funcname, (void **)&setupFunc)); 268 PetscCheck(setupFunc, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname); 269 PetscCall(DMAdaptorSetMixedSetupFunction(adaptor, setupFunc)); 270 } 271 PetscOptionsEnd(); 272 PetscCall(VecTaggerSetFromOptions(adaptor->refineTag)); 273 PetscCall(VecTaggerSetFromOptions(adaptor->coarsenTag)); 274 PetscFunctionReturn(PETSC_SUCCESS); 275 } 276 277 /*@ 278 DMAdaptorView - Views a `DMAdaptor` object 279 280 Collective 281 282 Input Parameters: 283 + adaptor - The `DMAdaptor` object 284 - viewer - The `PetscViewer` object 285 286 Level: beginner 287 288 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 289 @*/ 290 PetscErrorCode DMAdaptorView(DMAdaptor adaptor, PetscViewer viewer) 291 { 292 PetscFunctionBegin; 293 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)adaptor, viewer)); 294 PetscCall(PetscViewerASCIIPrintf(viewer, "DM Adaptor\n")); 295 PetscCall(PetscViewerASCIIPrintf(viewer, " sequence length: %" PetscInt_FMT "\n", adaptor->numSeq)); 296 PetscCall(VecTaggerView(adaptor->refineTag, viewer)); 297 PetscCall(VecTaggerView(adaptor->coarsenTag, viewer)); 298 PetscFunctionReturn(PETSC_SUCCESS); 299 } 300 301 /*@ 302 DMAdaptorGetSolver - Gets the solver used to produce discrete solutions 303 304 Not Collective 305 306 Input Parameter: 307 . adaptor - The `DMAdaptor` object 308 309 Output Parameter: 310 . snes - The solver 311 312 Level: intermediate 313 314 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 315 @*/ 316 PetscErrorCode DMAdaptorGetSolver(DMAdaptor adaptor, SNES *snes) 317 { 318 PetscFunctionBegin; 319 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 320 PetscAssertPointer(snes, 2); 321 *snes = adaptor->snes; 322 PetscFunctionReturn(PETSC_SUCCESS); 323 } 324 325 /*@ 326 DMAdaptorSetSolver - Sets the solver used to produce discrete solutions 327 328 Not Collective 329 330 Input Parameters: 331 + adaptor - The `DMAdaptor` object 332 - snes - The solver, this MUST have an attached `DM`/`PetscDS`, so that the exact solution can be computed 333 334 Level: intermediate 335 336 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorGetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 337 @*/ 338 PetscErrorCode DMAdaptorSetSolver(DMAdaptor adaptor, SNES snes) 339 { 340 PetscFunctionBegin; 341 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 342 PetscValidHeaderSpecific(snes, SNES_CLASSID, 2); 343 adaptor->snes = snes; 344 PetscCall(SNESGetDM(adaptor->snes, &adaptor->idm)); 345 PetscFunctionReturn(PETSC_SUCCESS); 346 } 347 348 /*@ 349 DMAdaptorGetSequenceLength - Gets the number of sequential adaptations used by an adapter 350 351 Not Collective 352 353 Input Parameter: 354 . adaptor - The `DMAdaptor` object 355 356 Output Parameter: 357 . num - The number of adaptations 358 359 Level: intermediate 360 361 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorSetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 362 @*/ 363 PetscErrorCode DMAdaptorGetSequenceLength(DMAdaptor adaptor, PetscInt *num) 364 { 365 PetscFunctionBegin; 366 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 367 PetscAssertPointer(num, 2); 368 *num = adaptor->numSeq; 369 PetscFunctionReturn(PETSC_SUCCESS); 370 } 371 372 /*@ 373 DMAdaptorSetSequenceLength - Sets the number of sequential adaptations 374 375 Not Collective 376 377 Input Parameters: 378 + adaptor - The `DMAdaptor` object 379 - num - The number of adaptations 380 381 Level: intermediate 382 383 .seealso: [](ch_dmbase), `DMAdaptorGetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 384 @*/ 385 PetscErrorCode DMAdaptorSetSequenceLength(DMAdaptor adaptor, PetscInt num) 386 { 387 PetscFunctionBegin; 388 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 389 adaptor->numSeq = num; 390 PetscFunctionReturn(PETSC_SUCCESS); 391 } 392 393 static PetscErrorCode DMAdaptorTransferSolution_Exact_Private(DMAdaptor adaptor, DM dm, Vec u, DM adm, Vec au, void *ctx) 394 { 395 PetscFunctionBeginUser; 396 PetscCall(DMProjectFunction(adm, 0.0, adaptor->exactSol, adaptor->exactCtx, INSERT_ALL_VALUES, au)); 397 PetscFunctionReturn(PETSC_SUCCESS); 398 } 399 400 /*@ 401 DMAdaptorSetUp - After the solver is specified, creates data structures for controlling adaptivity 402 403 Collective 404 405 Input Parameter: 406 . adaptor - The `DMAdaptor` object 407 408 Level: beginner 409 410 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()` 411 @*/ 412 PetscErrorCode DMAdaptorSetUp(DMAdaptor adaptor) 413 { 414 PetscDS prob; 415 PetscInt Nf, f; 416 417 PetscFunctionBegin; 418 PetscCall(DMGetDS(adaptor->idm, &prob)); 419 PetscCall(VecTaggerSetUp(adaptor->refineTag)); 420 PetscCall(VecTaggerSetUp(adaptor->coarsenTag)); 421 PetscCall(PetscDSGetNumFields(prob, &Nf)); 422 PetscCall(PetscMalloc2(Nf, &adaptor->exactSol, Nf, &adaptor->exactCtx)); 423 for (f = 0; f < Nf; ++f) { 424 PetscCall(PetscDSGetExactSolution(prob, f, &adaptor->exactSol[f], &adaptor->exactCtx[f])); 425 /* TODO Have a flag that forces projection rather than using the exact solution */ 426 if (adaptor->exactSol[0]) PetscCall(DMAdaptorSetTransferFunction(adaptor, DMAdaptorTransferSolution_Exact_Private)); 427 } 428 PetscTryTypeMethod(adaptor, setup); 429 PetscFunctionReturn(PETSC_SUCCESS); 430 } 431 432 PetscErrorCode DMAdaptorGetTransferFunction(DMAdaptor adaptor, PetscErrorCode (**tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *)) 433 { 434 PetscFunctionBegin; 435 *tfunc = adaptor->ops->transfersolution; 436 PetscFunctionReturn(PETSC_SUCCESS); 437 } 438 439 PetscErrorCode DMAdaptorSetTransferFunction(DMAdaptor adaptor, PetscErrorCode (*tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *)) 440 { 441 PetscFunctionBegin; 442 adaptor->ops->transfersolution = tfunc; 443 PetscFunctionReturn(PETSC_SUCCESS); 444 } 445 446 static PetscErrorCode DMAdaptorPreAdapt(DMAdaptor adaptor, Vec locX) 447 { 448 DM plex; 449 PetscDS prob; 450 PetscObject obj; 451 PetscClassId id; 452 PetscBool isForest; 453 454 PetscFunctionBegin; 455 PetscCall(DMConvert(adaptor->idm, DMPLEX, &plex)); 456 PetscCall(DMGetDS(adaptor->idm, &prob)); 457 PetscCall(PetscDSGetDiscretization(prob, 0, &obj)); 458 PetscCall(PetscObjectGetClassId(obj, &id)); 459 PetscCall(DMIsForest(adaptor->idm, &isForest)); 460 if (adaptor->adaptCriterion == DM_ADAPTATION_NONE) { 461 if (isForest) { 462 adaptor->adaptCriterion = DM_ADAPTATION_LABEL; 463 } 464 #if defined(PETSC_HAVE_PRAGMATIC) 465 else { 466 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 467 } 468 #elif defined(PETSC_HAVE_MMG) 469 else { 470 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 471 } 472 #elif defined(PETSC_HAVE_PARMMG) 473 else { 474 adaptor->adaptCriterion = DM_ADAPTATION_METRIC; 475 } 476 #else 477 else { 478 adaptor->adaptCriterion = DM_ADAPTATION_LABEL; 479 } 480 #endif 481 } 482 if (id == PETSCFV_CLASSID) { 483 adaptor->femType = PETSC_FALSE; 484 } else { 485 adaptor->femType = PETSC_TRUE; 486 } 487 if (adaptor->femType) { 488 /* Compute local solution bc */ 489 PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL)); 490 } else { 491 PetscFV fvm = (PetscFV)obj; 492 PetscLimiter noneLimiter; 493 Vec grad; 494 495 PetscCall(PetscFVGetComputeGradients(fvm, &adaptor->computeGradient)); 496 PetscCall(PetscFVSetComputeGradients(fvm, PETSC_TRUE)); 497 /* Use no limiting when reconstructing gradients for adaptivity */ 498 PetscCall(PetscFVGetLimiter(fvm, &adaptor->limiter)); 499 PetscCall(PetscObjectReference((PetscObject)adaptor->limiter)); 500 PetscCall(PetscLimiterCreate(PetscObjectComm((PetscObject)fvm), &noneLimiter)); 501 PetscCall(PetscLimiterSetType(noneLimiter, PETSCLIMITERNONE)); 502 PetscCall(PetscFVSetLimiter(fvm, noneLimiter)); 503 /* Get FVM data */ 504 PetscCall(DMPlexGetDataFVM(plex, fvm, &adaptor->cellGeom, &adaptor->faceGeom, &adaptor->gradDM)); 505 PetscCall(VecGetDM(adaptor->cellGeom, &adaptor->cellDM)); 506 PetscCall(VecGetArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray)); 507 /* Compute local solution bc */ 508 PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL)); 509 /* Compute gradients */ 510 PetscCall(DMCreateGlobalVector(adaptor->gradDM, &grad)); 511 PetscCall(DMPlexReconstructGradientsFVM(plex, locX, grad)); 512 PetscCall(DMGetLocalVector(adaptor->gradDM, &adaptor->cellGrad)); 513 PetscCall(DMGlobalToLocalBegin(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad)); 514 PetscCall(DMGlobalToLocalEnd(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad)); 515 PetscCall(VecDestroy(&grad)); 516 PetscCall(VecGetArrayRead(adaptor->cellGrad, &adaptor->cellGradArray)); 517 } 518 PetscCall(DMDestroy(&plex)); 519 PetscFunctionReturn(PETSC_SUCCESS); 520 } 521 522 static PetscErrorCode DMAdaptorTransferSolution(DMAdaptor adaptor, DM dm, Vec x, DM adm, Vec ax) 523 { 524 PetscReal time = 0.0; 525 Mat interp; 526 void *ctx; 527 528 PetscFunctionBegin; 529 PetscCall(DMGetApplicationContext(dm, &ctx)); 530 if (adaptor->ops->transfersolution) PetscUseTypeMethod(adaptor, transfersolution, dm, x, adm, ax, ctx); 531 else { 532 switch (adaptor->adaptCriterion) { 533 case DM_ADAPTATION_LABEL: 534 PetscCall(DMForestTransferVec(dm, x, adm, ax, PETSC_TRUE, time)); 535 break; 536 case DM_ADAPTATION_REFINE: 537 case DM_ADAPTATION_METRIC: 538 PetscCall(DMCreateInterpolation(dm, adm, &interp, NULL)); 539 PetscCall(MatInterpolate(interp, x, ax)); 540 PetscCall(DMInterpolate(dm, interp, adm)); 541 PetscCall(MatDestroy(&interp)); 542 break; 543 default: 544 SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_SUP, "No built-in projection for this adaptation criterion: %d", adaptor->adaptCriterion); 545 } 546 } 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 static PetscErrorCode DMAdaptorPostAdapt(DMAdaptor adaptor) 551 { 552 PetscDS prob; 553 PetscObject obj; 554 PetscClassId id; 555 556 PetscFunctionBegin; 557 PetscCall(DMGetDS(adaptor->idm, &prob)); 558 PetscCall(PetscDSGetDiscretization(prob, 0, &obj)); 559 PetscCall(PetscObjectGetClassId(obj, &id)); 560 if (id == PETSCFV_CLASSID) { 561 PetscFV fvm = (PetscFV)obj; 562 563 PetscCall(PetscFVSetComputeGradients(fvm, adaptor->computeGradient)); 564 /* Restore original limiter */ 565 PetscCall(PetscFVSetLimiter(fvm, adaptor->limiter)); 566 567 PetscCall(VecRestoreArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray)); 568 PetscCall(VecRestoreArrayRead(adaptor->cellGrad, &adaptor->cellGradArray)); 569 PetscCall(DMRestoreLocalVector(adaptor->gradDM, &adaptor->cellGrad)); 570 } 571 PetscFunctionReturn(PETSC_SUCCESS); 572 } 573 574 /* 575 DMAdaptorComputeCellErrorIndicator_Gradient - Use the integrated gradient as an error indicator in the `DMAdaptor` 576 577 Input Parameters: 578 + adaptor - The `DMAdaptor` object 579 . dim - The topological dimension 580 . cell - The cell 581 . field - The field integrated over the cell 582 . gradient - The gradient integrated over the cell 583 . cg - A `PetscFVCellGeom` struct 584 - ctx - A user context 585 586 Output Parameter: 587 . errInd - The error indicator 588 589 Developer Note: 590 Some of the input arguments are absurdly specialized to special situations, it is not clear this is a good general API 591 592 .seealso: [](ch_dmbase), `DMAdaptor` 593 */ 594 static PetscErrorCode DMAdaptorComputeCellErrorIndicator_Gradient(DMAdaptor adaptor, PetscInt dim, PetscInt Nc, const PetscScalar *field, const PetscScalar *gradient, const PetscFVCellGeom *cg, PetscReal *errInd, void *ctx) 595 { 596 PetscReal err = 0.; 597 PetscInt c, d; 598 599 PetscFunctionBeginHot; 600 for (c = 0; c < Nc; c++) { 601 for (d = 0; d < dim; ++d) err += PetscSqr(PetscRealPart(gradient[c * dim + d])); 602 } 603 *errInd = cg->volume * err; 604 PetscFunctionReturn(PETSC_SUCCESS); 605 } 606 607 static PetscErrorCode DMAdaptorComputeErrorIndicator_Gradient(DMAdaptor adaptor, Vec locX, Vec errVec) 608 { 609 DM dm, plex, edm, eplex; 610 PetscDS ds; 611 PetscObject obj; 612 PetscClassId id; 613 void *ctx; 614 PetscQuadrature quad; 615 PetscScalar *earray; 616 PetscReal minMaxInd[2] = {PETSC_MAX_REAL, PETSC_MIN_REAL}, minMaxIndGlobal[2]; 617 PetscInt dim, cdim, cStart, cEnd, Nf, Nc; 618 619 PetscFunctionBegin; 620 PetscCall(VecGetDM(locX, &dm)); 621 PetscCall(DMConvert(dm, DMPLEX, &plex)); 622 PetscCall(VecGetDM(errVec, &edm)); 623 PetscCall(DMConvert(edm, DMPLEX, &eplex)); 624 PetscCall(DMGetDimension(plex, &dim)); 625 PetscCall(DMGetCoordinateDim(plex, &cdim)); 626 PetscCall(DMGetApplicationContext(plex, &ctx)); 627 PetscCall(DMGetDS(plex, &ds)); 628 PetscCall(PetscDSGetNumFields(ds, &Nf)); 629 PetscCall(PetscDSGetDiscretization(ds, 0, &obj)); 630 PetscCall(PetscObjectGetClassId(obj, &id)); 631 632 PetscCall(VecGetArray(errVec, &earray)); 633 PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd)); 634 for (PetscInt cell = cStart; cell < cEnd; ++cell) { 635 PetscScalar *eval; 636 PetscReal errInd = 0.; 637 638 if (id == PETSCFV_CLASSID) { 639 PetscFV fv = (PetscFV)obj; 640 const PetscScalar *pointSols; 641 const PetscScalar *pointSol; 642 const PetscScalar *pointGrad; 643 PetscFVCellGeom *cg; 644 645 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 646 PetscCall(VecGetArrayRead(locX, &pointSols)); 647 PetscCall(DMPlexPointLocalRead(plex, cell, pointSols, (void *)&pointSol)); 648 PetscCall(DMPlexPointLocalRead(adaptor->gradDM, cell, adaptor->cellGradArray, (void *)&pointGrad)); 649 PetscCall(DMPlexPointLocalRead(adaptor->cellDM, cell, adaptor->cellGeomArray, &cg)); 650 PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, pointSol, pointGrad, cg, &errInd, ctx); 651 PetscCall(VecRestoreArrayRead(locX, &pointSols)); 652 } else { 653 PetscFE fe = (PetscFE)obj; 654 PetscScalar *x = NULL, *field, *gradient, *interpolant, *interpolantGrad; 655 PetscFVCellGeom cg; 656 PetscFEGeom fegeom; 657 const PetscReal *quadWeights; 658 PetscReal *coords; 659 PetscInt Nb, Nq, qNc; 660 661 fegeom.dim = dim; 662 fegeom.dimEmbed = cdim; 663 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 664 PetscCall(PetscFEGetQuadrature(fe, &quad)); 665 PetscCall(PetscFEGetDimension(fe, &Nb)); 666 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 667 PetscCall(PetscCalloc6(Nc, &field, cdim * Nc, &gradient, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 668 PetscCall(PetscMalloc2(Nc, &interpolant, cdim * Nc, &interpolantGrad)); 669 PetscCall(DMPlexComputeCellGeometryFEM(plex, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 670 PetscCall(DMPlexComputeCellGeometryFVM(plex, cell, &cg.volume, NULL, NULL)); 671 PetscCall(PetscArrayzero(gradient, cdim * Nc)); 672 PetscCall(DMPlexVecGetClosure(plex, NULL, locX, cell, NULL, &x)); 673 for (PetscInt f = 0; f < Nf; ++f) { 674 PetscInt qc = 0; 675 676 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 677 PetscCall(PetscArrayzero(interpolant, Nc)); 678 PetscCall(PetscArrayzero(interpolantGrad, cdim * Nc)); 679 for (PetscInt q = 0; q < Nq; ++q) { 680 PetscCall(PetscFEInterpolateFieldAndGradient_Static((PetscFE)obj, 1, x, &fegeom, q, interpolant, interpolantGrad)); 681 for (PetscInt fc = 0; fc < Nc; ++fc) { 682 const PetscReal wt = quadWeights[q * qNc + qc + fc]; 683 684 field[fc] += interpolant[fc] * wt * fegeom.detJ[q]; 685 for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] += interpolantGrad[fc * dim + d] * wt * fegeom.detJ[q]; 686 } 687 } 688 qc += Nc; 689 } 690 PetscCall(PetscFree2(interpolant, interpolantGrad)); 691 PetscCall(DMPlexVecRestoreClosure(plex, NULL, locX, cell, NULL, &x)); 692 for (PetscInt fc = 0; fc < Nc; ++fc) { 693 field[fc] /= cg.volume; 694 for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] /= cg.volume; 695 } 696 PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, field, gradient, &cg, &errInd, ctx); 697 PetscCall(PetscFree6(field, gradient, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 698 } 699 PetscCall(DMPlexPointGlobalRef(eplex, cell, earray, (void *)&eval)); 700 eval[0] = errInd; 701 minMaxInd[0] = PetscMin(minMaxInd[0], errInd); 702 minMaxInd[1] = PetscMax(minMaxInd[1], errInd); 703 } 704 PetscCall(VecRestoreArray(errVec, &earray)); 705 PetscCall(DMDestroy(&plex)); 706 PetscCall(DMDestroy(&eplex)); 707 PetscCall(PetscGlobalMinMaxReal(PetscObjectComm((PetscObject)adaptor), minMaxInd, minMaxIndGlobal)); 708 PetscCall(PetscInfo(adaptor, "DMAdaptor: error indicator range (%g, %g)\n", (double)minMaxIndGlobal[0], (double)minMaxIndGlobal[1])); 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 static PetscErrorCode DMAdaptorComputeErrorIndicator_Flux(DMAdaptor adaptor, Vec lu, Vec errVec) 713 { 714 DM dm, mdm; 715 SNES msnes; 716 Vec mu, lmu; 717 void *ctx; 718 719 PetscFunctionBegin; 720 PetscCall(VecGetDM(lu, &dm)); 721 722 // Set up and solve mixed problem 723 PetscCall(DMClone(dm, &mdm)); 724 PetscCall(SNESCreate(PetscObjectComm((PetscObject)mdm), &msnes)); 725 PetscCall(SNESSetDM(msnes, mdm)); 726 PetscCall(SNESAppendOptionsPrefix(msnes, "mixed_")); 727 728 PetscTryTypeMethod(adaptor, mixedsetup, mdm); 729 PetscCall(DMGetApplicationContext(dm, &ctx)); 730 PetscCall(DMPlexSetSNESLocalFEM(mdm, PETSC_FALSE, ctx)); 731 PetscCall(SNESSetFromOptions(msnes)); 732 733 PetscCall(DMCreateGlobalVector(mdm, &mu)); 734 PetscCall(PetscObjectSetName((PetscObject)mu, "Mixed Solution")); 735 PetscCall(VecSet(mu, 0.0)); 736 PetscCall(SNESSolve(msnes, NULL, mu)); 737 PetscCall(VecViewFromOptions(mu, (PetscObject)adaptor, "-adapt_mixed_sol_vec_view")); 738 739 PetscCall(DMGetLocalVector(mdm, &lmu)); 740 PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu)); 741 PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL)); 742 PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, 0, lmu, 0, errVec)); 743 PetscCall(DMRestoreLocalVector(mdm, &lmu)); 744 PetscCall(VecDestroy(&mu)); 745 PetscCall(SNESDestroy(&msnes)); 746 PetscCall(DMDestroy(&mdm)); 747 PetscFunctionReturn(PETSC_SUCCESS); 748 } 749 750 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[]) 751 { 752 PetscInt i, j; 753 754 for (i = 0; i < dim; ++i) { 755 for (j = 0; j < dim; ++j) f[i + dim * j] = u[i + dim * j]; 756 } 757 } 758 759 static PetscErrorCode DMAdaptorAdapt_Sequence_Private(DMAdaptor adaptor, Vec inx, PetscBool doSolve, DM *adm, Vec *ax) 760 { 761 PetscDS ds; 762 void *ctx; 763 MPI_Comm comm; 764 PetscInt numAdapt = adaptor->numSeq, adaptIter; 765 PetscInt dim, coordDim, Nf; 766 767 PetscFunctionBegin; 768 PetscCall(DMViewFromOptions(adaptor->idm, NULL, "-dm_adapt_pre_view")); 769 PetscCall(VecViewFromOptions(inx, NULL, "-sol_adapt_pre_view")); 770 PetscCall(PetscObjectGetComm((PetscObject)adaptor, &comm)); 771 PetscCall(DMGetDimension(adaptor->idm, &dim)); 772 PetscCall(DMGetCoordinateDim(adaptor->idm, &coordDim)); 773 PetscCall(DMGetApplicationContext(adaptor->idm, &ctx)); 774 PetscCall(DMGetDS(adaptor->idm, &ds)); 775 PetscCall(PetscDSGetNumFields(ds, &Nf)); 776 PetscCheck(Nf != 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot refine with no fields present!"); 777 778 /* Adapt until nothing changes */ 779 /* Adapt for a specified number of iterates */ 780 for (adaptIter = 0; adaptIter < numAdapt - 1; ++adaptIter) PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_(comm))); 781 for (adaptIter = 0; adaptIter < numAdapt; ++adaptIter) { 782 PetscBool adapted = PETSC_FALSE; 783 DM dm = adaptIter ? *adm : adaptor->idm, odm; 784 Vec x = adaptIter ? *ax : inx, locX, ox; 785 786 PetscCall(DMGetLocalVector(dm, &locX)); 787 PetscCall(DMAdaptorPreAdapt(adaptor, locX)); 788 if (doSolve) { 789 SNES snes; 790 791 PetscCall(DMAdaptorGetSolver(adaptor, &snes)); 792 PetscCall(SNESSolve(snes, NULL, adaptIter ? *ax : x)); 793 } 794 PetscCall(DMGlobalToLocalBegin(dm, adaptIter ? *ax : x, INSERT_VALUES, locX)); 795 PetscCall(DMGlobalToLocalEnd(dm, adaptIter ? *ax : x, INSERT_VALUES, locX)); 796 PetscCall(VecViewFromOptions(adaptIter ? *ax : x, (PetscObject)adaptor, "-adapt_primal_sol_vec_view")); 797 /* PetscCall(DMAdaptorMonitor(adaptor)); 798 Print iterate, memory used, DM, solution */ 799 switch (adaptor->adaptCriterion) { 800 case DM_ADAPTATION_REFINE: 801 PetscCall(DMRefine(dm, comm, &odm)); 802 PetscCheck(odm, comm, PETSC_ERR_ARG_INCOMP, "DMRefine() did not perform any refinement, cannot continue grid sequencing"); 803 adapted = PETSC_TRUE; 804 break; 805 case DM_ADAPTATION_LABEL: { 806 /* Adapt DM 807 Create local solution 808 Reconstruct gradients (FVM) or solve adjoint equation (FEM) 809 Produce cellwise error indicator */ 810 DM edm, plex; 811 PetscFE efe; 812 DMLabel adaptLabel; 813 IS refineIS, coarsenIS; 814 Vec errVec; 815 DMPolytopeType ct; 816 PetscInt nRefine, nCoarsen, cStart; 817 818 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "adapt", &adaptLabel)); 819 820 // TODO Move this creation to PreAdapt 821 PetscCall(DMClone(dm, &edm)); 822 PetscCall(DMConvert(edm, DMPLEX, &plex)); 823 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 824 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 825 PetscCall(DMDestroy(&plex)); 826 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, 0, PETSC_DEFAULT, &efe)); 827 PetscCall(PetscObjectSetName((PetscObject)efe, "Error")); 828 PetscCall(DMSetField(edm, 0, NULL, (PetscObject)efe)); 829 PetscCall(PetscFEDestroy(&efe)); 830 PetscCall(DMCreateDS(edm)); 831 PetscCall(DMGetGlobalVector(edm, &errVec)); 832 PetscCall(PetscObjectSetName((PetscObject)errVec, "Error Estimator")); 833 834 PetscUseTypeMethod(adaptor, computeerrorindicator, locX, errVec); 835 PetscCall(VecViewFromOptions(errVec, (PetscObject)adaptor, "-adapt_error_vec_view")); 836 837 // Compute IS from VecTagger 838 PetscCall(VecTaggerComputeIS(adaptor->refineTag, errVec, &refineIS, NULL)); 839 PetscCall(VecTaggerComputeIS(adaptor->coarsenTag, errVec, &coarsenIS, NULL)); 840 PetscCall(ISViewFromOptions(refineIS, (PetscObject)adaptor->refineTag, "-is_view")); 841 PetscCall(ISViewFromOptions(coarsenIS, (PetscObject)adaptor->coarsenTag, "-is_view")); 842 PetscCall(ISGetSize(refineIS, &nRefine)); 843 PetscCall(ISGetSize(coarsenIS, &nCoarsen)); 844 PetscCall(PetscInfo(adaptor, "DMAdaptor: numRefine %" PetscInt_FMT ", numCoarsen %" PetscInt_FMT "\n", nRefine, nCoarsen)); 845 if (nRefine) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE, refineIS)); 846 if (nCoarsen) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_COARSEN, coarsenIS)); 847 PetscCall(ISDestroy(&coarsenIS)); 848 PetscCall(ISDestroy(&refineIS)); 849 PetscCall(DMRestoreGlobalVector(edm, &errVec)); 850 PetscCall(DMDestroy(&edm)); 851 // Adapt DM from label 852 if (nRefine || nCoarsen) { 853 char oprefix[PETSC_MAX_PATH_LEN]; 854 const char *p; 855 PetscBool flg; 856 857 PetscCall(PetscOptionsHasName(NULL, adaptor->hdr.prefix, "-adapt_vec_view", &flg)); 858 if (flg) { 859 Vec ref; 860 861 PetscCall(DMPlexCreateLabelField(dm, adaptLabel, &ref)); 862 PetscCall(VecViewFromOptions(ref, (PetscObject)adaptor, "-adapt_vec_view")); 863 PetscCall(VecDestroy(&ref)); 864 } 865 866 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &p)); 867 PetscCall(PetscStrncpy(oprefix, p, PETSC_MAX_PATH_LEN)); 868 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "adapt_")); 869 PetscCall(DMAdaptLabel(dm, adaptLabel, &odm)); 870 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oprefix)); 871 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)odm, oprefix)); 872 adapted = PETSC_TRUE; 873 } 874 PetscCall(DMLabelDestroy(&adaptLabel)); 875 } break; 876 case DM_ADAPTATION_METRIC: { 877 DM dmGrad, dmHess, dmMetric, dmDet; 878 Vec xGrad, xHess, metric, determinant; 879 PetscReal N; 880 DMLabel bdLabel = NULL, rgLabel = NULL; 881 PetscBool higherOrder = PETSC_FALSE; 882 PetscInt Nd = coordDim * coordDim, f, vStart, vEnd; 883 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[]); 884 885 PetscCall(PetscMalloc(1, &funcs)); 886 funcs[0] = identityFunc; 887 888 /* Setup finite element spaces */ 889 PetscCall(DMClone(dm, &dmGrad)); 890 PetscCall(DMClone(dm, &dmHess)); 891 PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple fields not yet considered"); // TODO 892 for (f = 0; f < Nf; ++f) { 893 PetscFE fe, feGrad, feHess; 894 PetscDualSpace Q; 895 PetscSpace space; 896 DM K; 897 PetscQuadrature q; 898 PetscInt Nc, qorder, p; 899 const char *prefix; 900 901 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 902 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 903 PetscCheck(Nc <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple components not yet considered"); // TODO 904 PetscCall(PetscFEGetBasisSpace(fe, &space)); 905 PetscCall(PetscSpaceGetDegree(space, NULL, &p)); 906 if (p > 1) higherOrder = PETSC_TRUE; 907 PetscCall(PetscFEGetDualSpace(fe, &Q)); 908 PetscCall(PetscDualSpaceGetDM(Q, &K)); 909 PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd)); 910 PetscCall(PetscFEGetQuadrature(fe, &q)); 911 PetscCall(PetscQuadratureGetOrder(q, &qorder)); 912 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)fe, &prefix)); 913 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmGrad), dim, Nc * coordDim, PETSC_TRUE, prefix, qorder, &feGrad)); 914 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmHess), dim, Nc * Nd, PETSC_TRUE, prefix, qorder, &feHess)); 915 PetscCall(DMSetField(dmGrad, f, NULL, (PetscObject)feGrad)); 916 PetscCall(DMSetField(dmHess, f, NULL, (PetscObject)feHess)); 917 PetscCall(DMCreateDS(dmGrad)); 918 PetscCall(DMCreateDS(dmHess)); 919 PetscCall(PetscFEDestroy(&feGrad)); 920 PetscCall(PetscFEDestroy(&feHess)); 921 } 922 /* Compute vertexwise gradients from cellwise gradients */ 923 PetscCall(DMCreateLocalVector(dmGrad, &xGrad)); 924 PetscCall(VecViewFromOptions(locX, NULL, "-sol_adapt_loc_pre_view")); 925 PetscCall(DMPlexComputeGradientClementInterpolant(dm, locX, xGrad)); 926 PetscCall(VecViewFromOptions(xGrad, NULL, "-adapt_gradient_view")); 927 /* Compute vertexwise Hessians from cellwise Hessians */ 928 PetscCall(DMCreateLocalVector(dmHess, &xHess)); 929 PetscCall(DMPlexComputeGradientClementInterpolant(dmGrad, xGrad, xHess)); 930 PetscCall(VecViewFromOptions(xHess, NULL, "-adapt_hessian_view")); 931 PetscCall(VecDestroy(&xGrad)); 932 PetscCall(DMDestroy(&dmGrad)); 933 /* Compute L-p normalized metric */ 934 PetscCall(DMClone(dm, &dmMetric)); 935 N = adaptor->Nadapt >= 0 ? adaptor->Nadapt : PetscPowRealInt(adaptor->refinementFactor, dim) * ((PetscReal)(vEnd - vStart)); 936 if (adaptor->monitor) { 937 PetscMPIInt rank, size; 938 PetscCallMPI(MPI_Comm_rank(comm, &size)); 939 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 940 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] N_orig: %" PetscInt_FMT " N_adapt: %g\n", rank, vEnd - vStart, (double)N)); 941 } 942 PetscCall(DMPlexMetricSetTargetComplexity(dmMetric, (PetscReal)N)); 943 if (higherOrder) { 944 /* Project Hessian into P1 space, if required */ 945 PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric)); 946 PetscCall(DMProjectFieldLocal(dmMetric, 0.0, xHess, funcs, INSERT_ALL_VALUES, metric)); 947 PetscCall(VecDestroy(&xHess)); 948 xHess = metric; 949 } 950 PetscCall(PetscFree(funcs)); 951 PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric)); 952 PetscCall(DMPlexMetricDeterminantCreate(dmMetric, 0, &determinant, &dmDet)); 953 PetscCall(DMPlexMetricNormalize(dmMetric, xHess, PETSC_TRUE, PETSC_TRUE, metric, determinant)); 954 PetscCall(VecDestroy(&determinant)); 955 PetscCall(DMDestroy(&dmDet)); 956 PetscCall(VecDestroy(&xHess)); 957 PetscCall(DMDestroy(&dmHess)); 958 /* Adapt DM from metric */ 959 PetscCall(DMGetLabel(dm, "marker", &bdLabel)); 960 PetscCall(DMAdaptMetric(dm, metric, bdLabel, rgLabel, &odm)); 961 adapted = PETSC_TRUE; 962 /* Cleanup */ 963 PetscCall(VecDestroy(&metric)); 964 PetscCall(DMDestroy(&dmMetric)); 965 } break; 966 default: 967 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid adaptation type: %d", adaptor->adaptCriterion); 968 } 969 PetscCall(DMAdaptorPostAdapt(adaptor)); 970 PetscCall(DMRestoreLocalVector(dm, &locX)); 971 /* If DM was adapted, replace objects and recreate solution */ 972 if (adapted) { 973 const char *name; 974 975 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 976 PetscCall(PetscObjectSetName((PetscObject)odm, name)); 977 /* Reconfigure solver */ 978 PetscCall(SNESReset(adaptor->snes)); 979 PetscCall(SNESSetDM(adaptor->snes, odm)); 980 PetscCall(DMAdaptorSetSolver(adaptor, adaptor->snes)); 981 PetscCall(DMPlexSetSNESLocalFEM(odm, PETSC_FALSE, ctx)); 982 PetscCall(SNESSetFromOptions(adaptor->snes)); 983 /* Transfer system */ 984 PetscCall(DMCopyDisc(dm, odm)); 985 /* Transfer solution */ 986 PetscCall(DMCreateGlobalVector(odm, &ox)); 987 PetscCall(PetscObjectGetName((PetscObject)x, &name)); 988 PetscCall(PetscObjectSetName((PetscObject)ox, name)); 989 PetscCall(DMAdaptorTransferSolution(adaptor, dm, x, odm, ox)); 990 /* Cleanup adaptivity info */ 991 if (adaptIter > 0) PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_(comm))); 992 PetscCall(DMForestSetAdaptivityForest(dm, NULL)); /* clear internal references to the previous dm */ 993 PetscCall(DMDestroy(&dm)); 994 PetscCall(VecDestroy(&x)); 995 *adm = odm; 996 *ax = ox; 997 } else { 998 *adm = dm; 999 *ax = x; 1000 adaptIter = numAdapt; 1001 } 1002 if (adaptIter < numAdapt - 1) { 1003 PetscCall(DMViewFromOptions(odm, NULL, "-dm_adapt_iter_view")); 1004 PetscCall(VecViewFromOptions(ox, NULL, "-sol_adapt_iter_view")); 1005 } 1006 } 1007 PetscCall(DMViewFromOptions(*adm, NULL, "-dm_adapt_view")); 1008 PetscCall(VecViewFromOptions(*ax, NULL, "-sol_adapt_view")); 1009 PetscFunctionReturn(PETSC_SUCCESS); 1010 } 1011 1012 /*@ 1013 DMAdaptorAdapt - Creates a new `DM` that is adapted to the problem 1014 1015 Not Collective 1016 1017 Input Parameters: 1018 + adaptor - The `DMAdaptor` object 1019 . x - The global approximate solution 1020 - strategy - The adaptation strategy, see `DMAdaptationStrategy` 1021 1022 Output Parameters: 1023 + adm - The adapted `DM` 1024 - ax - The adapted solution 1025 1026 Options Database Keys: 1027 + -snes_adapt <strategy> - initial, sequential, multigrid 1028 . -adapt_gradient_view - View the Clement interpolant of the solution gradient 1029 . -adapt_hessian_view - View the Clement interpolant of the solution Hessian 1030 - -adapt_metric_view - View the metric tensor for adaptive mesh refinement 1031 1032 Level: intermediate 1033 1034 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptationStrategy`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()` 1035 @*/ 1036 PetscErrorCode DMAdaptorAdapt(DMAdaptor adaptor, Vec x, DMAdaptationStrategy strategy, DM *adm, Vec *ax) 1037 { 1038 PetscFunctionBegin; 1039 switch (strategy) { 1040 case DM_ADAPTATION_INITIAL: 1041 PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_FALSE, adm, ax)); 1042 break; 1043 case DM_ADAPTATION_SEQUENTIAL: 1044 PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_TRUE, adm, ax)); 1045 break; 1046 default: 1047 SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Unrecognized adaptation strategy %d", strategy); 1048 } 1049 PetscFunctionReturn(PETSC_SUCCESS); 1050 } 1051 1052 /*@C 1053 DMAdaptorGetMixedSetupFunction - Get the function setting up the mixed problem, if it exists 1054 1055 Not Collective 1056 1057 Input Parameter: 1058 . adaptor - the `DMAdaptor` 1059 1060 Output Parameter: 1061 . setupFunc - the function setting up the mixed problem, or `NULL` 1062 1063 Level: advanced 1064 1065 .seealso: `DMAdaptor`, `DMAdaptorSetMixedSetupFunction()`, `DMAdaptorAdapt()` 1066 @*/ 1067 PetscErrorCode DMAdaptorGetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (**setupFunc)(DMAdaptor, DM)) 1068 { 1069 PetscFunctionBegin; 1070 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1071 PetscAssertPointer(setupFunc, 2); 1072 *setupFunc = adaptor->ops->mixedsetup; 1073 PetscFunctionReturn(PETSC_SUCCESS); 1074 } 1075 1076 /*@C 1077 DMAdaptorSetMixedSetupFunction - Set the function setting up the mixed problem 1078 1079 Not Collective 1080 1081 Input Parameters: 1082 + adaptor - the `DMAdaptor` 1083 - setupFunc - the function setting up the mixed problem 1084 1085 Level: advanced 1086 1087 .seealso: `DMAdaptor`, `DMAdaptorGetMixedSetupFunction()`, `DMAdaptorAdapt()` 1088 @*/ 1089 PetscErrorCode DMAdaptorSetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (*setupFunc)(DMAdaptor, DM)) 1090 { 1091 PetscFunctionBegin; 1092 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1093 PetscValidFunction(setupFunc, 2); 1094 adaptor->ops->mixedsetup = setupFunc; 1095 PetscFunctionReturn(PETSC_SUCCESS); 1096 } 1097 1098 static PetscErrorCode DMAdaptorInitialize_Gradient(DMAdaptor adaptor) 1099 { 1100 PetscFunctionBegin; 1101 adaptor->ops->computeerrorindicator = DMAdaptorComputeErrorIndicator_Gradient; 1102 adaptor->ops->computecellerrorindicator = DMAdaptorComputeCellErrorIndicator_Gradient; 1103 PetscFunctionReturn(PETSC_SUCCESS); 1104 } 1105 1106 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor adaptor) 1107 { 1108 PetscFunctionBegin; 1109 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1110 adaptor->data = NULL; 1111 1112 PetscCall(DMAdaptorInitialize_Gradient(adaptor)); 1113 PetscFunctionReturn(PETSC_SUCCESS); 1114 } 1115 1116 static PetscErrorCode DMAdaptorInitialize_Flux(DMAdaptor adaptor) 1117 { 1118 PetscFunctionBegin; 1119 adaptor->ops->computeerrorindicator = DMAdaptorComputeErrorIndicator_Flux; 1120 PetscFunctionReturn(PETSC_SUCCESS); 1121 } 1122 1123 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor adaptor) 1124 { 1125 PetscFunctionBegin; 1126 PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1); 1127 adaptor->data = NULL; 1128 1129 PetscCall(DMAdaptorInitialize_Flux(adaptor)); 1130 PetscFunctionReturn(PETSC_SUCCESS); 1131 } 1132