1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petscblaslapack.h> 3 4 PetscLogEvent DMPLEX_MetricEnforceSPD, DMPLEX_MetricNormalize, DMPLEX_MetricAverage, DMPLEX_MetricIntersection; 5 6 PetscErrorCode DMPlexMetricSetFromOptions(DM dm) 7 { 8 DM_Plex *plex = (DM_Plex *)dm->data; 9 MPI_Comm comm; 10 PetscBool isotropic = PETSC_FALSE, uniform = PETSC_FALSE, restrictAnisotropyFirst = PETSC_FALSE; 11 PetscBool noInsert = PETSC_FALSE, noSwap = PETSC_FALSE, noMove = PETSC_FALSE, noSurf = PETSC_FALSE; 12 PetscInt verbosity = -1, numIter = 3; 13 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 1.0e+05, p = 1.0, target = 1000.0, beta = 1.3, hausd = 0.01; 14 15 PetscFunctionBegin; 16 if (!plex->metricCtx) PetscCall(PetscNew(&plex->metricCtx)); 17 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 18 PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric"); 19 PetscCall(PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL)); 20 PetscCall(DMPlexMetricSetIsotropic(dm, isotropic)); 21 PetscCall(PetscOptionsBool("-dm_plex_metric_uniform", "Is the metric uniform?", "DMPlexMetricCreateUniform", uniform, &uniform, NULL)); 22 PetscCall(DMPlexMetricSetUniform(dm, uniform)); 23 PetscCall(PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL)); 24 PetscCall(DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst)); 25 PetscCall(PetscOptionsBool("-dm_plex_metric_no_insert", "Turn off node insertion and deletion", "DMAdaptMetric", noInsert, &noInsert, NULL)); 26 PetscCall(DMPlexMetricSetNoInsertion(dm, noInsert)); 27 PetscCall(PetscOptionsBool("-dm_plex_metric_no_swap", "Turn off facet swapping", "DMAdaptMetric", noSwap, &noSwap, NULL)); 28 PetscCall(DMPlexMetricSetNoSwapping(dm, noSwap)); 29 PetscCall(PetscOptionsBool("-dm_plex_metric_no_move", "Turn off facet node movement", "DMAdaptMetric", noMove, &noMove, NULL)); 30 PetscCall(DMPlexMetricSetNoMovement(dm, noMove)); 31 PetscCall(PetscOptionsBool("-dm_plex_metric_no_surf", "Turn off surface modification", "DMAdaptMetric", noSurf, &noSurf, NULL)); 32 PetscCall(DMPlexMetricSetNoSurf(dm, noSurf)); 33 PetscCall(PetscOptionsBoundedInt("-dm_plex_metric_num_iterations", "Number of ParMmg adaptation iterations", "DMAdaptMetric", numIter, &numIter, NULL, 0)); 34 PetscCall(DMPlexMetricSetNumIterations(dm, numIter)); 35 PetscCall(PetscOptionsRangeInt("-dm_plex_metric_verbosity", "Verbosity of metric-based mesh adaptation package (-1 = silent, 10 = maximum)", "DMAdaptMetric", verbosity, &verbosity, NULL, -1, 10)); 36 PetscCall(DMPlexMetricSetVerbosity(dm, verbosity)); 37 PetscCall(PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL)); 38 PetscCall(DMPlexMetricSetMinimumMagnitude(dm, h_min)); 39 PetscCall(PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL)); 40 PetscCall(DMPlexMetricSetMaximumMagnitude(dm, h_max)); 41 PetscCall(PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL)); 42 PetscCall(DMPlexMetricSetMaximumAnisotropy(dm, a_max)); 43 PetscCall(PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL)); 44 PetscCall(DMPlexMetricSetNormalizationOrder(dm, p)); 45 PetscCall(PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL)); 46 PetscCall(DMPlexMetricSetTargetComplexity(dm, target)); 47 PetscCall(PetscOptionsReal("-dm_plex_metric_gradation_factor", "Metric gradation factor", "DMAdaptMetric", beta, &beta, NULL)); 48 PetscCall(DMPlexMetricSetGradationFactor(dm, beta)); 49 PetscCall(PetscOptionsReal("-dm_plex_metric_hausdorff_number", "Metric Hausdorff number", "DMAdaptMetric", hausd, &hausd, NULL)); 50 PetscCall(DMPlexMetricSetHausdorffNumber(dm, hausd)); 51 PetscOptionsEnd(); 52 PetscFunctionReturn(PETSC_SUCCESS); 53 } 54 55 /*@ 56 DMPlexMetricSetIsotropic - Record whether a metric is isotropic 57 58 Input Parameters: 59 + dm - The `DM` 60 - isotropic - Is the metric isotropic? 61 62 Level: beginner 63 64 .seealso: `DMPLEX`, `DMPlexMetricIsIsotropic()`, `DMPlexMetricSetUniform()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 65 @*/ 66 PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic) 67 { 68 DM_Plex *plex = (DM_Plex *)dm->data; 69 70 PetscFunctionBegin; 71 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 72 plex->metricCtx->isotropic = isotropic; 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 76 /*@ 77 DMPlexMetricIsIsotropic - Is a metric isotropic? 78 79 Input Parameters: 80 . dm - The `DM` 81 82 Output Parameters: 83 . isotropic - Is the metric isotropic? 84 85 Level: beginner 86 87 .seealso: `DMPLEX`, `DMPlexMetricSetIsotropic()`, `DMPlexMetricIsUniform()`, `DMPlexMetricRestrictAnisotropyFirst()` 88 @*/ 89 PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic) 90 { 91 DM_Plex *plex = (DM_Plex *)dm->data; 92 93 PetscFunctionBegin; 94 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 95 *isotropic = plex->metricCtx->isotropic; 96 PetscFunctionReturn(PETSC_SUCCESS); 97 } 98 99 /*@ 100 DMPlexMetricSetUniform - Record whether a metric is uniform 101 102 Input Parameters: 103 + dm - The `DM` 104 - uniform - Is the metric uniform? 105 106 Level: beginner 107 108 Note: 109 If the metric is specified as uniform then it is assumed to be isotropic, too. 110 111 .seealso: `DMPLEX`, `DMPlexMetricIsUniform()`, `DMPlexMetricSetIsotropic()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 112 @*/ 113 PetscErrorCode DMPlexMetricSetUniform(DM dm, PetscBool uniform) 114 { 115 DM_Plex *plex = (DM_Plex *)dm->data; 116 117 PetscFunctionBegin; 118 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 119 plex->metricCtx->uniform = uniform; 120 if (uniform) plex->metricCtx->isotropic = uniform; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 /*@ 125 DMPlexMetricIsUniform - Is a metric uniform? 126 127 Input Parameters: 128 . dm - The `DM` 129 130 Output Parameters: 131 . uniform - Is the metric uniform? 132 133 Level: beginner 134 135 .seealso: `DMPLEX`, `DMPlexMetricSetUniform()`, `DMPlexMetricIsIsotropic()`, `DMPlexMetricRestrictAnisotropyFirst()` 136 @*/ 137 PetscErrorCode DMPlexMetricIsUniform(DM dm, PetscBool *uniform) 138 { 139 DM_Plex *plex = (DM_Plex *)dm->data; 140 141 PetscFunctionBegin; 142 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 143 *uniform = plex->metricCtx->uniform; 144 PetscFunctionReturn(PETSC_SUCCESS); 145 } 146 147 /*@ 148 DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization 149 150 Input Parameters: 151 + dm - The `DM` 152 - restrictAnisotropyFirst - Should anisotropy be normalized first? 153 154 Level: beginner 155 156 .seealso: `DMPLEX`, `DMPlexMetricSetIsotropic()`, `DMPlexMetricRestrictAnisotropyFirst()` 157 @*/ 158 PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst) 159 { 160 DM_Plex *plex = (DM_Plex *)dm->data; 161 162 PetscFunctionBegin; 163 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 164 plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst; 165 PetscFunctionReturn(PETSC_SUCCESS); 166 } 167 168 /*@ 169 DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after? 170 171 Input Parameters: 172 . dm - The `DM` 173 174 Output Parameters: 175 . restrictAnisotropyFirst - Is anisotropy be normalized first? 176 177 Level: beginner 178 179 .seealso: `DMPLEX`, `DMPlexMetricIsIsotropic()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 180 @*/ 181 PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst) 182 { 183 DM_Plex *plex = (DM_Plex *)dm->data; 184 185 PetscFunctionBegin; 186 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 187 *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst; 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 191 /*@ 192 DMPlexMetricSetNoInsertion - Should node insertion and deletion be turned off? 193 194 Input Parameters: 195 + dm - The `DM` 196 - noInsert - Should node insertion and deletion be turned off? 197 198 Level: beginner 199 200 Note: 201 This is only used by Mmg and ParMmg (not Pragmatic). 202 203 .seealso: `DMPLEX`, `DMPlexMetricNoInsertion()`, `DMPlexMetricSetNoSwapping()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoSurf()` 204 @*/ 205 PetscErrorCode DMPlexMetricSetNoInsertion(DM dm, PetscBool noInsert) 206 { 207 DM_Plex *plex = (DM_Plex *)dm->data; 208 209 PetscFunctionBegin; 210 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 211 plex->metricCtx->noInsert = noInsert; 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 /*@ 216 DMPlexMetricNoInsertion - Are node insertion and deletion turned off? 217 218 Input Parameters: 219 . dm - The `DM` 220 221 Output Parameters: 222 . noInsert - Are node insertion and deletion turned off? 223 224 Level: beginner 225 226 Note: 227 This is only used by Mmg and ParMmg (not Pragmatic). 228 229 .seealso: `DMPLEX`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricNoSwapping()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoSurf()` 230 @*/ 231 PetscErrorCode DMPlexMetricNoInsertion(DM dm, PetscBool *noInsert) 232 { 233 DM_Plex *plex = (DM_Plex *)dm->data; 234 235 PetscFunctionBegin; 236 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 237 *noInsert = plex->metricCtx->noInsert; 238 PetscFunctionReturn(PETSC_SUCCESS); 239 } 240 241 /*@ 242 DMPlexMetricSetNoSwapping - Should facet swapping be turned off? 243 244 Input Parameters: 245 + dm - The `DM` 246 - noSwap - Should facet swapping be turned off? 247 248 Level: beginner 249 250 Note: 251 This is only used by Mmg and ParMmg (not Pragmatic). 252 253 .seealso: `DMPLEX`, `DMPlexMetricNoSwapping()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoSurf()` 254 @*/ 255 PetscErrorCode DMPlexMetricSetNoSwapping(DM dm, PetscBool noSwap) 256 { 257 DM_Plex *plex = (DM_Plex *)dm->data; 258 259 PetscFunctionBegin; 260 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 261 plex->metricCtx->noSwap = noSwap; 262 PetscFunctionReturn(PETSC_SUCCESS); 263 } 264 265 /*@ 266 DMPlexMetricNoSwapping - Is facet swapping turned off? 267 268 Input Parameters: 269 . dm - The `DM` 270 271 Output Parameters: 272 . noSwap - Is facet swapping turned off? 273 274 Level: beginner 275 276 Note: 277 This is only used by Mmg and ParMmg (not Pragmatic). 278 279 .seealso: `DMPLEX`, `DMPlexMetricSetNoSwapping()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoSurf()` 280 @*/ 281 PetscErrorCode DMPlexMetricNoSwapping(DM dm, PetscBool *noSwap) 282 { 283 DM_Plex *plex = (DM_Plex *)dm->data; 284 285 PetscFunctionBegin; 286 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 287 *noSwap = plex->metricCtx->noSwap; 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 291 /*@ 292 DMPlexMetricSetNoMovement - Should node movement be turned off? 293 294 Input Parameters: 295 + dm - The `DM` 296 - noMove - Should node movement be turned off? 297 298 Level: beginner 299 300 Note: 301 This is only used by Mmg and ParMmg (not Pragmatic). 302 303 .seealso: `DMPLEX`, `DMPlexMetricNoMovement()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoSwapping()`, `DMPlexMetricSetNoSurf()` 304 @*/ 305 PetscErrorCode DMPlexMetricSetNoMovement(DM dm, PetscBool noMove) 306 { 307 DM_Plex *plex = (DM_Plex *)dm->data; 308 309 PetscFunctionBegin; 310 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 311 plex->metricCtx->noMove = noMove; 312 PetscFunctionReturn(PETSC_SUCCESS); 313 } 314 315 /*@ 316 DMPlexMetricNoMovement - Is node movement turned off? 317 318 Input Parameters: 319 . dm - The `DM` 320 321 Output Parameters: 322 . noMove - Is node movement turned off? 323 324 Level: beginner 325 326 Note: 327 This is only used by Mmg and ParMmg (not Pragmatic). 328 329 .seealso: `DMPLEX`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoSwapping()`, `DMPlexMetricNoSurf()` 330 @*/ 331 PetscErrorCode DMPlexMetricNoMovement(DM dm, PetscBool *noMove) 332 { 333 DM_Plex *plex = (DM_Plex *)dm->data; 334 335 PetscFunctionBegin; 336 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 337 *noMove = plex->metricCtx->noMove; 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 /*@ 342 DMPlexMetricSetNoSurf - Should surface modification be turned off? 343 344 Input Parameters: 345 + dm - The `DM` 346 - noSurf - Should surface modification be turned off? 347 348 Level: beginner 349 350 Note: 351 This is only used by Mmg and ParMmg (not Pragmatic). 352 353 .seealso: `DMPLEX`, `DMPlexMetricNoSurf()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoSwapping()` 354 @*/ 355 PetscErrorCode DMPlexMetricSetNoSurf(DM dm, PetscBool noSurf) 356 { 357 DM_Plex *plex = (DM_Plex *)dm->data; 358 359 PetscFunctionBegin; 360 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 361 plex->metricCtx->noSurf = noSurf; 362 PetscFunctionReturn(PETSC_SUCCESS); 363 } 364 365 /*@ 366 DMPlexMetricNoSurf - Is surface modification turned off? 367 368 Input Parameters: 369 . dm - The `DM` 370 371 Output Parameters: 372 . noSurf - Is surface modification turned off? 373 374 Level: beginner 375 376 Note: 377 This is only used by Mmg and ParMmg (not Pragmatic). 378 379 .seealso: `DMPLEX`, `DMPlexMetricSetNoSurf()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoSwapping()` 380 @*/ 381 PetscErrorCode DMPlexMetricNoSurf(DM dm, PetscBool *noSurf) 382 { 383 DM_Plex *plex = (DM_Plex *)dm->data; 384 385 PetscFunctionBegin; 386 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 387 *noSurf = plex->metricCtx->noSurf; 388 PetscFunctionReturn(PETSC_SUCCESS); 389 } 390 391 /*@ 392 DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude 393 394 Input Parameters: 395 + dm - The `DM` 396 - h_min - The minimum tolerated metric magnitude 397 398 Level: beginner 399 400 .seealso: `DMPLEX`, `DMPlexMetricGetMinimumMagnitude()`, `DMPlexMetricSetMaximumMagnitude()` 401 @*/ 402 PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min) 403 { 404 DM_Plex *plex = (DM_Plex *)dm->data; 405 406 PetscFunctionBegin; 407 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 408 PetscCheck(h_min > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric magnitudes must be in (0, inf)"); 409 plex->metricCtx->h_min = h_min; 410 PetscFunctionReturn(PETSC_SUCCESS); 411 } 412 413 /*@ 414 DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude 415 416 Input Parameters: 417 . dm - The `DM` 418 419 Output Parameters: 420 . h_min - The minimum tolerated metric magnitude 421 422 Level: beginner 423 424 .seealso: `DMPLEX`, `DMPlexMetricSetMinimumMagnitude()`, `DMPlexMetricGetMaximumMagnitude()` 425 @*/ 426 PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min) 427 { 428 DM_Plex *plex = (DM_Plex *)dm->data; 429 430 PetscFunctionBegin; 431 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 432 *h_min = plex->metricCtx->h_min; 433 PetscFunctionReturn(PETSC_SUCCESS); 434 } 435 436 /*@ 437 DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude 438 439 Input Parameters: 440 + dm - The `DM` 441 - h_max - The maximum tolerated metric magnitude 442 443 Level: beginner 444 445 .seealso: `DMPLEX`, `DMPlexMetricGetMaximumMagnitude()`, `DMPlexMetricSetMinimumMagnitude()` 446 @*/ 447 PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max) 448 { 449 DM_Plex *plex = (DM_Plex *)dm->data; 450 451 PetscFunctionBegin; 452 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 453 PetscCheck(h_max > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric magnitudes must be in (0, inf)"); 454 plex->metricCtx->h_max = h_max; 455 PetscFunctionReturn(PETSC_SUCCESS); 456 } 457 458 /*@ 459 DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude 460 461 Input Parameters: 462 . dm - The `DM` 463 464 Output Parameters: 465 . h_max - The maximum tolerated metric magnitude 466 467 Level: beginner 468 469 .seealso: `DMPLEX`, `DMPlexMetricSetMaximumMagnitude()`, `DMPlexMetricGetMinimumMagnitude()` 470 @*/ 471 PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max) 472 { 473 DM_Plex *plex = (DM_Plex *)dm->data; 474 475 PetscFunctionBegin; 476 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 477 *h_max = plex->metricCtx->h_max; 478 PetscFunctionReturn(PETSC_SUCCESS); 479 } 480 481 /*@ 482 DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy 483 484 Input Parameters: 485 + dm - The `DM` 486 - a_max - The maximum tolerated metric anisotropy 487 488 Level: beginner 489 490 Note: 491 If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one. 492 493 .seealso: `DMPLEX`, `DMPlexMetricGetMaximumAnisotropy()`, `DMPlexMetricSetMaximumMagnitude()` 494 @*/ 495 PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max) 496 { 497 DM_Plex *plex = (DM_Plex *)dm->data; 498 499 PetscFunctionBegin; 500 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 501 PetscCheck(a_max >= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Anisotropy must be in [1, inf)"); 502 plex->metricCtx->a_max = a_max; 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 /*@ 507 DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy 508 509 Input Parameters: 510 . dm - The `DM` 511 512 Output Parameters: 513 . a_max - The maximum tolerated metric anisotropy 514 515 Level: beginner 516 517 .seealso: `DMPLEX`, `DMPlexMetricSetMaximumAnisotropy()`, `DMPlexMetricGetMaximumMagnitude()` 518 @*/ 519 PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max) 520 { 521 DM_Plex *plex = (DM_Plex *)dm->data; 522 523 PetscFunctionBegin; 524 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 525 *a_max = plex->metricCtx->a_max; 526 PetscFunctionReturn(PETSC_SUCCESS); 527 } 528 529 /*@ 530 DMPlexMetricSetTargetComplexity - Set the target metric complexity 531 532 Input Parameters: 533 + dm - The `DM` 534 - targetComplexity - The target metric complexity 535 536 Level: beginner 537 538 .seealso: `DMPLEX`, `DMPlexMetricGetTargetComplexity()`, `DMPlexMetricSetNormalizationOrder()` 539 @*/ 540 PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity) 541 { 542 DM_Plex *plex = (DM_Plex *)dm->data; 543 544 PetscFunctionBegin; 545 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 546 PetscCheck(targetComplexity > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric complexity must be in (0, inf)"); 547 plex->metricCtx->targetComplexity = targetComplexity; 548 PetscFunctionReturn(PETSC_SUCCESS); 549 } 550 551 /*@ 552 DMPlexMetricGetTargetComplexity - Get the target metric complexity 553 554 Input Parameters: 555 . dm - The `DM` 556 557 Output Parameters: 558 . targetComplexity - The target metric complexity 559 560 Level: beginner 561 562 .seealso: `DMPLEX`, `DMPlexMetricSetTargetComplexity()`, `DMPlexMetricGetNormalizationOrder()` 563 @*/ 564 PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity) 565 { 566 DM_Plex *plex = (DM_Plex *)dm->data; 567 568 PetscFunctionBegin; 569 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 570 *targetComplexity = plex->metricCtx->targetComplexity; 571 PetscFunctionReturn(PETSC_SUCCESS); 572 } 573 574 /*@ 575 DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization 576 577 Input Parameters: 578 + dm - The `DM` 579 - p - The normalization order 580 581 Level: beginner 582 583 .seealso: `DMPLEX`, `DMPlexMetricGetNormalizationOrder()`, `DMPlexMetricSetTargetComplexity()` 584 @*/ 585 PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p) 586 { 587 DM_Plex *plex = (DM_Plex *)dm->data; 588 589 PetscFunctionBegin; 590 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 591 PetscCheck(p >= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Normalization order must be in [1, inf)"); 592 plex->metricCtx->p = p; 593 PetscFunctionReturn(PETSC_SUCCESS); 594 } 595 596 /*@ 597 DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization 598 599 Input Parameters: 600 . dm - The `DM` 601 602 Output Parameters: 603 . p - The normalization order 604 605 Level: beginner 606 607 .seealso: `DMPLEX`, `DMPlexMetricSetNormalizationOrder()`, `DMPlexMetricGetTargetComplexity()` 608 @*/ 609 PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p) 610 { 611 DM_Plex *plex = (DM_Plex *)dm->data; 612 613 PetscFunctionBegin; 614 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 615 *p = plex->metricCtx->p; 616 PetscFunctionReturn(PETSC_SUCCESS); 617 } 618 619 /*@ 620 DMPlexMetricSetGradationFactor - Set the metric gradation factor 621 622 Input Parameters: 623 + dm - The `DM` 624 - beta - The metric gradation factor 625 626 Level: beginner 627 628 Notes: 629 The gradation factor is the maximum tolerated length ratio between adjacent edges. 630 631 Turn off gradation by passing the value -1. Otherwise, pass a positive value. 632 633 This is only used by Mmg and ParMmg (not Pragmatic). 634 635 .seealso: `DMPLEX`, `DMPlexMetricGetGradationFactor()`, `DMPlexMetricSetHausdorffNumber()` 636 @*/ 637 PetscErrorCode DMPlexMetricSetGradationFactor(DM dm, PetscReal beta) 638 { 639 DM_Plex *plex = (DM_Plex *)dm->data; 640 641 PetscFunctionBegin; 642 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 643 PetscCheck(beta > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric gradation factor must be in (0, inf)"); 644 plex->metricCtx->gradationFactor = beta; 645 PetscFunctionReturn(PETSC_SUCCESS); 646 } 647 648 /*@ 649 DMPlexMetricGetGradationFactor - Get the metric gradation factor 650 651 Input Parameters: 652 . dm - The `DM` 653 654 Output Parameters: 655 . beta - The metric gradation factor 656 657 Level: beginner 658 659 Notes: 660 The gradation factor is the maximum tolerated length ratio between adjacent edges. 661 662 The value -1 implies that gradation is turned off. 663 664 This is only used by Mmg and ParMmg (not Pragmatic). 665 666 .seealso: `DMPLEX`, `DMPlexMetricSetGradationFactor()`, `DMPlexMetricGetHausdorffNumber()` 667 @*/ 668 PetscErrorCode DMPlexMetricGetGradationFactor(DM dm, PetscReal *beta) 669 { 670 DM_Plex *plex = (DM_Plex *)dm->data; 671 672 PetscFunctionBegin; 673 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 674 *beta = plex->metricCtx->gradationFactor; 675 PetscFunctionReturn(PETSC_SUCCESS); 676 } 677 678 /*@ 679 DMPlexMetricSetHausdorffNumber - Set the metric Hausdorff number 680 681 Input Parameters: 682 + dm - The `DM` 683 - hausd - The metric Hausdorff number 684 685 Level: beginner 686 687 Notes: 688 The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the 689 boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the 690 high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for 691 an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease 692 (resp. increase) the Hausdorff parameter. (Taken from 693 https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd). 694 695 This is only used by Mmg and ParMmg (not Pragmatic). 696 697 .seealso: `DMPLEX`, `DMPlexMetricSetGradationFactor()`, `DMPlexMetricGetHausdorffNumber()` 698 @*/ 699 PetscErrorCode DMPlexMetricSetHausdorffNumber(DM dm, PetscReal hausd) 700 { 701 DM_Plex *plex = (DM_Plex *)dm->data; 702 703 PetscFunctionBegin; 704 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 705 PetscCheck(hausd > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric Hausdorff number must be in (0, inf)"); 706 plex->metricCtx->hausdorffNumber = hausd; 707 PetscFunctionReturn(PETSC_SUCCESS); 708 } 709 710 /*@ 711 DMPlexMetricGetHausdorffNumber - Get the metric Hausdorff number 712 713 Input Parameters: 714 . dm - The `DM` 715 716 Output Parameters: 717 . hausd - The metric Hausdorff number 718 719 Level: beginner 720 721 Notes: 722 The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the 723 boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the 724 high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for 725 an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease 726 (resp. increase) the Hausdorff parameter. (Taken from 727 https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd). 728 729 This is only used by Mmg and ParMmg (not Pragmatic). 730 731 .seealso: `DMPLEX`, `DMPlexMetricGetGradationFactor()`, `DMPlexMetricSetHausdorffNumber()` 732 @*/ 733 PetscErrorCode DMPlexMetricGetHausdorffNumber(DM dm, PetscReal *hausd) 734 { 735 DM_Plex *plex = (DM_Plex *)dm->data; 736 737 PetscFunctionBegin; 738 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 739 *hausd = plex->metricCtx->hausdorffNumber; 740 PetscFunctionReturn(PETSC_SUCCESS); 741 } 742 743 /*@ 744 DMPlexMetricSetVerbosity - Set the verbosity of the mesh adaptation package 745 746 Input Parameters: 747 + dm - The `DM` 748 - verbosity - The verbosity, where -1 is silent and 10 is maximum 749 750 Level: beginner 751 752 Note: 753 This is only used by Mmg and ParMmg (not Pragmatic). 754 755 .seealso: `DMPLEX`, `DMPlexMetricGetVerbosity()`, `DMPlexMetricSetNumIterations()` 756 @*/ 757 PetscErrorCode DMPlexMetricSetVerbosity(DM dm, PetscInt verbosity) 758 { 759 DM_Plex *plex = (DM_Plex *)dm->data; 760 761 PetscFunctionBegin; 762 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 763 plex->metricCtx->verbosity = verbosity; 764 PetscFunctionReturn(PETSC_SUCCESS); 765 } 766 767 /*@ 768 DMPlexMetricGetVerbosity - Get the verbosity of the mesh adaptation package 769 770 Input Parameters: 771 . dm - The `DM` 772 773 Output Parameters: 774 . verbosity - The verbosity, where -1 is silent and 10 is maximum 775 776 Level: beginner 777 778 Note: 779 This is only used by Mmg and ParMmg (not Pragmatic). 780 781 .seealso: `DMPLEX`, `DMPlexMetricSetVerbosity()`, `DMPlexMetricGetNumIterations()` 782 @*/ 783 PetscErrorCode DMPlexMetricGetVerbosity(DM dm, PetscInt *verbosity) 784 { 785 DM_Plex *plex = (DM_Plex *)dm->data; 786 787 PetscFunctionBegin; 788 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 789 *verbosity = plex->metricCtx->verbosity; 790 PetscFunctionReturn(PETSC_SUCCESS); 791 } 792 793 /*@ 794 DMPlexMetricSetNumIterations - Set the number of parallel adaptation iterations 795 796 Input Parameters: 797 + dm - The `DM` 798 - numIter - the number of parallel adaptation iterations 799 800 Level: beginner 801 802 Note: 803 This is only used by ParMmg (not Pragmatic or Mmg). 804 805 .seealso: `DMPLEX`, `DMPlexMetricSetVerbosity()`, `DMPlexMetricGetNumIterations()` 806 @*/ 807 PetscErrorCode DMPlexMetricSetNumIterations(DM dm, PetscInt numIter) 808 { 809 DM_Plex *plex = (DM_Plex *)dm->data; 810 811 PetscFunctionBegin; 812 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 813 plex->metricCtx->numIter = numIter; 814 PetscFunctionReturn(PETSC_SUCCESS); 815 } 816 817 /*@ 818 DMPlexMetricGetNumIterations - Get the number of parallel adaptation iterations 819 820 Input Parameters: 821 . dm - The `DM` 822 823 Output Parameters: 824 . numIter - the number of parallel adaptation iterations 825 826 Level: beginner 827 828 Note: 829 This is only used by Mmg and ParMmg (not Pragmatic or Mmg). 830 831 .seealso: `DMPLEX`, `DMPlexMetricSetNumIterations()`, `DMPlexMetricGetVerbosity()` 832 @*/ 833 PetscErrorCode DMPlexMetricGetNumIterations(DM dm, PetscInt *numIter) 834 { 835 DM_Plex *plex = (DM_Plex *)dm->data; 836 837 PetscFunctionBegin; 838 if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 839 *numIter = plex->metricCtx->numIter; 840 PetscFunctionReturn(PETSC_SUCCESS); 841 } 842 843 static PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric) 844 { 845 MPI_Comm comm; 846 PetscFE fe; 847 PetscInt dim; 848 849 PetscFunctionBegin; 850 /* Extract metadata from dm */ 851 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 852 PetscCall(DMGetDimension(dm, &dim)); 853 854 /* Create a P1 field of the requested size */ 855 PetscCall(PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe)); 856 PetscCall(DMSetField(dm, f, NULL, (PetscObject)fe)); 857 PetscCall(DMCreateDS(dm)); 858 PetscCall(PetscFEDestroy(&fe)); 859 PetscCall(DMCreateLocalVector(dm, metric)); 860 PetscFunctionReturn(PETSC_SUCCESS); 861 } 862 863 /*@ 864 DMPlexMetricCreate - Create a Riemannian metric field 865 866 Input Parameters: 867 + dm - The `DM` 868 - f - The field number to use 869 870 Output Parameter: 871 . metric - The metric 872 873 Options Database Key: 874 . -dm_adaptor <pragmatic/mmg/parmmg> - specify dm adaptor to use 875 876 Options Database Keys for Mmg and ParMmg: 877 + -dm_plex_metric_gradation_factor - Maximum ratio by which edge lengths may grow during gradation 878 . -dm_plex_metric_num_iterations - Number of parallel mesh adaptation iterations for ParMmg 879 . -dm_plex_metric_no_insert - Should node insertion/deletion be turned off? 880 . -dm_plex_metric_no_swap - Should facet swapping be turned off? 881 . -dm_plex_metric_no_move - Should node movement be turned off? 882 - -dm_plex_metric_verbosity - Choose a verbosity level from -1 (silent) to 10 (maximum). 883 884 Options Database Keys for Riemannian metrics: 885 + -dm_plex_metric_isotropic - Is the metric isotropic? 886 . -dm_plex_metric_uniform - Is the metric uniform? 887 . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 888 . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 889 . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 890 . -dm_plex_metric_a_max - Maximum tolerated anisotropy 891 . -dm_plex_metric_p - L-p normalization order 892 - -dm_plex_metric_target_complexity - Target metric complexity 893 894 Level: beginner 895 896 Note: 897 It is assumed that the `DM` is comprised of simplices. 898 899 .seealso: `DMPLEX`, `DMPlexMetricCreateUniform()`, `DMPlexMetricCreateIsotropic()` 900 @*/ 901 PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric) 902 { 903 PetscBool isotropic, uniform; 904 PetscInt coordDim, Nd; 905 906 PetscFunctionBegin; 907 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 908 Nd = coordDim * coordDim; 909 PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 910 PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 911 if (uniform) { 912 MPI_Comm comm; 913 914 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 915 PetscCheck(isotropic, comm, PETSC_ERR_SUP, "Uniform anisotropic metrics not supported"); 916 PetscCall(VecCreate(comm, metric)); 917 PetscCall(VecSetSizes(*metric, 1, PETSC_DECIDE)); 918 PetscCall(VecSetFromOptions(*metric)); 919 } else if (isotropic) PetscCall(DMPlexP1FieldCreate_Private(dm, f, 1, metric)); 920 else PetscCall(DMPlexP1FieldCreate_Private(dm, f, Nd, metric)); 921 PetscFunctionReturn(PETSC_SUCCESS); 922 } 923 924 /*@ 925 DMPlexMetricCreateUniform - Construct a uniform isotropic metric 926 927 Input Parameters: 928 + dm - The `DM` 929 . f - The field number to use 930 - alpha - Scaling parameter for the diagonal 931 932 Output Parameter: 933 . metric - The uniform metric 934 935 Level: beginner 936 937 Note: 938 In this case, the metric is constant in space and so is only specified for a single vertex. 939 940 .seealso: `DMPLEX`, `DMPlexMetricCreate()`, `DMPlexMetricCreateIsotropic()` 941 @*/ 942 PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric) 943 { 944 PetscFunctionBegin; 945 PetscCall(DMPlexMetricSetUniform(dm, PETSC_TRUE)); 946 PetscCall(DMPlexMetricCreate(dm, f, metric)); 947 PetscCheck(alpha, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined"); 948 PetscCheck(alpha > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Uniform metric scaling should be in (0, inf)"); 949 PetscCall(VecSet(*metric, alpha)); 950 PetscCall(VecAssemblyBegin(*metric)); 951 PetscCall(VecAssemblyEnd(*metric)); 952 PetscFunctionReturn(PETSC_SUCCESS); 953 } 954 955 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 f0[]) 956 { 957 f0[0] = u[0]; 958 } 959 960 /*@ 961 DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator 962 963 Input Parameters: 964 + dm - The `DM` 965 . f - The field number to use 966 - indicator - The error indicator 967 968 Output Parameter: 969 . metric - The isotropic metric 970 971 Level: beginner 972 973 Notes: 974 It is assumed that the `DM` is comprised of simplices. 975 976 The indicator needs to be a scalar field. If it is not defined vertex-wise, then it is projected appropriately. 977 978 .seealso: `DMPLEX`, `DMPlexMetricCreate()`, `DMPlexMetricCreateUniform()` 979 @*/ 980 PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric) 981 { 982 PetscInt m, n; 983 984 PetscFunctionBegin; 985 PetscCall(DMPlexMetricSetIsotropic(dm, PETSC_TRUE)); 986 PetscCall(DMPlexMetricCreate(dm, f, metric)); 987 PetscCall(VecGetSize(indicator, &m)); 988 PetscCall(VecGetSize(*metric, &n)); 989 if (m == n) PetscCall(VecCopy(indicator, *metric)); 990 else { 991 DM dmIndi; 992 void (*funcs[1])(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[]); 993 994 PetscCall(VecGetDM(indicator, &dmIndi)); 995 funcs[0] = identity; 996 PetscCall(DMProjectFieldLocal(dmIndi, 0.0, indicator, funcs, INSERT_VALUES, *metric)); 997 } 998 PetscFunctionReturn(PETSC_SUCCESS); 999 } 1000 1001 /*@ 1002 DMPlexMetricDeterminantCreate - Create the determinant field for a Riemannian metric 1003 1004 Input Parameters: 1005 + dm - The `DM` of the metric field 1006 - f - The field number to use 1007 1008 Output Parameters: 1009 + determinant - The determinant field 1010 - dmDet - The corresponding `DM` 1011 1012 Level: beginner 1013 1014 .seealso: `DMPLEX`, `DMPlexMetricCreateUniform()`, `DMPlexMetricCreateIsotropic()`, `DMPlexMetricCreate()` 1015 @*/ 1016 PetscErrorCode DMPlexMetricDeterminantCreate(DM dm, PetscInt f, Vec *determinant, DM *dmDet) 1017 { 1018 PetscBool uniform; 1019 1020 PetscFunctionBegin; 1021 PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 1022 PetscCall(DMClone(dm, dmDet)); 1023 if (uniform) { 1024 MPI_Comm comm; 1025 1026 PetscCall(PetscObjectGetComm((PetscObject)*dmDet, &comm)); 1027 PetscCall(VecCreate(comm, determinant)); 1028 PetscCall(VecSetSizes(*determinant, 1, PETSC_DECIDE)); 1029 PetscCall(VecSetFromOptions(*determinant)); 1030 } else PetscCall(DMPlexP1FieldCreate_Private(*dmDet, f, 1, determinant)); 1031 PetscFunctionReturn(PETSC_SUCCESS); 1032 } 1033 1034 static PetscErrorCode LAPACKsyevFail(PetscInt dim, PetscScalar Mpos[]) 1035 { 1036 PetscInt i, j; 1037 1038 PetscFunctionBegin; 1039 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Failed to apply LAPACKsyev to the matrix\n")); 1040 for (i = 0; i < dim; ++i) { 1041 if (i == 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, " [[")); 1042 else PetscCall(PetscPrintf(PETSC_COMM_SELF, " [")); 1043 for (j = 0; j < dim; ++j) { 1044 if (j < dim - 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%15.8e, ", (double)PetscAbsScalar(Mpos[i * dim + j]))); 1045 else PetscCall(PetscPrintf(PETSC_COMM_SELF, "%15.8e", (double)PetscAbsScalar(Mpos[i * dim + j]))); 1046 } 1047 if (i < dim - 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 1048 else PetscCall(PetscPrintf(PETSC_COMM_SELF, "]]\n")); 1049 } 1050 PetscFunctionReturn(PETSC_SUCCESS); 1051 } 1052 1053 static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[], PetscScalar *detMp) 1054 { 1055 PetscInt i, j, k; 1056 PetscReal *eigs, max_eig, l_min = 1.0 / (h_max * h_max), l_max = 1.0 / (h_min * h_min), la_min = 1.0 / (a_max * a_max); 1057 PetscScalar *Mpos; 1058 1059 PetscFunctionBegin; 1060 PetscCall(PetscMalloc2(dim * dim, &Mpos, dim, &eigs)); 1061 1062 /* Symmetrize */ 1063 for (i = 0; i < dim; ++i) { 1064 Mpos[i * dim + i] = Mp[i * dim + i]; 1065 for (j = i + 1; j < dim; ++j) { 1066 Mpos[i * dim + j] = 0.5 * (Mp[i * dim + j] + Mp[j * dim + i]); 1067 Mpos[j * dim + i] = Mpos[i * dim + j]; 1068 } 1069 } 1070 1071 /* Compute eigendecomposition */ 1072 if (dim == 1) { 1073 /* Isotropic case */ 1074 eigs[0] = PetscRealPart(Mpos[0]); 1075 Mpos[0] = 1.0; 1076 } else { 1077 /* Anisotropic case */ 1078 PetscScalar *work; 1079 PetscBLASInt lwork; 1080 1081 lwork = 5 * dim; 1082 PetscCall(PetscMalloc1(5 * dim, &work)); 1083 { 1084 PetscBLASInt lierr; 1085 PetscBLASInt nb; 1086 1087 PetscCall(PetscBLASIntCast(dim, &nb)); 1088 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1089 #if defined(PETSC_USE_COMPLEX) 1090 { 1091 PetscReal *rwork; 1092 PetscCall(PetscMalloc1(3 * dim, &rwork)); 1093 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, Mpos, &nb, eigs, work, &lwork, rwork, &lierr)); 1094 PetscCall(PetscFree(rwork)); 1095 } 1096 #else 1097 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, Mpos, &nb, eigs, work, &lwork, &lierr)); 1098 #endif 1099 if (lierr) { 1100 for (i = 0; i < dim; ++i) { 1101 Mpos[i * dim + i] = Mp[i * dim + i]; 1102 for (j = i + 1; j < dim; ++j) { 1103 Mpos[i * dim + j] = 0.5 * (Mp[i * dim + j] + Mp[j * dim + i]); 1104 Mpos[j * dim + i] = Mpos[i * dim + j]; 1105 } 1106 } 1107 PetscCall(LAPACKsyevFail(dim, Mpos)); 1108 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int)lierr); 1109 } 1110 PetscCall(PetscFPTrapPop()); 1111 } 1112 PetscCall(PetscFree(work)); 1113 } 1114 1115 /* Reflect to positive orthant and enforce maximum and minimum size */ 1116 max_eig = 0.0; 1117 for (i = 0; i < dim; ++i) { 1118 eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i]))); 1119 max_eig = PetscMax(eigs[i], max_eig); 1120 } 1121 1122 /* Enforce maximum anisotropy and compute determinant */ 1123 *detMp = 1.0; 1124 for (i = 0; i < dim; ++i) { 1125 if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig * la_min); 1126 *detMp *= eigs[i]; 1127 } 1128 1129 /* Reconstruct Hessian */ 1130 for (i = 0; i < dim; ++i) { 1131 for (j = 0; j < dim; ++j) { 1132 Mp[i * dim + j] = 0.0; 1133 for (k = 0; k < dim; ++k) Mp[i * dim + j] += Mpos[k * dim + i] * eigs[k] * Mpos[k * dim + j]; 1134 } 1135 } 1136 PetscCall(PetscFree2(Mpos, eigs)); 1137 PetscFunctionReturn(PETSC_SUCCESS); 1138 } 1139 1140 /*@ 1141 DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric 1142 1143 Input Parameters: 1144 + dm - The `DM` 1145 . metricIn - The metric 1146 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 1147 - restrictAnisotropy - Should maximum anisotropy be enforced? 1148 1149 Output Parameters: 1150 + metricOut - The metric 1151 - determinant - Its determinant 1152 1153 Options Database Keys: 1154 + -dm_plex_metric_isotropic - Is the metric isotropic? 1155 . -dm_plex_metric_uniform - Is the metric uniform? 1156 . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 1157 . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 1158 - -dm_plex_metric_a_max - Maximum tolerated anisotropy 1159 1160 Level: beginner 1161 1162 .seealso: `DMPLEX`, `DMPlexMetricNormalize()`, `DMPlexMetricIntersection()` 1163 @*/ 1164 PetscErrorCode DMPlexMetricEnforceSPD(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metricOut, Vec determinant) 1165 { 1166 DM dmDet; 1167 PetscBool isotropic, uniform; 1168 PetscInt dim, vStart, vEnd, v; 1169 PetscScalar *met, *det; 1170 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 1.0e+15; 1171 1172 PetscFunctionBegin; 1173 PetscCall(PetscLogEventBegin(DMPLEX_MetricEnforceSPD, 0, 0, 0, 0)); 1174 1175 /* Extract metadata from dm */ 1176 PetscCall(DMGetDimension(dm, &dim)); 1177 if (restrictSizes) { 1178 PetscCall(DMPlexMetricGetMinimumMagnitude(dm, &h_min)); 1179 PetscCall(DMPlexMetricGetMaximumMagnitude(dm, &h_max)); 1180 h_min = PetscMax(h_min, 1.0e-30); 1181 h_max = PetscMin(h_max, 1.0e+30); 1182 PetscCheck(h_min < h_max, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum metric magnitude should be smaller than maximum metric magnitude"); 1183 } 1184 if (restrictAnisotropy) { 1185 PetscCall(DMPlexMetricGetMaximumAnisotropy(dm, &a_max)); 1186 a_max = PetscMin(a_max, 1.0e+30); 1187 } 1188 1189 /* Setup output metric */ 1190 PetscCall(VecCopy(metricIn, metricOut)); 1191 1192 /* Enforce SPD and extract determinant */ 1193 PetscCall(VecGetArray(metricOut, &met)); 1194 PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 1195 PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 1196 if (uniform) { 1197 PetscCheck(isotropic, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform anisotropic metrics cannot exist"); 1198 1199 /* Uniform case */ 1200 PetscCall(VecGetArray(determinant, &det)); 1201 PetscCall(DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det)); 1202 PetscCall(VecRestoreArray(determinant, &det)); 1203 } else { 1204 /* Spatially varying case */ 1205 PetscInt nrow; 1206 1207 if (isotropic) nrow = 1; 1208 else nrow = dim; 1209 PetscCall(VecGetDM(determinant, &dmDet)); 1210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1211 PetscCall(VecGetArray(determinant, &det)); 1212 for (v = vStart; v < vEnd; ++v) { 1213 PetscScalar *vmet, *vdet; 1214 PetscCall(DMPlexPointLocalRef(dm, v, met, &vmet)); 1215 PetscCall(DMPlexPointLocalRef(dmDet, v, det, &vdet)); 1216 PetscCall(DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, vmet, vdet)); 1217 } 1218 PetscCall(VecRestoreArray(determinant, &det)); 1219 } 1220 PetscCall(VecRestoreArray(metricOut, &met)); 1221 1222 PetscCall(PetscLogEventEnd(DMPLEX_MetricEnforceSPD, 0, 0, 0, 0)); 1223 PetscFunctionReturn(PETSC_SUCCESS); 1224 } 1225 1226 static void detMFunc(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 f0[]) 1227 { 1228 const PetscScalar p = constants[0]; 1229 1230 f0[0] = PetscPowScalar(u[0], p / (2.0 * p + dim)); 1231 } 1232 1233 /*@ 1234 DMPlexMetricNormalize - Apply L-p normalization to a metric 1235 1236 Input Parameters: 1237 + dm - The `DM` 1238 . metricIn - The unnormalized metric 1239 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 1240 - restrictAnisotropy - Should maximum metric anisotropy be enforced? 1241 1242 Output Parameters: 1243 + metricOut - The normalized metric 1244 - determinant - computed determinant 1245 1246 Options Database Keys: 1247 + -dm_plex_metric_isotropic - Is the metric isotropic? 1248 . -dm_plex_metric_uniform - Is the metric uniform? 1249 . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 1250 . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 1251 . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 1252 . -dm_plex_metric_a_max - Maximum tolerated anisotropy 1253 . -dm_plex_metric_p - L-p normalization order 1254 - -dm_plex_metric_target_complexity - Target metric complexity 1255 1256 Level: beginner 1257 1258 .seealso: `DMPLEX`, `DMPlexMetricEnforceSPD()`, `DMPlexMetricIntersection()` 1259 @*/ 1260 PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metricOut, Vec determinant) 1261 { 1262 DM dmDet; 1263 MPI_Comm comm; 1264 PetscBool restrictAnisotropyFirst, isotropic, uniform; 1265 PetscDS ds; 1266 PetscInt dim, Nd, vStart, vEnd, v, i; 1267 PetscScalar *met, *det, integral, constants[1]; 1268 PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, fact, target, realIntegral; 1269 1270 PetscFunctionBegin; 1271 PetscCall(PetscLogEventBegin(DMPLEX_MetricNormalize, 0, 0, 0, 0)); 1272 1273 /* Extract metadata from dm */ 1274 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1275 PetscCall(DMGetDimension(dm, &dim)); 1276 PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 1277 PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 1278 if (isotropic) Nd = 1; 1279 else Nd = dim * dim; 1280 1281 /* Set up metric and ensure it is SPD */ 1282 PetscCall(DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst)); 1283 PetscCall(DMPlexMetricEnforceSPD(dm, metricIn, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), metricOut, determinant)); 1284 1285 /* Compute global normalization factor */ 1286 PetscCall(DMPlexMetricGetTargetComplexity(dm, &target)); 1287 PetscCall(DMPlexMetricGetNormalizationOrder(dm, &p)); 1288 constants[0] = p; 1289 if (uniform) { 1290 PetscCheck(isotropic, comm, PETSC_ERR_SUP, "Uniform anisotropic metrics not supported"); 1291 DM dmTmp; 1292 Vec tmp; 1293 1294 PetscCall(DMClone(dm, &dmTmp)); 1295 PetscCall(DMPlexP1FieldCreate_Private(dmTmp, 0, 1, &tmp)); 1296 PetscCall(VecGetArray(determinant, &det)); 1297 PetscCall(VecSet(tmp, det[0])); 1298 PetscCall(VecRestoreArray(determinant, &det)); 1299 PetscCall(DMGetDS(dmTmp, &ds)); 1300 PetscCall(PetscDSSetConstants(ds, 1, constants)); 1301 PetscCall(PetscDSSetObjective(ds, 0, detMFunc)); 1302 PetscCall(DMPlexComputeIntegralFEM(dmTmp, tmp, &integral, NULL)); 1303 PetscCall(VecDestroy(&tmp)); 1304 PetscCall(DMDestroy(&dmTmp)); 1305 } else { 1306 PetscCall(VecGetDM(determinant, &dmDet)); 1307 PetscCall(DMGetDS(dmDet, &ds)); 1308 PetscCall(PetscDSSetConstants(ds, 1, constants)); 1309 PetscCall(PetscDSSetObjective(ds, 0, detMFunc)); 1310 PetscCall(DMPlexComputeIntegralFEM(dmDet, determinant, &integral, NULL)); 1311 } 1312 realIntegral = PetscRealPart(integral); 1313 PetscCheck(realIntegral > 1.0e-30, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Global metric normalization factor must be in (0, inf). Is the input metric positive-definite?"); 1314 factGlob = PetscPowReal(target / realIntegral, 2.0 / dim); 1315 1316 /* Apply local scaling */ 1317 if (restrictSizes) { 1318 PetscCall(DMPlexMetricGetMinimumMagnitude(dm, &h_min)); 1319 PetscCall(DMPlexMetricGetMaximumMagnitude(dm, &h_max)); 1320 h_min = PetscMax(h_min, 1.0e-30); 1321 h_max = PetscMin(h_max, 1.0e+30); 1322 PetscCheck(h_min < h_max, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum metric magnitude should be smaller than maximum metric magnitude"); 1323 } 1324 if (restrictAnisotropy && !restrictAnisotropyFirst) { 1325 PetscCall(DMPlexMetricGetMaximumAnisotropy(dm, &a_max)); 1326 a_max = PetscMin(a_max, 1.0e+30); 1327 } 1328 PetscCall(VecGetArray(metricOut, &met)); 1329 PetscCall(VecGetArray(determinant, &det)); 1330 if (uniform) { 1331 /* Uniform case */ 1332 met[0] *= factGlob * PetscPowReal(PetscAbsScalar(det[0]), -1.0 / (2 * p + dim)); 1333 if (restrictSizes) PetscCall(DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det)); 1334 } else { 1335 /* Spatially varying case */ 1336 PetscInt nrow; 1337 1338 if (isotropic) nrow = 1; 1339 else nrow = dim; 1340 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1341 PetscCall(VecGetDM(determinant, &dmDet)); 1342 for (v = vStart; v < vEnd; ++v) { 1343 PetscScalar *Mp, *detM; 1344 1345 PetscCall(DMPlexPointLocalRef(dm, v, met, &Mp)); 1346 PetscCall(DMPlexPointLocalRef(dmDet, v, det, &detM)); 1347 fact = factGlob * PetscPowReal(PetscAbsScalar(detM[0]), -1.0 / (2 * p + dim)); 1348 for (i = 0; i < Nd; ++i) Mp[i] *= fact; 1349 if (restrictSizes) PetscCall(DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, Mp, detM)); 1350 } 1351 } 1352 PetscCall(VecRestoreArray(determinant, &det)); 1353 PetscCall(VecRestoreArray(metricOut, &met)); 1354 1355 PetscCall(PetscLogEventEnd(DMPLEX_MetricNormalize, 0, 0, 0, 0)); 1356 PetscFunctionReturn(PETSC_SUCCESS); 1357 } 1358 1359 /*@ 1360 DMPlexMetricAverage - Compute the average of a list of metrics 1361 1362 Input Parameters: 1363 + dm - The `DM` 1364 . numMetrics - The number of metrics to be averaged 1365 . weights - Weights for the average 1366 - metrics - The metrics to be averaged 1367 1368 Output Parameter: 1369 . metricAvg - The averaged metric 1370 1371 Level: beginner 1372 1373 Notes: 1374 The weights should sum to unity. 1375 1376 If weights are not provided then an unweighted average is used. 1377 1378 .seealso: `DMPLEX`, `DMPlexMetricAverage2()`, `DMPlexMetricAverage3()`, `DMPlexMetricIntersection()` 1379 @*/ 1380 PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec metricAvg) 1381 { 1382 PetscBool haveWeights = PETSC_TRUE; 1383 PetscInt i, m, n; 1384 PetscReal sum = 0.0, tol = 1.0e-10; 1385 1386 PetscFunctionBegin; 1387 PetscCall(PetscLogEventBegin(DMPLEX_MetricAverage, 0, 0, 0, 0)); 1388 PetscCheck(numMetrics >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %" PetscInt_FMT " < 1 metrics", numMetrics); 1389 PetscCall(VecSet(metricAvg, 0.0)); 1390 PetscCall(VecGetSize(metricAvg, &m)); 1391 for (i = 0; i < numMetrics; ++i) { 1392 PetscCall(VecGetSize(metrics[i], &n)); 1393 PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Averaging different metric types not implemented"); 1394 } 1395 1396 /* Default to the unweighted case */ 1397 if (!weights) { 1398 PetscCall(PetscMalloc1(numMetrics, &weights)); 1399 haveWeights = PETSC_FALSE; 1400 for (i = 0; i < numMetrics; ++i) weights[i] = 1.0 / numMetrics; 1401 } 1402 1403 /* Check weights sum to unity */ 1404 for (i = 0; i < numMetrics; ++i) sum += weights[i]; 1405 PetscCheck(PetscAbsReal(sum - 1) <= tol, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); 1406 1407 /* Compute metric average */ 1408 for (i = 0; i < numMetrics; ++i) PetscCall(VecAXPY(metricAvg, weights[i], metrics[i])); 1409 if (!haveWeights) PetscCall(PetscFree(weights)); 1410 1411 PetscCall(PetscLogEventEnd(DMPLEX_MetricAverage, 0, 0, 0, 0)); 1412 PetscFunctionReturn(PETSC_SUCCESS); 1413 } 1414 1415 /*@ 1416 DMPlexMetricAverage2 - Compute the unweighted average of two metrics 1417 1418 Input Parameters: 1419 + dm - The `DM` 1420 . metric1 - The first metric to be averaged 1421 - metric2 - The second metric to be averaged 1422 1423 Output Parameter: 1424 . metricAvg - The averaged metric 1425 1426 Level: beginner 1427 1428 .seealso: `DMPLEX`, `DMPlexMetricAverage()`, `DMPlexMetricAverage3()` 1429 @*/ 1430 PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec metricAvg) 1431 { 1432 PetscReal weights[2] = {0.5, 0.5}; 1433 Vec metrics[2] = {metric1, metric2}; 1434 1435 PetscFunctionBegin; 1436 PetscCall(DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg)); 1437 PetscFunctionReturn(PETSC_SUCCESS); 1438 } 1439 1440 /*@ 1441 DMPlexMetricAverage3 - Compute the unweighted average of three metrics 1442 1443 Input Parameters: 1444 + dm - The `DM` 1445 . metric1 - The first metric to be averaged 1446 . metric2 - The second metric to be averaged 1447 - metric3 - The third metric to be averaged 1448 1449 Output Parameter: 1450 . metricAvg - The averaged metric 1451 1452 Level: beginner 1453 1454 .seealso: `DMPLEX`, `DMPlexMetricAverage()`, `DMPlexMetricAverage2()` 1455 @*/ 1456 PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec metricAvg) 1457 { 1458 PetscReal weights[3] = {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0}; 1459 Vec metrics[3] = {metric1, metric2, metric3}; 1460 1461 PetscFunctionBegin; 1462 PetscCall(DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg)); 1463 PetscFunctionReturn(PETSC_SUCCESS); 1464 } 1465 1466 static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 1467 { 1468 PetscInt i, j, k, l, m; 1469 PetscReal *evals; 1470 PetscScalar *evecs, *sqrtM1, *isqrtM1; 1471 1472 PetscFunctionBegin; 1473 /* Isotropic case */ 1474 if (dim == 1) { 1475 M2[0] = (PetscScalar)PetscMax(PetscRealPart(M1[0]), PetscRealPart(M2[0])); 1476 PetscFunctionReturn(PETSC_SUCCESS); 1477 } 1478 1479 /* Anisotropic case */ 1480 PetscCall(PetscMalloc4(dim * dim, &evecs, dim * dim, &sqrtM1, dim * dim, &isqrtM1, dim, &evals)); 1481 for (i = 0; i < dim; ++i) { 1482 for (j = 0; j < dim; ++j) evecs[i * dim + j] = M1[i * dim + j]; 1483 } 1484 { 1485 PetscScalar *work; 1486 PetscBLASInt lwork; 1487 1488 lwork = 5 * dim; 1489 PetscCall(PetscMalloc1(5 * dim, &work)); 1490 { 1491 PetscBLASInt lierr, nb; 1492 PetscReal sqrtj; 1493 1494 /* Compute eigendecomposition of M1 */ 1495 PetscCall(PetscBLASIntCast(dim, &nb)); 1496 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1497 #if defined(PETSC_USE_COMPLEX) 1498 { 1499 PetscReal *rwork; 1500 PetscCall(PetscMalloc1(3 * dim, &rwork)); 1501 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 1502 PetscCall(PetscFree(rwork)); 1503 } 1504 #else 1505 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 1506 #endif 1507 if (lierr) { 1508 PetscCall(LAPACKsyevFail(dim, M1)); 1509 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int)lierr); 1510 } 1511 PetscCall(PetscFPTrapPop()); 1512 1513 /* Compute square root and the reciprocal thereof */ 1514 for (i = 0; i < dim; ++i) { 1515 for (k = 0; k < dim; ++k) { 1516 sqrtM1[i * dim + k] = 0.0; 1517 isqrtM1[i * dim + k] = 0.0; 1518 for (j = 0; j < dim; ++j) { 1519 sqrtj = PetscSqrtReal(evals[j]); 1520 sqrtM1[i * dim + k] += evecs[j * dim + i] * sqrtj * evecs[j * dim + k]; 1521 isqrtM1[i * dim + k] += evecs[j * dim + i] * (1.0 / sqrtj) * evecs[j * dim + k]; 1522 } 1523 } 1524 } 1525 1526 /* Map M2 into the space spanned by the eigenvectors of M1 */ 1527 for (i = 0; i < dim; ++i) { 1528 for (l = 0; l < dim; ++l) { 1529 evecs[i * dim + l] = 0.0; 1530 for (j = 0; j < dim; ++j) { 1531 for (k = 0; k < dim; ++k) evecs[i * dim + l] += isqrtM1[j * dim + i] * M2[j * dim + k] * isqrtM1[k * dim + l]; 1532 } 1533 } 1534 } 1535 1536 /* Compute eigendecomposition */ 1537 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1538 #if defined(PETSC_USE_COMPLEX) 1539 { 1540 PetscReal *rwork; 1541 PetscCall(PetscMalloc1(3 * dim, &rwork)); 1542 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 1543 PetscCall(PetscFree(rwork)); 1544 } 1545 #else 1546 PetscCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 1547 #endif 1548 if (lierr) { 1549 for (i = 0; i < dim; ++i) { 1550 for (l = 0; l < dim; ++l) { 1551 evecs[i * dim + l] = 0.0; 1552 for (j = 0; j < dim; ++j) { 1553 for (k = 0; k < dim; ++k) evecs[i * dim + l] += isqrtM1[j * dim + i] * M2[j * dim + k] * isqrtM1[k * dim + l]; 1554 } 1555 } 1556 } 1557 PetscCall(LAPACKsyevFail(dim, evecs)); 1558 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int)lierr); 1559 } 1560 PetscCall(PetscFPTrapPop()); 1561 1562 /* Modify eigenvalues */ 1563 for (i = 0; i < dim; ++i) evals[i] = PetscMax(evals[i], 1.0); 1564 1565 /* Map back to get the intersection */ 1566 for (i = 0; i < dim; ++i) { 1567 for (m = 0; m < dim; ++m) { 1568 M2[i * dim + m] = 0.0; 1569 for (j = 0; j < dim; ++j) { 1570 for (k = 0; k < dim; ++k) { 1571 for (l = 0; l < dim; ++l) M2[i * dim + m] += sqrtM1[j * dim + i] * evecs[j * dim + k] * evals[k] * evecs[l * dim + k] * sqrtM1[l * dim + m]; 1572 } 1573 } 1574 } 1575 } 1576 } 1577 PetscCall(PetscFree(work)); 1578 } 1579 PetscCall(PetscFree4(evecs, sqrtM1, isqrtM1, evals)); 1580 PetscFunctionReturn(PETSC_SUCCESS); 1581 } 1582 1583 /*@ 1584 DMPlexMetricIntersection - Compute the intersection of a list of metrics 1585 1586 Input Parameters: 1587 + dm - The `DM` 1588 . numMetrics - The number of metrics to be intersected 1589 - metrics - The metrics to be intersected 1590 1591 Output Parameter: 1592 . metricInt - The intersected metric 1593 1594 Level: beginner 1595 1596 Notes: 1597 The intersection of a list of metrics has the minimal ellipsoid which fits within the ellipsoids of the component metrics. 1598 1599 The implementation used here is only consistent with the minimal ellipsoid definition in the case numMetrics = 2. 1600 1601 .seealso: `DMPLEX`, `DMPlexMetricIntersection2()`, `DMPlexMetricIntersection3()`, `DMPlexMetricAverage()` 1602 @*/ 1603 PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec metricInt) 1604 { 1605 PetscBool isotropic, uniform; 1606 PetscInt v, i, m, n; 1607 PetscScalar *met, *meti; 1608 1609 PetscFunctionBegin; 1610 PetscCall(PetscLogEventBegin(DMPLEX_MetricIntersection, 0, 0, 0, 0)); 1611 PetscCheck(numMetrics >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %" PetscInt_FMT " < 1 metrics", numMetrics); 1612 1613 /* Copy over the first metric */ 1614 PetscCall(VecCopy(metrics[0], metricInt)); 1615 if (numMetrics == 1) PetscFunctionReturn(PETSC_SUCCESS); 1616 PetscCall(VecGetSize(metricInt, &m)); 1617 for (i = 0; i < numMetrics; ++i) { 1618 PetscCall(VecGetSize(metrics[i], &n)); 1619 PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Intersecting different metric types not implemented"); 1620 } 1621 1622 /* Intersect subsequent metrics in turn */ 1623 PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 1624 PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 1625 if (uniform) { 1626 /* Uniform case */ 1627 PetscCall(VecGetArray(metricInt, &met)); 1628 for (i = 1; i < numMetrics; ++i) { 1629 PetscCall(VecGetArray(metrics[i], &meti)); 1630 PetscCall(DMPlexMetricIntersection_Private(1, meti, met)); 1631 PetscCall(VecRestoreArray(metrics[i], &meti)); 1632 } 1633 PetscCall(VecRestoreArray(metricInt, &met)); 1634 } else { 1635 /* Spatially varying case */ 1636 PetscInt dim, vStart, vEnd, nrow; 1637 PetscScalar *M, *Mi; 1638 1639 PetscCall(DMGetDimension(dm, &dim)); 1640 if (isotropic) nrow = 1; 1641 else nrow = dim; 1642 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1643 PetscCall(VecGetArray(metricInt, &met)); 1644 for (i = 1; i < numMetrics; ++i) { 1645 PetscCall(VecGetArray(metrics[i], &meti)); 1646 for (v = vStart; v < vEnd; ++v) { 1647 PetscCall(DMPlexPointLocalRef(dm, v, met, &M)); 1648 PetscCall(DMPlexPointLocalRef(dm, v, meti, &Mi)); 1649 PetscCall(DMPlexMetricIntersection_Private(nrow, Mi, M)); 1650 } 1651 PetscCall(VecRestoreArray(metrics[i], &meti)); 1652 } 1653 PetscCall(VecRestoreArray(metricInt, &met)); 1654 } 1655 1656 PetscCall(PetscLogEventEnd(DMPLEX_MetricIntersection, 0, 0, 0, 0)); 1657 PetscFunctionReturn(PETSC_SUCCESS); 1658 } 1659 1660 /*@ 1661 DMPlexMetricIntersection2 - Compute the intersection of two metrics 1662 1663 Input Parameters: 1664 + dm - The `DM` 1665 . metric1 - The first metric to be intersected 1666 - metric2 - The second metric to be intersected 1667 1668 Output Parameter: 1669 . metricInt - The intersected metric 1670 1671 Level: beginner 1672 1673 .seealso: `DMPLEX`, `DMPlexMetricIntersection()`, `DMPlexMetricIntersection3()` 1674 @*/ 1675 PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec metricInt) 1676 { 1677 Vec metrics[2] = {metric1, metric2}; 1678 1679 PetscFunctionBegin; 1680 PetscCall(DMPlexMetricIntersection(dm, 2, metrics, metricInt)); 1681 PetscFunctionReturn(PETSC_SUCCESS); 1682 } 1683 1684 /*@ 1685 DMPlexMetricIntersection3 - Compute the intersection of three metrics 1686 1687 Input Parameters: 1688 + dm - The `DM` 1689 . metric1 - The first metric to be intersected 1690 . metric2 - The second metric to be intersected 1691 - metric3 - The third metric to be intersected 1692 1693 Output Parameter: 1694 . metricInt - The intersected metric 1695 1696 Level: beginner 1697 1698 .seealso: `DMPLEX`, `DMPlexMetricIntersection()`, `DMPlexMetricIntersection2()` 1699 @*/ 1700 PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec metricInt) 1701 { 1702 Vec metrics[3] = {metric1, metric2, metric3}; 1703 1704 PetscFunctionBegin; 1705 PetscCall(DMPlexMetricIntersection(dm, 3, metrics, metricInt)); 1706 PetscFunctionReturn(PETSC_SUCCESS); 1707 } 1708