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 LAPACKsyevFail(PetscInt dim, PetscScalar Mpos[]) 902 { 903 PetscInt i, j; 904 905 PetscFunctionBegin; 906 PetscPrintf(PETSC_COMM_SELF, "Failed to apply LAPACKsyev to the matrix\n"); 907 for (i = 0; i < dim; ++i) { 908 if (i == 0) PetscPrintf(PETSC_COMM_SELF, " [["); 909 else PetscPrintf(PETSC_COMM_SELF, " ["); 910 for (j = 0; j < dim; ++j) { 911 if (j < dim-1) PetscPrintf(PETSC_COMM_SELF, "%15.8e, ", Mpos[i*dim+j]); 912 else PetscPrintf(PETSC_COMM_SELF, "%15.8e", Mpos[i*dim+j]); 913 } 914 if (i < dim-1) PetscPrintf(PETSC_COMM_SELF, "]\n"); 915 else PetscPrintf(PETSC_COMM_SELF, "]]\n"); 916 } 917 PetscFunctionReturn(0); 918 } 919 920 static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[], PetscScalar *detMp) 921 { 922 PetscErrorCode ierr; 923 PetscInt i, j, k; 924 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); 925 PetscScalar *Mpos; 926 927 PetscFunctionBegin; 928 ierr = PetscMalloc2(dim*dim, &Mpos, dim, &eigs);CHKERRQ(ierr); 929 930 /* Symmetrize */ 931 for (i = 0; i < dim; ++i) { 932 Mpos[i*dim+i] = Mp[i*dim+i]; 933 for (j = i+1; j < dim; ++j) { 934 Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 935 Mpos[j*dim+i] = Mpos[i*dim+j]; 936 } 937 } 938 939 /* Compute eigendecomposition */ 940 { 941 PetscScalar *work; 942 PetscBLASInt lwork; 943 944 lwork = 5*dim; 945 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 946 { 947 PetscBLASInt lierr; 948 PetscBLASInt nb; 949 950 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 951 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 952 #if defined(PETSC_USE_COMPLEX) 953 { 954 PetscReal *rwork; 955 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 956 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr)); 957 ierr = PetscFree(rwork);CHKERRQ(ierr); 958 } 959 #else 960 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr)); 961 #endif 962 if (lierr) { 963 for (i = 0; i < dim; ++i) { 964 Mpos[i*dim+i] = Mp[i*dim+i]; 965 for (j = i+1; j < dim; ++j) { 966 Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 967 Mpos[j*dim+i] = Mpos[i*dim+j]; 968 } 969 } 970 LAPACKsyevFail(dim, Mpos); 971 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 972 } 973 ierr = PetscFPTrapPop();CHKERRQ(ierr); 974 } 975 ierr = PetscFree(work);CHKERRQ(ierr); 976 } 977 978 /* Reflect to positive orthant and enforce maximum and minimum size */ 979 max_eig = 0.0; 980 for (i = 0; i < dim; ++i) { 981 eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i]))); 982 max_eig = PetscMax(eigs[i], max_eig); 983 } 984 985 /* Enforce maximum anisotropy and compute determinant */ 986 *detMp = 1.0; 987 for (i = 0; i < dim; ++i) { 988 if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min); 989 *detMp *= eigs[i]; 990 } 991 992 /* Reconstruct Hessian */ 993 for (i = 0; i < dim; ++i) { 994 for (j = 0; j < dim; ++j) { 995 Mp[i*dim+j] = 0.0; 996 for (k = 0; k < dim; ++k) { 997 Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j]; 998 } 999 } 1000 } 1001 ierr = PetscFree2(Mpos, eigs);CHKERRQ(ierr); 1002 1003 PetscFunctionReturn(0); 1004 } 1005 1006 /* 1007 DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric 1008 1009 Input parameters: 1010 + dm - The DM 1011 . metricIn - The metric 1012 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 1013 - restrictAnisotropy - Should maximum anisotropy be enforced? 1014 1015 Output parameter: 1016 + metricOut - The metric 1017 - determinant - Its determinant 1018 1019 Level: beginner 1020 1021 .seealso: DMPlexMetricNormalize(), DMPlexMetricIntersection() 1022 */ 1023 PetscErrorCode DMPlexMetricEnforceSPD(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut, Vec *determinant) 1024 { 1025 DM dmDet; 1026 PetscErrorCode ierr; 1027 PetscInt dim, vStart, vEnd, v; 1028 PetscScalar *met, *det; 1029 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0; 1030 1031 PetscFunctionBegin; 1032 1033 /* Extract metadata from dm */ 1034 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1035 if (restrictSizes) { 1036 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 1037 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 1038 h_min = PetscMax(h_min, 1.0e-30); 1039 h_max = PetscMin(h_max, 1.0e+30); 1040 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); 1041 } 1042 if (restrictAnisotropy) { 1043 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 1044 a_max = PetscMin(a_max, 1.0e+30); 1045 } 1046 1047 /* Setup output metric and determinant */ 1048 ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr); 1049 ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr); 1050 ierr = DMClone(dm, &dmDet);CHKERRQ(ierr); 1051 ierr = DMPlexP1FieldCreate_Private(dmDet, 0, 1, determinant);CHKERRQ(ierr); 1052 1053 /* Enforce SPD */ 1054 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1055 ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr); 1056 ierr = VecGetArray(*determinant, &det);CHKERRQ(ierr); 1057 for (v = vStart; v < vEnd; ++v) { 1058 PetscScalar *vmet, *vdet; 1059 ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr); 1060 ierr = DMPlexPointLocalRef(dmDet, v, det, &vdet);CHKERRQ(ierr); 1061 ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, vmet, vdet);CHKERRQ(ierr); 1062 } 1063 ierr = VecRestoreArray(*determinant, &det);CHKERRQ(ierr); 1064 ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr); 1065 1066 PetscFunctionReturn(0); 1067 } 1068 1069 static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 1070 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 1071 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 1072 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 1073 { 1074 const PetscScalar p = constants[0]; 1075 1076 f0[0] = PetscPowReal(u[0], p/(2.0*p + dim)); 1077 } 1078 1079 /* 1080 DMPlexMetricNormalize - Apply L-p normalization to a metric 1081 1082 Input parameters: 1083 + dm - The DM 1084 . metricIn - The unnormalized metric 1085 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 1086 - restrictAnisotropy - Should maximum metric anisotropy be enforced? 1087 1088 Output parameter: 1089 . metricOut - The normalized metric 1090 1091 Level: beginner 1092 1093 .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection() 1094 */ 1095 PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut) 1096 { 1097 DM dmDet; 1098 MPI_Comm comm; 1099 PetscBool restrictAnisotropyFirst; 1100 PetscDS ds; 1101 PetscErrorCode ierr; 1102 PetscInt dim, Nd, vStart, vEnd, v, i; 1103 PetscScalar *met, *det, integral, constants[1]; 1104 PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, target, realIntegral; 1105 Vec determinant; 1106 1107 PetscFunctionBegin; 1108 1109 /* Extract metadata from dm */ 1110 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 1111 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1112 Nd = dim*dim; 1113 1114 /* Set up metric and ensure it is SPD */ 1115 ierr = DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst);CHKERRQ(ierr); 1116 ierr = DMPlexMetricEnforceSPD(dm, metricIn, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), metricOut, &determinant);CHKERRQ(ierr); 1117 1118 /* Compute global normalization factor */ 1119 ierr = DMPlexMetricGetTargetComplexity(dm, &target);CHKERRQ(ierr); 1120 ierr = DMPlexMetricGetNormalizationOrder(dm, &p);CHKERRQ(ierr); 1121 constants[0] = p; 1122 ierr = VecGetDM(determinant, &dmDet);CHKERRQ(ierr); 1123 ierr = DMGetDS(dmDet, &ds);CHKERRQ(ierr); 1124 ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr); 1125 ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr); 1126 ierr = DMPlexComputeIntegralFEM(dmDet, determinant, &integral, NULL);CHKERRQ(ierr); 1127 realIntegral = PetscRealPart(integral); 1128 if (realIntegral < 1.0e-30) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global metric normalization factor should be strictly positive, not %.4e Is the input metric positive-definite?", realIntegral); 1129 factGlob = PetscPowReal(target/realIntegral, 2.0/dim); 1130 1131 /* Apply local scaling */ 1132 if (restrictSizes) { 1133 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 1134 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 1135 h_min = PetscMax(h_min, 1.0e-30); 1136 h_max = PetscMin(h_max, 1.0e+30); 1137 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); 1138 } 1139 if (restrictAnisotropy && !restrictAnisotropyFirst) { 1140 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 1141 a_max = PetscMin(a_max, 1.0e+30); 1142 } 1143 ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr); 1144 ierr = VecGetArray(determinant, &det);CHKERRQ(ierr); 1145 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1146 for (v = vStart; v < vEnd; ++v) { 1147 PetscScalar *Mp, *detM; 1148 PetscReal fact; 1149 1150 ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr); 1151 ierr = DMPlexPointLocalRef(dmDet, v, det, &detM);CHKERRQ(ierr); 1152 fact = factGlob * PetscPowReal(PetscAbsScalar(detM[0]), -1.0/(2*p+dim)); 1153 for (i = 0; i < Nd; ++i) Mp[i] *= fact; 1154 if (restrictSizes) { ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, Mp, detM);CHKERRQ(ierr); } 1155 } 1156 ierr = VecRestoreArray(determinant, &det);CHKERRQ(ierr); 1157 ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr); 1158 ierr = VecDestroy(&determinant);CHKERRQ(ierr); 1159 ierr = DMDestroy(&dmDet);CHKERRQ(ierr); 1160 1161 PetscFunctionReturn(0); 1162 } 1163 1164 /* 1165 DMPlexMetricAverage - Compute the average of a list of metrics 1166 1167 Input Parameter: 1168 + dm - The DM 1169 . numMetrics - The number of metrics to be averaged 1170 . weights - Weights for the average 1171 - metrics - The metrics to be averaged 1172 1173 Output Parameter: 1174 . metricAvg - The averaged metric 1175 1176 Level: beginner 1177 1178 Notes: 1179 The weights should sum to unity. 1180 1181 If weights are not provided then an unweighted average is used. 1182 1183 .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection() 1184 */ 1185 PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg) 1186 { 1187 PetscBool haveWeights = PETSC_TRUE; 1188 PetscErrorCode ierr; 1189 PetscInt i; 1190 PetscReal sum = 0.0, tol = 1.0e-10; 1191 1192 PetscFunctionBegin; 1193 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics); } 1194 ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr); 1195 ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr); 1196 1197 /* Default to the unweighted case */ 1198 if (!weights) { 1199 ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr); 1200 haveWeights = PETSC_FALSE; 1201 for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; } 1202 } 1203 1204 /* Check weights sum to unity */ 1205 for (i = 0; i < numMetrics; ++i) { sum += weights[i]; } 1206 if (PetscAbsReal(sum - 1) > tol) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); } 1207 1208 /* Compute metric average */ 1209 for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); } 1210 if (!haveWeights) {ierr = PetscFree(weights); } 1211 PetscFunctionReturn(0); 1212 } 1213 1214 /* 1215 DMPlexMetricAverage2 - Compute the unweighted average of two metrics 1216 1217 Input Parameter: 1218 + dm - The DM 1219 . metric1 - The first metric to be averaged 1220 - metric2 - The second metric to be averaged 1221 1222 Output Parameter: 1223 . metricAvg - The averaged metric 1224 1225 Level: beginner 1226 1227 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3() 1228 */ 1229 PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg) 1230 { 1231 PetscErrorCode ierr; 1232 PetscReal weights[2] = {0.5, 0.5}; 1233 Vec metrics[2] = {metric1, metric2}; 1234 1235 PetscFunctionBegin; 1236 ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr); 1237 PetscFunctionReturn(0); 1238 } 1239 1240 /* 1241 DMPlexMetricAverage3 - Compute the unweighted average of three metrics 1242 1243 Input Parameter: 1244 + dm - The DM 1245 . metric1 - The first metric to be averaged 1246 . metric2 - The second metric to be averaged 1247 - metric3 - The third metric to be averaged 1248 1249 Output Parameter: 1250 . metricAvg - The averaged metric 1251 1252 Level: beginner 1253 1254 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2() 1255 */ 1256 PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg) 1257 { 1258 PetscErrorCode ierr; 1259 PetscReal weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0}; 1260 Vec metrics[3] = {metric1, metric2, metric3}; 1261 1262 PetscFunctionBegin; 1263 ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr); 1264 PetscFunctionReturn(0); 1265 } 1266 1267 static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 1268 { 1269 PetscErrorCode ierr; 1270 PetscInt i, j, k, l, m; 1271 PetscReal *evals, *evals1; 1272 PetscScalar *evecs, *sqrtM1, *isqrtM1; 1273 1274 PetscFunctionBegin; 1275 ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr); 1276 for (i = 0; i < dim; ++i) { 1277 for (j = 0; j < dim; ++j) { 1278 evecs[i*dim+j] = M1[i*dim+j]; 1279 } 1280 } 1281 { 1282 PetscScalar *work; 1283 PetscBLASInt lwork; 1284 1285 lwork = 5*dim; 1286 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 1287 { 1288 PetscBLASInt lierr, nb; 1289 PetscReal sqrtk; 1290 1291 /* Compute eigendecomposition of M1 */ 1292 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 1293 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1294 #if defined(PETSC_USE_COMPLEX) 1295 { 1296 PetscReal *rwork; 1297 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 1298 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr)); 1299 ierr = PetscFree(rwork);CHKERRQ(ierr); 1300 } 1301 #else 1302 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr)); 1303 #endif 1304 if (lierr) { 1305 LAPACKsyevFail(dim, M1); 1306 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 1307 } 1308 ierr = PetscFPTrapPop(); 1309 1310 /* Compute square root and reciprocal */ 1311 for (i = 0; i < dim; ++i) { 1312 for (j = 0; j < dim; ++j) { 1313 sqrtM1[i*dim+j] = 0.0; 1314 isqrtM1[i*dim+j] = 0.0; 1315 for (k = 0; k < dim; ++k) { 1316 sqrtk = PetscSqrtReal(evals1[k]); 1317 sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j]; 1318 isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j]; 1319 } 1320 } 1321 } 1322 1323 /* Map into the space spanned by the eigenvectors of M1 */ 1324 for (i = 0; i < dim; ++i) { 1325 for (j = 0; j < dim; ++j) { 1326 evecs[i*dim+j] = 0.0; 1327 for (k = 0; k < dim; ++k) { 1328 for (l = 0; l < dim; ++l) { 1329 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l]; 1330 } 1331 } 1332 } 1333 } 1334 1335 /* Compute eigendecomposition */ 1336 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1337 #if defined(PETSC_USE_COMPLEX) 1338 { 1339 PetscReal *rwork; 1340 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 1341 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 1342 ierr = PetscFree(rwork);CHKERRQ(ierr); 1343 } 1344 #else 1345 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 1346 #endif 1347 if (lierr) { 1348 for (i = 0; i < dim; ++i) { 1349 for (j = 0; j < dim; ++j) { 1350 evecs[i*dim+j] = 0.0; 1351 for (k = 0; k < dim; ++k) { 1352 for (l = 0; l < dim; ++l) { 1353 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l]; 1354 } 1355 } 1356 } 1357 } 1358 LAPACKsyevFail(dim, evecs); 1359 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 1360 } 1361 ierr = PetscFPTrapPop(); 1362 1363 /* Modify eigenvalues */ 1364 for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]); 1365 1366 /* Map back to get the intersection */ 1367 for (i = 0; i < dim; ++i) { 1368 for (j = 0; j < dim; ++j) { 1369 M2[i*dim+j] = 0.0; 1370 for (k = 0; k < dim; ++k) { 1371 for (l = 0; l < dim; ++l) { 1372 for (m = 0; m < dim; ++m) { 1373 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m]; 1374 } 1375 } 1376 } 1377 } 1378 } 1379 } 1380 ierr = PetscFree(work);CHKERRQ(ierr); 1381 } 1382 ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr); 1383 PetscFunctionReturn(0); 1384 } 1385 1386 /* 1387 DMPlexMetricIntersection - Compute the intersection of a list of metrics 1388 1389 Input Parameter: 1390 + dm - The DM 1391 . numMetrics - The number of metrics to be intersected 1392 - metrics - The metrics to be intersected 1393 1394 Output Parameter: 1395 . metricInt - The intersected metric 1396 1397 Level: beginner 1398 1399 Notes: 1400 1401 The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics. 1402 1403 The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2. 1404 1405 .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage() 1406 */ 1407 PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt) 1408 { 1409 PetscErrorCode ierr; 1410 PetscInt dim, vStart, vEnd, v, i; 1411 PetscScalar *met, *meti, *M, *Mi; 1412 1413 PetscFunctionBegin; 1414 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics); } 1415 1416 /* Extract metadata from dm */ 1417 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1418 ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr); 1419 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1420 1421 /* Copy over the first metric */ 1422 ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr); 1423 1424 /* Intersect subsequent metrics in turn */ 1425 if (numMetrics > 1) { 1426 ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr); 1427 for (i = 1; i < numMetrics; ++i) { 1428 ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr); 1429 for (v = vStart; v < vEnd; ++v) { 1430 ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr); 1431 ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr); 1432 ierr = DMPlexMetricIntersection_Private(dim, Mi, M);CHKERRQ(ierr); 1433 } 1434 ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr); 1435 } 1436 ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr); 1437 } 1438 1439 PetscFunctionReturn(0); 1440 } 1441 1442 /* 1443 DMPlexMetricIntersection2 - Compute the intersection of two metrics 1444 1445 Input Parameter: 1446 + dm - The DM 1447 . metric1 - The first metric to be intersected 1448 - metric2 - The second metric to be intersected 1449 1450 Output Parameter: 1451 . metricInt - The intersected metric 1452 1453 Level: beginner 1454 1455 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3() 1456 */ 1457 PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt) 1458 { 1459 PetscErrorCode ierr; 1460 Vec metrics[2] = {metric1, metric2}; 1461 1462 PetscFunctionBegin; 1463 ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr); 1464 PetscFunctionReturn(0); 1465 } 1466 1467 /* 1468 DMPlexMetricIntersection3 - Compute the intersection of three metrics 1469 1470 Input Parameter: 1471 + dm - The DM 1472 . metric1 - The first metric to be intersected 1473 . metric2 - The second metric to be intersected 1474 - metric3 - The third metric to be intersected 1475 1476 Output Parameter: 1477 . metricInt - The intersected metric 1478 1479 Level: beginner 1480 1481 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2() 1482 */ 1483 PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt) 1484 { 1485 PetscErrorCode ierr; 1486 Vec metrics[3] = {metric1, metric2, metric3}; 1487 1488 PetscFunctionBegin; 1489 ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr); 1490 PetscFunctionReturn(0); 1491 } 1492