1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petscblaslapack.h> 3 4 PetscErrorCode DMPlexMetricSetFromOptions(DM dm) 5 { 6 MPI_Comm comm; 7 PetscBool isotropic = PETSC_FALSE, restrictAnisotropyFirst = PETSC_FALSE; 8 PetscBool noInsert = PETSC_FALSE, noSwap = PETSC_FALSE, noMove = PETSC_FALSE; 9 PetscErrorCode ierr; 10 PetscInt verbosity = -1, numIter = 3; 11 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; 12 13 PetscFunctionBegin; 14 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 15 ierr = PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric");CHKERRQ(ierr); 16 ierr = PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL);CHKERRQ(ierr); 17 ierr = DMPlexMetricSetIsotropic(dm, isotropic);CHKERRQ(ierr); 18 ierr = PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL);CHKERRQ(ierr); 19 ierr = DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst);CHKERRQ(ierr); 20 ierr = PetscOptionsBool("-dm_plex_metric_no_insert", "Turn off node insertion and deletion", "DMAdaptMetric", noInsert, &noInsert, NULL);CHKERRQ(ierr); 21 ierr = DMPlexMetricSetNoInsertion(dm, noInsert);CHKERRQ(ierr); 22 ierr = PetscOptionsBool("-dm_plex_metric_no_swap", "Turn off facet swapping", "DMAdaptMetric", noSwap, &noSwap, NULL);CHKERRQ(ierr); 23 ierr = DMPlexMetricSetNoSwapping(dm, noSwap);CHKERRQ(ierr); 24 ierr = PetscOptionsBool("-dm_plex_metric_no_move", "Turn off facet node movement", "DMAdaptMetric", noMove, &noMove, NULL);CHKERRQ(ierr); 25 ierr = DMPlexMetricSetNoMovement(dm, noMove);CHKERRQ(ierr); 26 ierr = PetscOptionsBoundedInt("-dm_plex_metric_num_iterations", "Number of ParMmg adaptation iterations", "DMAdaptMetric", numIter, &numIter, NULL, 0);CHKERRQ(ierr); 27 ierr = DMPlexMetricSetNumIterations(dm, numIter);CHKERRQ(ierr); 28 ierr = PetscOptionsRangeInt("-dm_plex_metric_verbosity", "Verbosity of metric-based mesh adaptation package (-1 = silent, 10 = maximum)", "DMAdaptMetric", verbosity, &verbosity, NULL, -1, 10);CHKERRQ(ierr); 29 ierr = DMPlexMetricSetVerbosity(dm, verbosity);CHKERRQ(ierr); 30 ierr = PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL);CHKERRQ(ierr); 31 ierr = DMPlexMetricSetMinimumMagnitude(dm, h_min);CHKERRQ(ierr); 32 ierr = PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL);CHKERRQ(ierr); 33 ierr = DMPlexMetricSetMaximumMagnitude(dm, h_max);CHKERRQ(ierr); 34 ierr = PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL);CHKERRQ(ierr); 35 ierr = DMPlexMetricSetMaximumAnisotropy(dm, a_max);CHKERRQ(ierr); 36 ierr = PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL);CHKERRQ(ierr); 37 ierr = DMPlexMetricSetNormalizationOrder(dm, p);CHKERRQ(ierr); 38 ierr = PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL);CHKERRQ(ierr); 39 ierr = DMPlexMetricSetTargetComplexity(dm, target);CHKERRQ(ierr); 40 ierr = PetscOptionsReal("-dm_plex_metric_gradation_factor", "Metric gradation factor", "DMAdaptMetric", beta, &beta, NULL);CHKERRQ(ierr); 41 ierr = DMPlexMetricSetGradationFactor(dm, beta);CHKERRQ(ierr); 42 ierr = PetscOptionsEnd();CHKERRQ(ierr); 43 PetscFunctionReturn(0); 44 } 45 46 /* 47 DMPlexMetricSetIsotropic - Record whether a metric is isotropic 48 49 Input parameters: 50 + dm - The DM 51 - isotropic - Is the metric isotropic? 52 53 Level: beginner 54 55 .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst() 56 */ 57 PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic) 58 { 59 DM_Plex *plex = (DM_Plex *) dm->data; 60 PetscErrorCode ierr; 61 62 PetscFunctionBegin; 63 if (!plex->metricCtx) { 64 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 65 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 66 } 67 plex->metricCtx->isotropic = isotropic; 68 PetscFunctionReturn(0); 69 } 70 71 /* 72 DMPlexMetricIsIsotropic - Is a metric is isotropic? 73 74 Input parameters: 75 . dm - The DM 76 77 Output parameters: 78 . isotropic - Is the metric isotropic? 79 80 Level: beginner 81 82 .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst() 83 */ 84 PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic) 85 { 86 DM_Plex *plex = (DM_Plex *) dm->data; 87 PetscErrorCode ierr; 88 89 PetscFunctionBegin; 90 if (!plex->metricCtx) { 91 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 92 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 93 } 94 *isotropic = plex->metricCtx->isotropic; 95 PetscFunctionReturn(0); 96 } 97 98 /* 99 DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization 100 101 Input parameters: 102 + dm - The DM 103 - restrictAnisotropyFirst - Should anisotropy be normalized first? 104 105 Level: beginner 106 107 .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst() 108 */ 109 PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst) 110 { 111 DM_Plex *plex = (DM_Plex *) dm->data; 112 PetscErrorCode ierr; 113 114 PetscFunctionBegin; 115 if (!plex->metricCtx) { 116 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 117 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 118 } 119 plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst; 120 PetscFunctionReturn(0); 121 } 122 123 /* 124 DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after? 125 126 Input parameters: 127 . dm - The DM 128 129 Output parameters: 130 . restrictAnisotropyFirst - Is anisotropy be normalized first? 131 132 Level: beginner 133 134 .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst() 135 */ 136 PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst) 137 { 138 DM_Plex *plex = (DM_Plex *) dm->data; 139 PetscErrorCode ierr; 140 141 PetscFunctionBegin; 142 if (!plex->metricCtx) { 143 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 144 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 145 } 146 *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst; 147 PetscFunctionReturn(0); 148 } 149 150 /* 151 DMPlexMetricSetNoInsertion - Should node insertion and deletion be turned off? 152 153 Input parameters: 154 + dm - The DM 155 - noInsert - Should node insertion and deletion be turned off? 156 157 Level: beginner 158 159 .seealso: DMPlexMetricNoInsertion(), DMPlexMetricSetNoSwapping(), DMPlexMetricSetNoMovement() 160 */ 161 PetscErrorCode DMPlexMetricSetNoInsertion(DM dm, PetscBool noInsert) 162 { 163 DM_Plex *plex = (DM_Plex *) dm->data; 164 PetscErrorCode ierr; 165 166 PetscFunctionBegin; 167 if (!plex->metricCtx) { 168 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 169 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 170 } 171 plex->metricCtx->noInsert = noInsert; 172 PetscFunctionReturn(0); 173 } 174 175 /* 176 DMPlexMetricNoInsertion - Are node insertion and deletion turned off? 177 178 Input parameters: 179 . dm - The DM 180 181 Output parameters: 182 . noInsert - Are node insertion and deletion turned off? 183 184 Level: beginner 185 186 .seealso: DMPlexMetricSetNoInsertion(), DMPlexMetricNoSwapping(), DMPlexMetricNoMovement() 187 */ 188 PetscErrorCode DMPlexMetricNoInsertion(DM dm, PetscBool *noInsert) 189 { 190 DM_Plex *plex = (DM_Plex *) dm->data; 191 PetscErrorCode ierr; 192 193 PetscFunctionBegin; 194 if (!plex->metricCtx) { 195 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 196 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 197 } 198 *noInsert = plex->metricCtx->noInsert; 199 PetscFunctionReturn(0); 200 } 201 202 /* 203 DMPlexMetricSetNoSwapping - Should facet swapping be turned off? 204 205 Input parameters: 206 + dm - The DM 207 - noSwap - Should facet swapping be turned off? 208 209 Level: beginner 210 211 .seealso: DMPlexMetricNoSwapping(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoMovement() 212 */ 213 PetscErrorCode DMPlexMetricSetNoSwapping(DM dm, PetscBool noSwap) 214 { 215 DM_Plex *plex = (DM_Plex *) dm->data; 216 PetscErrorCode ierr; 217 218 PetscFunctionBegin; 219 if (!plex->metricCtx) { 220 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 221 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 222 } 223 plex->metricCtx->noSwap = noSwap; 224 PetscFunctionReturn(0); 225 } 226 227 /* 228 DMPlexMetricNoSwapping - Is facet swapping turned off? 229 230 Input parameters: 231 . dm - The DM 232 233 Output parameters: 234 . noSwap - Is facet swapping turned off? 235 236 Level: beginner 237 238 .seealso: DMPlexMetricSetNoSwapping(), DMPlexMetricNoInsertion(), DMPlexMetricNoMovement() 239 */ 240 PetscErrorCode DMPlexMetricNoSwapping(DM dm, PetscBool *noSwap) 241 { 242 DM_Plex *plex = (DM_Plex *) dm->data; 243 PetscErrorCode ierr; 244 245 PetscFunctionBegin; 246 if (!plex->metricCtx) { 247 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 248 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 249 } 250 *noSwap = plex->metricCtx->noSwap; 251 PetscFunctionReturn(0); 252 } 253 254 /* 255 DMPlexMetricSetNoMovement - Should node movement be turned off? 256 257 Input parameters: 258 + dm - The DM 259 - noMove - Should node movement be turned off? 260 261 Level: beginner 262 263 .seealso: DMPlexMetricNoMovement(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoSwapping() 264 */ 265 PetscErrorCode DMPlexMetricSetNoMovement(DM dm, PetscBool noMove) 266 { 267 DM_Plex *plex = (DM_Plex *) dm->data; 268 PetscErrorCode ierr; 269 270 PetscFunctionBegin; 271 if (!plex->metricCtx) { 272 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 273 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 274 } 275 plex->metricCtx->noMove = noMove; 276 PetscFunctionReturn(0); 277 } 278 279 /* 280 DMPlexMetricNoMovement - Is node movement turned off? 281 282 Input parameters: 283 . dm - The DM 284 285 Output parameters: 286 . noMove - Is node movement turned off? 287 288 Level: beginner 289 290 .seealso: DMPlexMetricSetNoMovement(), DMPlexMetricNoInsertion(), DMPlexMetricNoSwapping() 291 */ 292 PetscErrorCode DMPlexMetricNoMovement(DM dm, PetscBool *noMove) 293 { 294 DM_Plex *plex = (DM_Plex *) dm->data; 295 PetscErrorCode ierr; 296 297 PetscFunctionBegin; 298 if (!plex->metricCtx) { 299 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 300 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 301 } 302 *noMove = plex->metricCtx->noMove; 303 PetscFunctionReturn(0); 304 } 305 306 /* 307 DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude 308 309 Input parameters: 310 + dm - The DM 311 - h_min - The minimum tolerated metric magnitude 312 313 Level: beginner 314 315 .seealso: DMPlexMetricGetMinimumMagnitude(), DMPlexMetricSetMaximumMagnitude() 316 */ 317 PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min) 318 { 319 DM_Plex *plex = (DM_Plex *) dm->data; 320 PetscErrorCode ierr; 321 322 PetscFunctionBegin; 323 if (!plex->metricCtx) { 324 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 325 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 326 } 327 if (h_min <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_min); 328 plex->metricCtx->h_min = h_min; 329 PetscFunctionReturn(0); 330 } 331 332 /* 333 DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude 334 335 Input parameters: 336 . dm - The DM 337 338 Output parameters: 339 . h_min - The minimum tolerated metric magnitude 340 341 Level: beginner 342 343 .seealso: DMPlexMetricSetMinimumMagnitude(), DMPlexMetricGetMaximumMagnitude() 344 */ 345 PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min) 346 { 347 DM_Plex *plex = (DM_Plex *) dm->data; 348 PetscErrorCode ierr; 349 350 PetscFunctionBegin; 351 if (!plex->metricCtx) { 352 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 353 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 354 } 355 *h_min = plex->metricCtx->h_min; 356 PetscFunctionReturn(0); 357 } 358 359 /* 360 DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude 361 362 Input parameters: 363 + dm - The DM 364 - h_max - The maximum tolerated metric magnitude 365 366 Level: beginner 367 368 .seealso: DMPlexMetricGetMaximumMagnitude(), DMPlexMetricSetMinimumMagnitude() 369 */ 370 PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max) 371 { 372 DM_Plex *plex = (DM_Plex *) dm->data; 373 PetscErrorCode ierr; 374 375 PetscFunctionBegin; 376 if (!plex->metricCtx) { 377 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 378 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 379 } 380 if (h_max <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_max); 381 plex->metricCtx->h_max = h_max; 382 PetscFunctionReturn(0); 383 } 384 385 /* 386 DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude 387 388 Input parameters: 389 . dm - The DM 390 391 Output parameters: 392 . h_max - The maximum tolerated metric magnitude 393 394 Level: beginner 395 396 .seealso: DMPlexMetricSetMaximumMagnitude(), DMPlexMetricGetMinimumMagnitude() 397 */ 398 PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max) 399 { 400 DM_Plex *plex = (DM_Plex *) dm->data; 401 PetscErrorCode ierr; 402 403 PetscFunctionBegin; 404 if (!plex->metricCtx) { 405 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 406 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 407 } 408 *h_max = plex->metricCtx->h_max; 409 PetscFunctionReturn(0); 410 } 411 412 /* 413 DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy 414 415 Input parameters: 416 + dm - The DM 417 - a_max - The maximum tolerated metric anisotropy 418 419 Level: beginner 420 421 Note: If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one. 422 423 .seealso: DMPlexMetricGetMaximumAnisotropy(), DMPlexMetricSetMaximumMagnitude() 424 */ 425 PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max) 426 { 427 DM_Plex *plex = (DM_Plex *) dm->data; 428 PetscErrorCode ierr; 429 430 PetscFunctionBegin; 431 if (!plex->metricCtx) { 432 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 433 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 434 } 435 if (a_max < 1.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Anisotropy must be at least one, not %.4e", a_max); 436 plex->metricCtx->a_max = a_max; 437 PetscFunctionReturn(0); 438 } 439 440 /* 441 DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy 442 443 Input parameters: 444 . dm - The DM 445 446 Output parameters: 447 . a_max - The maximum tolerated metric anisotropy 448 449 Level: beginner 450 451 .seealso: DMPlexMetricSetMaximumAnisotropy(), DMPlexMetricGetMaximumMagnitude() 452 */ 453 PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max) 454 { 455 DM_Plex *plex = (DM_Plex *) dm->data; 456 PetscErrorCode ierr; 457 458 PetscFunctionBegin; 459 if (!plex->metricCtx) { 460 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 461 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 462 } 463 *a_max = plex->metricCtx->a_max; 464 PetscFunctionReturn(0); 465 } 466 467 /* 468 DMPlexMetricSetTargetComplexity - Set the target metric complexity 469 470 Input parameters: 471 + dm - The DM 472 - targetComplexity - The target metric complexity 473 474 Level: beginner 475 476 .seealso: DMPlexMetricGetTargetComplexity(), DMPlexMetricSetNormalizationOrder() 477 */ 478 PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity) 479 { 480 DM_Plex *plex = (DM_Plex *) dm->data; 481 PetscErrorCode ierr; 482 483 PetscFunctionBegin; 484 if (!plex->metricCtx) { 485 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 486 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 487 } 488 if (targetComplexity <= 0.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric complexity must be positive"); 489 plex->metricCtx->targetComplexity = targetComplexity; 490 PetscFunctionReturn(0); 491 } 492 493 /* 494 DMPlexMetricGetTargetComplexity - Get the target metric complexity 495 496 Input parameters: 497 . dm - The DM 498 499 Output parameters: 500 . targetComplexity - The target metric complexity 501 502 Level: beginner 503 504 .seealso: DMPlexMetricSetTargetComplexity(), DMPlexMetricGetNormalizationOrder() 505 */ 506 PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity) 507 { 508 DM_Plex *plex = (DM_Plex *) dm->data; 509 PetscErrorCode ierr; 510 511 PetscFunctionBegin; 512 if (!plex->metricCtx) { 513 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 514 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 515 } 516 *targetComplexity = plex->metricCtx->targetComplexity; 517 PetscFunctionReturn(0); 518 } 519 520 /* 521 DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization 522 523 Input parameters: 524 + dm - The DM 525 - p - The normalization order 526 527 Level: beginner 528 529 .seealso: DMPlexMetricGetNormalizationOrder(), DMPlexMetricSetTargetComplexity() 530 */ 531 PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p) 532 { 533 DM_Plex *plex = (DM_Plex *) dm->data; 534 PetscErrorCode ierr; 535 536 PetscFunctionBegin; 537 if (!plex->metricCtx) { 538 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 539 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 540 } 541 if (p < 1.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Normalization order must be one or greater"); 542 plex->metricCtx->p = p; 543 PetscFunctionReturn(0); 544 } 545 546 /* 547 DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization 548 549 Input parameters: 550 . dm - The DM 551 552 Output parameters: 553 . p - The normalization order 554 555 Level: beginner 556 557 .seealso: DMPlexMetricSetNormalizationOrder(), DMPlexMetricGetTargetComplexity() 558 */ 559 PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p) 560 { 561 DM_Plex *plex = (DM_Plex *) dm->data; 562 PetscErrorCode ierr; 563 564 PetscFunctionBegin; 565 if (!plex->metricCtx) { 566 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 567 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 568 } 569 *p = plex->metricCtx->p; 570 PetscFunctionReturn(0); 571 } 572 573 /* 574 DMPlexMetricSetGradationFactor - Set the metric gradation factor 575 576 Input parameters: 577 + dm - The DM 578 - beta - The metric gradation factor 579 580 Level: beginner 581 582 Notes: 583 584 The gradation factor is the maximum tolerated length ratio between adjacent edges. 585 586 Turn off gradation by passing the value -1. Otherwise, pass a positive value. 587 588 .seealso: DMPlexMetricGetGradationFactor() 589 */ 590 PetscErrorCode DMPlexMetricSetGradationFactor(DM dm, PetscReal beta) 591 { 592 DM_Plex *plex = (DM_Plex *) dm->data; 593 PetscErrorCode ierr; 594 595 PetscFunctionBegin; 596 if (!plex->metricCtx) { 597 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 598 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 599 } 600 plex->metricCtx->gradationFactor = beta; 601 PetscFunctionReturn(0); 602 } 603 604 /* 605 DMPlexMetricGetGradationFactor - Get the metric gradation factor 606 607 Input parameters: 608 . dm - The DM 609 610 Output parameters: 611 . beta - The metric gradation factor 612 613 Level: beginner 614 615 Note: The gradation factor is the maximum tolerated length ratio between adjacent edges. 616 617 .seealso: DMPlexMetricSetGradationFactor() 618 */ 619 PetscErrorCode DMPlexMetricGetGradationFactor(DM dm, PetscReal *beta) 620 { 621 DM_Plex *plex = (DM_Plex *) dm->data; 622 PetscErrorCode ierr; 623 624 PetscFunctionBegin; 625 if (!plex->metricCtx) { 626 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 627 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 628 } 629 *beta = plex->metricCtx->gradationFactor; 630 PetscFunctionReturn(0); 631 } 632 633 /* 634 DMPlexMetricSetVerbosity - Set the verbosity of the mesh adaptation package 635 636 Input parameters: 637 + dm - The DM 638 - verbosity - The verbosity, where -1 is silent and 10 is maximum 639 640 .seealso: DMPlexMetricGetVerbosity(), DMPlexMetricSetNumIterations() 641 */ 642 PetscErrorCode DMPlexMetricSetVerbosity(DM dm, PetscInt verbosity) 643 { 644 DM_Plex *plex = (DM_Plex *) dm->data; 645 PetscErrorCode ierr; 646 647 PetscFunctionBegin; 648 if (!plex->metricCtx) { 649 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 650 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 651 } 652 plex->metricCtx->verbosity = verbosity; 653 PetscFunctionReturn(0); 654 } 655 656 /* 657 DMPlexMetricGetVerbosity - Get the verbosity of the mesh adaptation package 658 659 Input parameters: 660 . dm - The DM 661 662 Output parameters: 663 . verbosity - The verbosity, where -1 is silent and 10 is maximum 664 665 .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations() 666 */ 667 PetscErrorCode DMPlexMetricGetVerbosity(DM dm, PetscInt *verbosity) 668 { 669 DM_Plex *plex = (DM_Plex *) dm->data; 670 PetscErrorCode ierr; 671 672 PetscFunctionBegin; 673 if (!plex->metricCtx) { 674 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 675 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 676 } 677 *verbosity = plex->metricCtx->verbosity; 678 PetscFunctionReturn(0); 679 } 680 681 /* 682 DMPlexMetricSetNumIterations - Set the number of parallel adaptation iterations 683 684 Input parameters: 685 + dm - The DM 686 - numIter - the number of parallel adaptation iterations 687 688 Note: This option is only used by ParMmg, not Mmg or Pragmatic. 689 690 .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations() 691 */ 692 PetscErrorCode DMPlexMetricSetNumIterations(DM dm, PetscInt numIter) 693 { 694 DM_Plex *plex = (DM_Plex *) dm->data; 695 PetscErrorCode ierr; 696 697 PetscFunctionBegin; 698 if (!plex->metricCtx) { 699 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 700 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 701 } 702 plex->metricCtx->numIter = numIter; 703 PetscFunctionReturn(0); 704 } 705 706 /* 707 DMPlexMetricGetNumIterations - Get the number of parallel adaptation iterations 708 709 Input parameters: 710 . dm - The DM 711 712 Output parameters: 713 . numIter - the number of parallel adaptation iterations 714 715 Note: This option is only used by ParMmg, not Mmg or Pragmatic. 716 717 .seealso: DMPlexMetricSetNumIterations(), DMPlexMetricGetVerbosity() 718 */ 719 PetscErrorCode DMPlexMetricGetNumIterations(DM dm, PetscInt *numIter) 720 { 721 DM_Plex *plex = (DM_Plex *) dm->data; 722 PetscErrorCode ierr; 723 724 PetscFunctionBegin; 725 if (!plex->metricCtx) { 726 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 727 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 728 } 729 *numIter = plex->metricCtx->numIter; 730 PetscFunctionReturn(0); 731 } 732 733 PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric) 734 { 735 MPI_Comm comm; 736 PetscErrorCode ierr; 737 PetscFE fe; 738 PetscInt dim; 739 740 PetscFunctionBegin; 741 742 /* Extract metadata from dm */ 743 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 744 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 745 746 /* Create a P1 field of the requested size */ 747 ierr = PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe);CHKERRQ(ierr); 748 ierr = DMSetField(dm, f, NULL, (PetscObject)fe);CHKERRQ(ierr); 749 ierr = DMCreateDS(dm);CHKERRQ(ierr); 750 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 751 ierr = DMCreateLocalVector(dm, metric);CHKERRQ(ierr); 752 753 PetscFunctionReturn(0); 754 } 755 756 /* 757 DMPlexMetricCreate - Create a Riemannian metric field 758 759 Input parameters: 760 + dm - The DM 761 - f - The field number to use 762 763 Output parameter: 764 . metric - The metric 765 766 Level: beginner 767 768 Notes: 769 770 It is assumed that the DM is comprised of simplices. 771 772 Command line options for Riemannian metrics: 773 774 -dm_plex_metric_isotropic - Is the metric isotropic? 775 -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 776 -dm_plex_metric_h_min - Minimum tolerated metric magnitude 777 -dm_plex_metric_h_max - Maximum tolerated metric magnitude 778 -dm_plex_metric_a_max - Maximum tolerated anisotropy 779 -dm_plex_metric_p - L-p normalization order 780 -dm_plex_metric_target_complexity - Target metric complexity 781 782 .seealso: DMPlexMetricCreateUniform(), DMPlexMetricCreateIsotropic() 783 */ 784 PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric) 785 { 786 DM_Plex *plex = (DM_Plex *) dm->data; 787 PetscErrorCode ierr; 788 PetscInt coordDim, Nd; 789 790 PetscFunctionBegin; 791 if (!plex->metricCtx) { 792 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 793 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 794 } 795 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 796 Nd = coordDim*coordDim; 797 ierr = DMPlexP1FieldCreate_Private(dm, f, Nd, metric);CHKERRQ(ierr); 798 PetscFunctionReturn(0); 799 } 800 801 typedef struct { 802 PetscReal scaling; /* Scaling for uniform metric diagonal */ 803 } DMPlexMetricUniformCtx; 804 805 static PetscErrorCode diagonal(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 806 { 807 DMPlexMetricUniformCtx *user = (DMPlexMetricUniformCtx*)ctx; 808 PetscInt i, j; 809 810 for (i = 0; i < dim; ++i) { 811 for (j = 0; j < dim; ++j) { 812 if (i == j) u[i+dim*j] = user->scaling; 813 else u[i+dim*j] = 0.0; 814 } 815 } 816 return 0; 817 } 818 819 /* 820 DMPlexMetricCreateUniform - Construct a uniform isotropic metric 821 822 Input parameters: 823 + dm - The DM 824 . f - The field number to use 825 - alpha - Scaling parameter for the diagonal 826 827 Output parameter: 828 . metric - The uniform metric 829 830 Level: beginner 831 832 Note: It is assumed that the DM is comprised of simplices. 833 834 .seealso: DMPlexMetricCreate(), DMPlexMetricCreateIsotropic() 835 */ 836 PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric) 837 { 838 DMPlexMetricUniformCtx user; 839 PetscErrorCode (*funcs[1])(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *); 840 PetscErrorCode ierr; 841 void *ctxs[1]; 842 843 PetscFunctionBegin; 844 ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr); 845 if (!alpha) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined"); 846 if (alpha < 1.0e-30) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling %e should be positive", alpha); 847 else user.scaling = alpha; 848 funcs[0] = diagonal; 849 ctxs[0] = &user; 850 ierr = DMProjectFunctionLocal(dm, 0.0, funcs, ctxs, INSERT_ALL_VALUES, *metric);CHKERRQ(ierr); 851 PetscFunctionReturn(0); 852 } 853 854 /* 855 DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator 856 857 Input parameters: 858 + dm - The DM 859 . f - The field number to use 860 - indicator - The error indicator 861 862 Output parameter: 863 . metric - The isotropic metric 864 865 Level: beginner 866 867 Notes: 868 869 It is assumed that the DM is comprised of simplices. 870 871 The indicator needs to be a scalar field defined at *vertices*. 872 873 .seealso: DMPlexMetricCreate(), DMPlexMetricCreateUniform() 874 */ 875 PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric) 876 { 877 DM dmIndi; 878 PetscErrorCode ierr; 879 PetscInt dim, d, vStart, vEnd, v; 880 const PetscScalar *indi; 881 PetscScalar *met; 882 883 PetscFunctionBegin; 884 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 885 ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr); 886 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 887 ierr = VecGetArrayRead(indicator, &indi);CHKERRQ(ierr); 888 ierr = VecGetArrayWrite(*metric, &met);CHKERRQ(ierr); 889 ierr = VecGetDM(indicator, &dmIndi);CHKERRQ(ierr); 890 for (v = vStart; v < vEnd; ++v) { 891 PetscScalar *vindi, *vmet; 892 ierr = DMPlexPointLocalRead(dmIndi, v, indi, &vindi);CHKERRQ(ierr); 893 ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr); 894 for (d = 0; d < dim; ++d) vmet[d*(dim+1)] = vindi[0]; 895 } 896 ierr = VecRestoreArrayWrite(*metric, &met);CHKERRQ(ierr); 897 ierr = VecRestoreArrayRead(indicator, &indi);CHKERRQ(ierr); 898 PetscFunctionReturn(0); 899 } 900 901 static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[]) 902 { 903 PetscErrorCode ierr; 904 PetscInt i, j, k; 905 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); 906 PetscScalar *Mpos; 907 908 PetscFunctionBegin; 909 ierr = PetscMalloc2(dim*dim, &Mpos, dim, &eigs);CHKERRQ(ierr); 910 911 /* Symmetrize */ 912 for (i = 0; i < dim; ++i) { 913 Mpos[i*dim+i] = Mp[i*dim+i]; 914 for (j = i+1; j < dim; ++j) { 915 Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 916 Mpos[j*dim+i] = Mpos[i*dim+j]; 917 } 918 } 919 920 /* Compute eigendecomposition */ 921 { 922 PetscScalar *work; 923 PetscBLASInt lwork; 924 925 lwork = 5*dim; 926 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 927 { 928 PetscBLASInt lierr; 929 PetscBLASInt nb; 930 931 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 932 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 933 #if defined(PETSC_USE_COMPLEX) 934 { 935 PetscReal *rwork; 936 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 937 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr)); 938 ierr = PetscFree(rwork);CHKERRQ(ierr); 939 } 940 #else 941 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr)); 942 #endif 943 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 944 ierr = PetscFPTrapPop();CHKERRQ(ierr); 945 } 946 ierr = PetscFree(work);CHKERRQ(ierr); 947 } 948 949 /* Reflect to positive orthant and enforce maximum and minimum size */ 950 max_eig = 0.0; 951 for (i = 0; i < dim; ++i) { 952 eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i]))); 953 max_eig = PetscMax(eigs[i], max_eig); 954 } 955 956 /* Enforce maximum anisotropy */ 957 for (i = 0; i < dim; ++i) { 958 if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min); 959 } 960 961 /* Reconstruct Hessian */ 962 for (i = 0; i < dim; ++i) { 963 for (j = 0; j < dim; ++j) { 964 Mp[i*dim+j] = 0.0; 965 for (k = 0; k < dim; ++k) { 966 Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j]; 967 } 968 } 969 } 970 ierr = PetscFree2(Mpos, eigs);CHKERRQ(ierr); 971 972 PetscFunctionReturn(0); 973 } 974 975 /* 976 DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric 977 978 Input parameters: 979 + dm - The DM 980 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 981 . restrictAnisotropy - Should maximum anisotropy be enforced? 982 - metric - The metric 983 984 Output parameter: 985 . metric - The metric 986 987 Level: beginner 988 989 .seealso: DMPlexMetricNormalize(), DMPlexMetricIntersection() 990 */ 991 PetscErrorCode DMPlexMetricEnforceSPD(DM dm, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metric) 992 { 993 PetscErrorCode ierr; 994 PetscInt dim, vStart, vEnd, v; 995 PetscScalar *met; 996 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0; 997 998 PetscFunctionBegin; 999 1000 /* Extract metadata from dm */ 1001 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1002 if (restrictSizes) { 1003 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 1004 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 1005 h_min = PetscMax(h_min, 1.0e-30); 1006 h_max = PetscMin(h_max, 1.0e+30); 1007 if (h_min >= h_max) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max); 1008 } 1009 if (restrictAnisotropy) { 1010 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 1011 a_max = PetscMin(a_max, 1.0e+30); 1012 } 1013 1014 /* Enforce SPD */ 1015 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1016 ierr = VecGetArray(metric, &met);CHKERRQ(ierr); 1017 for (v = vStart; v < vEnd; ++v) { 1018 PetscScalar *vmet; 1019 ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr); 1020 ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, vmet);CHKERRQ(ierr); 1021 } 1022 ierr = VecRestoreArray(metric, &met);CHKERRQ(ierr); 1023 1024 PetscFunctionReturn(0); 1025 } 1026 1027 static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 1028 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 1029 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 1030 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 1031 { 1032 const PetscScalar p = constants[0]; 1033 PetscReal detH = 0.0; 1034 1035 if (dim == 2) DMPlex_Det2D_Scalar_Internal(&detH, u); 1036 else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detH, u); 1037 f0[0] = PetscPowReal(detH, p/(2.0*p + dim)); 1038 } 1039 1040 /* 1041 DMPlexMetricNormalize - Apply L-p normalization to a metric 1042 1043 Input parameters: 1044 + dm - The DM 1045 . metricIn - The unnormalized metric 1046 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 1047 - restrictAnisotropy - Should maximum metric anisotropy be enforced? 1048 1049 Output parameter: 1050 . metricOut - The normalized metric 1051 1052 Level: beginner 1053 1054 .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection() 1055 */ 1056 PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut) 1057 { 1058 MPI_Comm comm; 1059 PetscBool restrictAnisotropyFirst; 1060 PetscDS ds; 1061 PetscErrorCode ierr; 1062 PetscInt dim, Nd, vStart, vEnd, v, i; 1063 PetscScalar *met, integral, constants[1]; 1064 PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, target; 1065 1066 PetscFunctionBegin; 1067 1068 /* Extract metadata from dm */ 1069 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 1070 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1071 Nd = dim*dim; 1072 1073 /* Set up metric and ensure it is SPD */ 1074 ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr); 1075 ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr); 1076 ierr = DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst);CHKERRQ(ierr); 1077 ierr = DMPlexMetricEnforceSPD(dm, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), *metricOut);CHKERRQ(ierr); 1078 1079 /* Compute global normalization factor */ 1080 ierr = DMPlexMetricGetTargetComplexity(dm, &target);CHKERRQ(ierr); 1081 ierr = DMPlexMetricGetNormalizationOrder(dm, &p);CHKERRQ(ierr); 1082 constants[0] = p; 1083 ierr = DMGetDS(dm, &ds);CHKERRQ(ierr); 1084 ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr); 1085 ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr); 1086 ierr = DMPlexComputeIntegralFEM(dm, *metricOut, &integral, NULL);CHKERRQ(ierr); 1087 factGlob = PetscPowReal(target/PetscRealPart(integral), 2.0/dim); 1088 1089 /* Apply local scaling */ 1090 if (restrictSizes) { 1091 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 1092 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 1093 h_min = PetscMax(h_min, 1.0e-30); 1094 h_max = PetscMin(h_max, 1.0e+30); 1095 if (h_min >= h_max) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max); 1096 } 1097 if (restrictAnisotropy && !restrictAnisotropyFirst) { 1098 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 1099 a_max = PetscMin(a_max, 1.0e+30); 1100 } 1101 ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr); 1102 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1103 for (v = vStart; v < vEnd; ++v) { 1104 PetscScalar *Mp; 1105 PetscReal detM, fact; 1106 1107 ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr); 1108 if (dim == 2) DMPlex_Det2D_Scalar_Internal(&detM, Mp); 1109 else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detM, Mp); 1110 else SETERRQ1(comm, PETSC_ERR_SUP, "Dimension %d not supported", dim); 1111 fact = factGlob * PetscPowReal(PetscAbsReal(detM), -1.0/(2*p+dim)); 1112 for (i = 0; i < Nd; ++i) Mp[i] *= fact; 1113 if (restrictSizes) { ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, Mp);CHKERRQ(ierr); } 1114 } 1115 ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr); 1116 1117 PetscFunctionReturn(0); 1118 } 1119 1120 /* 1121 DMPlexMetricAverage - Compute the average of a list of metrics 1122 1123 Input Parameter: 1124 + dm - The DM 1125 . numMetrics - The number of metrics to be averaged 1126 . weights - Weights for the average 1127 - metrics - The metrics to be averaged 1128 1129 Output Parameter: 1130 . metricAvg - The averaged metric 1131 1132 Level: beginner 1133 1134 Notes: 1135 The weights should sum to unity. 1136 1137 If weights are not provided then an unweighted average is used. 1138 1139 .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection() 1140 */ 1141 PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg) 1142 { 1143 PetscBool haveWeights = PETSC_TRUE; 1144 PetscErrorCode ierr; 1145 PetscInt i; 1146 PetscReal sum = 0.0, tol = 1.0e-10; 1147 1148 PetscFunctionBegin; 1149 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics); } 1150 ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr); 1151 ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr); 1152 1153 /* Default to the unweighted case */ 1154 if (!weights) { 1155 ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr); 1156 haveWeights = PETSC_FALSE; 1157 for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; } 1158 } 1159 1160 /* Check weights sum to unity */ 1161 for (i = 0; i < numMetrics; ++i) { sum += weights[i]; } 1162 if (PetscAbsReal(sum - 1) > tol) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); } 1163 1164 /* Compute metric average */ 1165 for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); } 1166 if (!haveWeights) {ierr = PetscFree(weights); } 1167 PetscFunctionReturn(0); 1168 } 1169 1170 /* 1171 DMPlexMetricAverage2 - Compute the unweighted average of two metrics 1172 1173 Input Parameter: 1174 + dm - The DM 1175 . metric1 - The first metric to be averaged 1176 - metric2 - The second metric to be averaged 1177 1178 Output Parameter: 1179 . metricAvg - The averaged metric 1180 1181 Level: beginner 1182 1183 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3() 1184 */ 1185 PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg) 1186 { 1187 PetscErrorCode ierr; 1188 PetscReal weights[2] = {0.5, 0.5}; 1189 Vec metrics[2] = {metric1, metric2}; 1190 1191 PetscFunctionBegin; 1192 ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr); 1193 PetscFunctionReturn(0); 1194 } 1195 1196 /* 1197 DMPlexMetricAverage3 - Compute the unweighted average of three metrics 1198 1199 Input Parameter: 1200 + dm - The DM 1201 . metric1 - The first metric to be averaged 1202 . metric2 - The second metric to be averaged 1203 - metric3 - The third metric to be averaged 1204 1205 Output Parameter: 1206 . metricAvg - The averaged metric 1207 1208 Level: beginner 1209 1210 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2() 1211 */ 1212 PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg) 1213 { 1214 PetscErrorCode ierr; 1215 PetscReal weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0}; 1216 Vec metrics[3] = {metric1, metric2, metric3}; 1217 1218 PetscFunctionBegin; 1219 ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr); 1220 PetscFunctionReturn(0); 1221 } 1222 1223 static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 1224 { 1225 PetscErrorCode ierr; 1226 PetscInt i, j, k, l, m; 1227 PetscReal *evals, *evals1; 1228 PetscScalar *evecs, *sqrtM1, *isqrtM1; 1229 1230 PetscFunctionBegin; 1231 ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr); 1232 for (i = 0; i < dim; ++i) { 1233 for (j = 0; j < dim; ++j) { 1234 evecs[i*dim+j] = M1[i*dim+j]; 1235 } 1236 } 1237 { 1238 PetscScalar *work; 1239 PetscBLASInt lwork; 1240 1241 lwork = 5*dim; 1242 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 1243 { 1244 PetscBLASInt lierr, nb; 1245 PetscReal sqrtk; 1246 1247 /* Compute eigendecomposition of M1 */ 1248 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 1249 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1250 #if defined(PETSC_USE_COMPLEX) 1251 { 1252 PetscReal *rwork; 1253 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 1254 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr)); 1255 ierr = PetscFree(rwork);CHKERRQ(ierr); 1256 } 1257 #else 1258 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr)); 1259 #endif 1260 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 1261 ierr = PetscFPTrapPop(); 1262 1263 /* Compute square root and reciprocal */ 1264 for (i = 0; i < dim; ++i) { 1265 for (j = 0; j < dim; ++j) { 1266 sqrtM1[i*dim+j] = 0.0; 1267 isqrtM1[i*dim+j] = 0.0; 1268 for (k = 0; k < dim; ++k) { 1269 sqrtk = PetscSqrtReal(evals1[k]); 1270 sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j]; 1271 isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j]; 1272 } 1273 } 1274 } 1275 1276 /* Map into the space spanned by the eigenvectors of M1 */ 1277 for (i = 0; i < dim; ++i) { 1278 for (j = 0; j < dim; ++j) { 1279 evecs[i*dim+j] = 0.0; 1280 for (k = 0; k < dim; ++k) { 1281 for (l = 0; l < dim; ++l) { 1282 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l]; 1283 } 1284 } 1285 } 1286 } 1287 1288 /* Compute eigendecomposition */ 1289 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1290 #if defined(PETSC_USE_COMPLEX) 1291 { 1292 PetscReal *rwork; 1293 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 1294 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 1295 ierr = PetscFree(rwork);CHKERRQ(ierr); 1296 } 1297 #else 1298 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 1299 #endif 1300 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 1301 ierr = PetscFPTrapPop(); 1302 1303 /* Modify eigenvalues */ 1304 for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]); 1305 1306 /* Map back to get the intersection */ 1307 for (i = 0; i < dim; ++i) { 1308 for (j = 0; j < dim; ++j) { 1309 M2[i*dim+j] = 0.0; 1310 for (k = 0; k < dim; ++k) { 1311 for (l = 0; l < dim; ++l) { 1312 for (m = 0; m < dim; ++m) { 1313 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m]; 1314 } 1315 } 1316 } 1317 } 1318 } 1319 } 1320 ierr = PetscFree(work);CHKERRQ(ierr); 1321 } 1322 ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr); 1323 PetscFunctionReturn(0); 1324 } 1325 1326 /* 1327 DMPlexMetricIntersection - Compute the intersection of a list of metrics 1328 1329 Input Parameter: 1330 + dm - The DM 1331 . numMetrics - The number of metrics to be intersected 1332 - metrics - The metrics to be intersected 1333 1334 Output Parameter: 1335 . metricInt - The intersected metric 1336 1337 Level: beginner 1338 1339 Notes: 1340 1341 The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics. 1342 1343 The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2. 1344 1345 .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage() 1346 */ 1347 PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt) 1348 { 1349 PetscErrorCode ierr; 1350 PetscInt dim, vStart, vEnd, v, i; 1351 PetscScalar *met, *meti, *M, *Mi; 1352 1353 PetscFunctionBegin; 1354 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics); } 1355 1356 /* Extract metadata from dm */ 1357 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1358 ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr); 1359 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1360 1361 /* Copy over the first metric */ 1362 ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr); 1363 1364 /* Intersect subsequent metrics in turn */ 1365 if (numMetrics > 1) { 1366 ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr); 1367 for (i = 1; i < numMetrics; ++i) { 1368 ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr); 1369 for (v = vStart; v < vEnd; ++v) { 1370 ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr); 1371 ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr); 1372 ierr = DMPlexMetricIntersection_Private(dim, Mi, M);CHKERRQ(ierr); 1373 } 1374 ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr); 1375 } 1376 ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr); 1377 } 1378 1379 PetscFunctionReturn(0); 1380 } 1381 1382 /* 1383 DMPlexMetricIntersection2 - Compute the intersection of two metrics 1384 1385 Input Parameter: 1386 + dm - The DM 1387 . metric1 - The first metric to be intersected 1388 - metric2 - The second metric to be intersected 1389 1390 Output Parameter: 1391 . metricInt - The intersected metric 1392 1393 Level: beginner 1394 1395 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3() 1396 */ 1397 PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt) 1398 { 1399 PetscErrorCode ierr; 1400 Vec metrics[2] = {metric1, metric2}; 1401 1402 PetscFunctionBegin; 1403 ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr); 1404 PetscFunctionReturn(0); 1405 } 1406 1407 /* 1408 DMPlexMetricIntersection3 - Compute the intersection of three metrics 1409 1410 Input Parameter: 1411 + dm - The DM 1412 . metric1 - The first metric to be intersected 1413 . metric2 - The second metric to be intersected 1414 - metric3 - The third metric to be intersected 1415 1416 Output Parameter: 1417 . metricInt - The intersected metric 1418 1419 Level: beginner 1420 1421 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2() 1422 */ 1423 PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt) 1424 { 1425 PetscErrorCode ierr; 1426 Vec metrics[3] = {metric1, metric2, metric3}; 1427 1428 PetscFunctionBegin; 1429 ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr); 1430 PetscFunctionReturn(0); 1431 } 1432