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 PetscErrorCode ierr; 9 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 1.0e+05, p = 1.0, target = 1000.0; 10 11 PetscFunctionBegin; 12 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 13 ierr = PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric");CHKERRQ(ierr); 14 ierr = PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL);CHKERRQ(ierr); 15 ierr = DMPlexMetricSetIsotropic(dm, isotropic); 16 ierr = PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL);CHKERRQ(ierr); 17 ierr = DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst); 18 ierr = PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL);CHKERRQ(ierr); 19 ierr = DMPlexMetricSetMinimumMagnitude(dm, h_min);CHKERRQ(ierr); 20 ierr = PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL);CHKERRQ(ierr); 21 ierr = DMPlexMetricSetMaximumMagnitude(dm, h_max);CHKERRQ(ierr); 22 ierr = PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL);CHKERRQ(ierr); 23 ierr = DMPlexMetricSetMaximumAnisotropy(dm, a_max);CHKERRQ(ierr); 24 ierr = PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL);CHKERRQ(ierr); 25 ierr = DMPlexMetricSetNormalizationOrder(dm, p);CHKERRQ(ierr); 26 ierr = PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL);CHKERRQ(ierr); 27 ierr = DMPlexMetricSetTargetComplexity(dm, target);CHKERRQ(ierr); 28 ierr = PetscOptionsEnd();CHKERRQ(ierr); 29 PetscFunctionReturn(0); 30 } 31 32 /* 33 DMPlexMetricSetIsotropic - Record whether a metric is isotropic 34 35 Input parameters: 36 + dm - The DM 37 - isotropic - Is the metric isotropic? 38 39 Level: beginner 40 41 .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst() 42 */ 43 PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic) 44 { 45 DM_Plex *plex = (DM_Plex *) dm->data; 46 PetscErrorCode ierr; 47 48 PetscFunctionBegin; 49 if (!plex->metricCtx) { 50 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 51 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 52 } 53 plex->metricCtx->isotropic = isotropic; 54 PetscFunctionReturn(0); 55 } 56 57 /* 58 DMPlexMetricIsIsotropic - Is a metric is isotropic? 59 60 Input parameters: 61 . dm - The DM 62 63 Output parameters: 64 . isotropic - Is the metric isotropic? 65 66 Level: beginner 67 68 .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst() 69 */ 70 PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic) 71 { 72 DM_Plex *plex = (DM_Plex *) dm->data; 73 PetscErrorCode ierr; 74 75 PetscFunctionBegin; 76 if (!plex->metricCtx) { 77 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 78 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 79 } 80 *isotropic = plex->metricCtx->isotropic; 81 PetscFunctionReturn(0); 82 } 83 84 /* 85 DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization 86 87 Input parameters: 88 + dm - The DM 89 - restrictAnisotropyFirst - Should anisotropy be normalized first? 90 91 Level: beginner 92 93 .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst() 94 */ 95 PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst) 96 { 97 DM_Plex *plex = (DM_Plex *) dm->data; 98 PetscErrorCode ierr; 99 100 PetscFunctionBegin; 101 if (!plex->metricCtx) { 102 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 103 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 104 } 105 plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst; 106 PetscFunctionReturn(0); 107 } 108 109 /* 110 DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after? 111 112 Input parameters: 113 . dm - The DM 114 115 Output parameters: 116 . restrictAnisotropyFirst - Is anisotropy be normalized first? 117 118 Level: beginner 119 120 .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst() 121 */ 122 PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst) 123 { 124 DM_Plex *plex = (DM_Plex *) dm->data; 125 PetscErrorCode ierr; 126 127 PetscFunctionBegin; 128 if (!plex->metricCtx) { 129 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 130 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 131 } 132 *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst; 133 PetscFunctionReturn(0); 134 } 135 136 /* 137 DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude 138 139 Input parameters: 140 + dm - The DM 141 - h_min - The minimum tolerated metric magnitude 142 143 Level: beginner 144 145 .seealso: DMPlexMetricGetMinimumMagnitude(), DMPlexMetricSetMaximumMagnitude() 146 */ 147 PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min) 148 { 149 DM_Plex *plex = (DM_Plex *) dm->data; 150 PetscErrorCode ierr; 151 152 PetscFunctionBegin; 153 if (!plex->metricCtx) { 154 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 155 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 156 } 157 if (h_min <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_min); 158 plex->metricCtx->h_min = h_min; 159 PetscFunctionReturn(0); 160 } 161 162 /* 163 DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude 164 165 Input parameters: 166 . dm - The DM 167 168 Input parameters: 169 . h_min - The minimum tolerated metric magnitude 170 171 Level: beginner 172 173 .seealso: DMPlexMetricSetMinimumMagnitude(), DMPlexMetricGetMaximumMagnitude() 174 */ 175 PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min) 176 { 177 DM_Plex *plex = (DM_Plex *) dm->data; 178 PetscErrorCode ierr; 179 180 PetscFunctionBegin; 181 if (!plex->metricCtx) { 182 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 183 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 184 } 185 *h_min = plex->metricCtx->h_min; 186 PetscFunctionReturn(0); 187 } 188 189 /* 190 DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude 191 192 Input parameters: 193 + dm - The DM 194 - h_max - The maximum tolerated metric magnitude 195 196 Level: beginner 197 198 .seealso: DMPlexMetricGetMaximumMagnitude(), DMPlexMetricSetMinimumMagnitude() 199 */ 200 PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max) 201 { 202 DM_Plex *plex = (DM_Plex *) dm->data; 203 PetscErrorCode ierr; 204 205 PetscFunctionBegin; 206 if (!plex->metricCtx) { 207 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 208 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 209 } 210 if (h_max <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_max); 211 plex->metricCtx->h_max = h_max; 212 PetscFunctionReturn(0); 213 } 214 215 /* 216 DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude 217 218 Input parameters: 219 . dm - The DM 220 221 Input parameters: 222 . h_max - The maximum tolerated metric magnitude 223 224 Level: beginner 225 226 .seealso: DMPlexMetricSetMaximumMagnitude(), DMPlexMetricGetMinimumMagnitude() 227 */ 228 PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max) 229 { 230 DM_Plex *plex = (DM_Plex *) dm->data; 231 PetscErrorCode ierr; 232 233 PetscFunctionBegin; 234 if (!plex->metricCtx) { 235 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 236 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 237 } 238 *h_max = plex->metricCtx->h_max; 239 PetscFunctionReturn(0); 240 } 241 242 /* 243 DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy 244 245 Input parameters: 246 + dm - The DM 247 - a_max - The maximum tolerated metric anisotropy 248 249 Level: beginner 250 251 Note: If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one. 252 253 .seealso: DMPlexMetricGetMaximumAnisotropy(), DMPlexMetricSetMaximumMagnitude() 254 */ 255 PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max) 256 { 257 DM_Plex *plex = (DM_Plex *) dm->data; 258 PetscErrorCode ierr; 259 260 PetscFunctionBegin; 261 if (!plex->metricCtx) { 262 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 263 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 264 } 265 if (a_max < 1.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Anisotropy must be at least one, not %.4e", a_max); 266 plex->metricCtx->a_max = a_max; 267 PetscFunctionReturn(0); 268 } 269 270 /* 271 DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy 272 273 Input parameters: 274 . dm - The DM 275 276 Input parameters: 277 . a_max - The maximum tolerated metric anisotropy 278 279 Level: beginner 280 281 .seealso: DMPlexMetricSetMaximumAnisotropy(), DMPlexMetricGetMaximumMagnitude() 282 */ 283 PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max) 284 { 285 DM_Plex *plex = (DM_Plex *) dm->data; 286 PetscErrorCode ierr; 287 288 PetscFunctionBegin; 289 if (!plex->metricCtx) { 290 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 291 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 292 } 293 *a_max = plex->metricCtx->a_max; 294 PetscFunctionReturn(0); 295 } 296 297 /* 298 DMPlexMetricSetTargetComplexity - Set the target metric complexity 299 300 Input parameters: 301 + dm - The DM 302 - targetComplexity - The target metric complexity 303 304 Level: beginner 305 306 .seealso: DMPlexMetricGetTargetComplexity(), DMPlexMetricSetNormalizationOrder() 307 */ 308 PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity) 309 { 310 DM_Plex *plex = (DM_Plex *) dm->data; 311 PetscErrorCode ierr; 312 313 PetscFunctionBegin; 314 if (!plex->metricCtx) { 315 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 316 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 317 } 318 if (targetComplexity <= 0.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric complexity must be positive"); 319 plex->metricCtx->targetComplexity = targetComplexity; 320 PetscFunctionReturn(0); 321 } 322 323 /* 324 DMPlexMetricGetTargetComplexity - Get the target metric complexity 325 326 Input parameters: 327 . dm - The DM 328 329 Input parameters: 330 . targetComplexity - The target metric complexity 331 332 Level: beginner 333 334 .seealso: DMPlexMetricSetTargetComplexity(), DMPlexMetricGetNormalizationOrder() 335 */ 336 PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity) 337 { 338 DM_Plex *plex = (DM_Plex *) dm->data; 339 PetscErrorCode ierr; 340 341 PetscFunctionBegin; 342 if (!plex->metricCtx) { 343 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 344 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 345 } 346 *targetComplexity = plex->metricCtx->targetComplexity; 347 PetscFunctionReturn(0); 348 } 349 350 /* 351 DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization 352 353 Input parameters: 354 + dm - The DM 355 - p - The normalization order 356 357 Level: beginner 358 359 .seealso: DMPlexMetricGetNormalizationOrder(), DMPlexMetricSetTargetComplexity() 360 */ 361 PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p) 362 { 363 DM_Plex *plex = (DM_Plex *) dm->data; 364 PetscErrorCode ierr; 365 366 PetscFunctionBegin; 367 if (!plex->metricCtx) { 368 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 369 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 370 } 371 if (p < 1.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Normalization order must be one or greater"); 372 plex->metricCtx->p = p; 373 PetscFunctionReturn(0); 374 } 375 376 /* 377 DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization 378 379 Input parameters: 380 . dm - The DM 381 382 Input parameters: 383 . p - The normalization order 384 385 Level: beginner 386 387 .seealso: DMPlexMetricSetNormalizationOrder(), DMPlexMetricGetTargetComplexity() 388 */ 389 PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p) 390 { 391 DM_Plex *plex = (DM_Plex *) dm->data; 392 PetscErrorCode ierr; 393 394 PetscFunctionBegin; 395 if (!plex->metricCtx) { 396 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 397 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 398 } 399 *p = plex->metricCtx->p; 400 PetscFunctionReturn(0); 401 } 402 403 PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric) 404 { 405 MPI_Comm comm; 406 PetscErrorCode ierr; 407 PetscFE fe; 408 PetscInt dim; 409 410 PetscFunctionBegin; 411 412 /* Extract metadata from dm */ 413 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 414 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 415 416 /* Create a P1 field of the requested size */ 417 ierr = PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe);CHKERRQ(ierr); 418 ierr = DMSetField(dm, f, NULL, (PetscObject)fe);CHKERRQ(ierr); 419 ierr = DMCreateDS(dm);CHKERRQ(ierr); 420 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 421 ierr = DMCreateLocalVector(dm, metric);CHKERRQ(ierr); 422 423 PetscFunctionReturn(0); 424 } 425 426 /* 427 DMPlexMetricCreate - Create a Riemannian metric field 428 429 Input parameters: 430 + dm - The DM 431 - f - The field number to use 432 433 Output parameter: 434 . metric - The metric 435 436 Level: beginner 437 438 Notes: 439 440 It is assumed that the DM is comprised of simplices. 441 442 Command line options for Riemannian metrics: 443 444 -dm_plex_metric_isotropic - Is the metric isotropic? 445 -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 446 -dm_plex_metric_h_min - Minimum tolerated metric magnitude 447 -dm_plex_metric_h_max - Maximum tolerated metric magnitude 448 -dm_plex_metric_a_max - Maximum tolerated anisotropy 449 -dm_plex_metric_p - L-p normalization order 450 -dm_plex_metric_target_complexity - Target metric complexity 451 452 .seealso: DMPlexMetricCreateUniform(), DMPlexMetricCreateIsotropic() 453 */ 454 PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric) 455 { 456 DM_Plex *plex = (DM_Plex *) dm->data; 457 PetscErrorCode ierr; 458 PetscInt coordDim, Nd; 459 460 PetscFunctionBegin; 461 if (!plex->metricCtx) { 462 ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr); 463 ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr); 464 } 465 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 466 Nd = coordDim*coordDim; 467 ierr = DMPlexP1FieldCreate_Private(dm, f, Nd, metric);CHKERRQ(ierr); 468 PetscFunctionReturn(0); 469 } 470 471 typedef struct { 472 PetscReal scaling; /* Scaling for uniform metric diagonal */ 473 } DMPlexMetricUniformCtx; 474 475 static PetscErrorCode diagonal(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 476 { 477 DMPlexMetricUniformCtx *user = (DMPlexMetricUniformCtx*)ctx; 478 PetscInt i, j; 479 480 for (i = 0; i < dim; ++i) { 481 for (j = 0; j < dim; ++j) { 482 if (i == j) u[i+dim*j] = user->scaling; 483 else u[i+dim*j] = 0.0; 484 } 485 } 486 return 0; 487 } 488 489 /* 490 DMPlexMetricCreateUniform - Construct a uniform isotropic metric 491 492 Input parameters: 493 + dm - The DM 494 . f - The field number to use 495 - alpha - Scaling parameter for the diagonal 496 497 Output parameter: 498 . metric - The uniform metric 499 500 Level: beginner 501 502 Note: It is assumed that the DM is comprised of simplices. 503 504 .seealso: DMPlexMetricCreate(), DMPlexMetricCreateIsotropic() 505 */ 506 PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric) 507 { 508 DMPlexMetricUniformCtx user; 509 PetscErrorCode (*funcs[1])(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *); 510 PetscErrorCode ierr; 511 void *ctxs[1]; 512 513 PetscFunctionBegin; 514 ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr); 515 if (!alpha) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined"); 516 if (alpha < 1.0e-30) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling %e should be positive", alpha); 517 else user.scaling = alpha; 518 funcs[0] = diagonal; 519 ctxs[0] = &user; 520 ierr = DMProjectFunctionLocal(dm, 0.0, funcs, ctxs, INSERT_ALL_VALUES, *metric);CHKERRQ(ierr); 521 PetscFunctionReturn(0); 522 } 523 524 /* 525 DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator 526 527 Input parameters: 528 + dm - The DM 529 . f - The field number to use 530 - indicator - The error indicator 531 532 Output parameter: 533 . metric - The isotropic metric 534 535 Level: beginner 536 537 Notes: 538 539 It is assumed that the DM is comprised of simplices. 540 541 The indicator needs to be a scalar field defined at *vertices*. 542 543 .seealso: DMPlexMetricCreate(), DMPlexMetricCreateUniform() 544 */ 545 PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric) 546 { 547 DM dmIndi; 548 PetscErrorCode ierr; 549 PetscInt dim, d, vStart, vEnd, v; 550 const PetscScalar *indi; 551 PetscScalar *met; 552 553 PetscFunctionBegin; 554 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 555 ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr); 556 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 557 ierr = VecGetArrayRead(indicator, &indi);CHKERRQ(ierr); 558 ierr = VecGetArrayWrite(*metric, &met);CHKERRQ(ierr); 559 ierr = VecGetDM(indicator, &dmIndi);CHKERRQ(ierr); 560 for (v = vStart; v < vEnd; ++v) { 561 PetscScalar *vindi, *vmet; 562 ierr = DMPlexPointLocalRead(dmIndi, v, indi, &vindi);CHKERRQ(ierr); 563 ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr); 564 for (d = 0; d < dim; ++d) vmet[d*(dim+1)] = vindi[0]; 565 } 566 ierr = VecRestoreArrayWrite(*metric, &met);CHKERRQ(ierr); 567 ierr = VecRestoreArrayRead(indicator, &indi);CHKERRQ(ierr); 568 PetscFunctionReturn(0); 569 } 570 571 static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[]) 572 { 573 PetscErrorCode ierr; 574 PetscInt i, j, k; 575 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); 576 PetscScalar *Mpos; 577 578 PetscFunctionBegin; 579 ierr = PetscMalloc2(dim*dim, &Mpos, dim, &eigs);CHKERRQ(ierr); 580 581 /* Symmetrize */ 582 for (i = 0; i < dim; ++i) { 583 Mpos[i*dim+i] = Mp[i*dim+i]; 584 for (j = i+1; j < dim; ++j) { 585 Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 586 Mpos[j*dim+i] = Mpos[i*dim+j]; 587 } 588 } 589 590 /* Compute eigendecomposition */ 591 { 592 PetscScalar *work; 593 PetscBLASInt lwork; 594 595 lwork = 5*dim; 596 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 597 { 598 PetscBLASInt lierr; 599 PetscBLASInt nb; 600 601 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 602 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 603 #if defined(PETSC_USE_COMPLEX) 604 { 605 PetscReal *rwork; 606 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 607 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr)); 608 ierr = PetscFree(rwork);CHKERRQ(ierr); 609 } 610 #else 611 PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr)); 612 #endif 613 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 614 ierr = PetscFPTrapPop();CHKERRQ(ierr); 615 } 616 ierr = PetscFree(work);CHKERRQ(ierr); 617 } 618 619 /* Reflect to positive orthant and enforce maximum and minimum size */ 620 max_eig = 0.0; 621 for (i = 0; i < dim; ++i) { 622 eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i]))); 623 max_eig = PetscMax(eigs[i], max_eig); 624 } 625 626 /* Enforce maximum anisotropy */ 627 for (i = 0; i < dim; ++i) { 628 if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min); 629 } 630 631 /* Reconstruct Hessian */ 632 for (i = 0; i < dim; ++i) { 633 for (j = 0; j < dim; ++j) { 634 Mp[i*dim+j] = 0.0; 635 for (k = 0; k < dim; ++k) { 636 Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j]; 637 } 638 } 639 } 640 ierr = PetscFree2(Mpos, eigs);CHKERRQ(ierr); 641 642 PetscFunctionReturn(0); 643 } 644 645 /* 646 DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric 647 648 Input parameters: 649 + dm - The DM 650 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 651 . restrictAnisotropy - Should maximum anisotropy be enforced? 652 - metric - The metric 653 654 Output parameter: 655 . metric - The metric 656 657 Level: beginner 658 659 .seealso: DMPlexMetricNormalize(), DMPlexMetricIntersection() 660 */ 661 PetscErrorCode DMPlexMetricEnforceSPD(DM dm, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metric) 662 { 663 PetscErrorCode ierr; 664 PetscInt dim, vStart, vEnd, v; 665 PetscScalar *met; 666 PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0; 667 668 PetscFunctionBegin; 669 670 /* Extract metadata from dm */ 671 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 672 if (restrictSizes) { 673 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 674 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 675 h_min = PetscMax(h_min, 1.0e-30); 676 h_max = PetscMin(h_max, 1.0e+30); 677 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); 678 } 679 if (restrictAnisotropy) { 680 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 681 a_max = PetscMin(a_max, 1.0e+30); 682 } 683 684 /* Enforce SPD */ 685 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 686 ierr = VecGetArray(metric, &met);CHKERRQ(ierr); 687 for (v = vStart; v < vEnd; ++v) { 688 PetscScalar *vmet; 689 ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr); 690 ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, vmet);CHKERRQ(ierr); 691 } 692 ierr = VecRestoreArray(metric, &met);CHKERRQ(ierr); 693 694 PetscFunctionReturn(0); 695 } 696 697 static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 698 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 699 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 700 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 701 { 702 const PetscScalar p = constants[0]; 703 PetscReal detH = 0.0; 704 705 if (dim == 2) DMPlex_Det2D_Scalar_Internal(&detH, u); 706 else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detH, u); 707 f0[0] = PetscPowReal(detH, p/(2.0*p + dim)); 708 } 709 710 /* 711 DMPlexMetricNormalize - Apply L-p normalization to a metric 712 713 Input parameters: 714 + dm - The DM 715 . metricIn - The unnormalized metric 716 . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 717 - restrictAnisotropy - Should maximum metric anisotropy be enforced? 718 719 Output parameter: 720 . metricOut - The normalized metric 721 722 Level: beginner 723 724 .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection() 725 */ 726 PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut) 727 { 728 MPI_Comm comm; 729 PetscBool restrictAnisotropyFirst; 730 PetscDS ds; 731 PetscErrorCode ierr; 732 PetscInt dim, Nd, vStart, vEnd, v, i; 733 PetscScalar *met, integral, constants[1]; 734 PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, target; 735 736 PetscFunctionBegin; 737 738 /* Extract metadata from dm */ 739 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 740 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 741 Nd = dim*dim; 742 743 /* Set up metric and ensure it is SPD */ 744 ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr); 745 ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr); 746 ierr = DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst);CHKERRQ(ierr); 747 ierr = DMPlexMetricEnforceSPD(dm, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), *metricOut);CHKERRQ(ierr); 748 749 /* Compute global normalization factor */ 750 ierr = DMPlexMetricGetTargetComplexity(dm, &target);CHKERRQ(ierr); 751 ierr = DMPlexMetricGetNormalizationOrder(dm, &p);CHKERRQ(ierr); 752 constants[0] = p; 753 ierr = DMGetDS(dm, &ds);CHKERRQ(ierr); 754 ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr); 755 ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr); 756 ierr = DMPlexComputeIntegralFEM(dm, *metricOut, &integral, NULL);CHKERRQ(ierr); 757 factGlob = PetscPowReal(target/PetscRealPart(integral), 2.0/dim); 758 759 /* Apply local scaling */ 760 if (restrictSizes) { 761 ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr); 762 ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr); 763 h_min = PetscMax(h_min, 1.0e-30); 764 h_max = PetscMin(h_max, 1.0e+30); 765 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); 766 } 767 if (restrictAnisotropy && !restrictAnisotropyFirst) { 768 ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr); 769 a_max = PetscMin(a_max, 1.0e+30); 770 } 771 ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr); 772 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 773 for (v = vStart; v < vEnd; ++v) { 774 PetscScalar *Mp; 775 PetscReal detM, fact; 776 777 ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr); 778 if (dim == 2) DMPlex_Det2D_Scalar_Internal(&detM, Mp); 779 else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detM, Mp); 780 else SETERRQ1(comm, PETSC_ERR_SUP, "Dimension %d not supported", dim); 781 fact = factGlob * PetscPowReal(PetscAbsReal(detM), -1.0/(2*p+dim)); 782 for (i = 0; i < Nd; ++i) Mp[i] *= fact; 783 if (restrictSizes) { ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, Mp);CHKERRQ(ierr); } 784 } 785 ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr); 786 787 PetscFunctionReturn(0); 788 } 789 790 /* 791 DMPlexMetricAverage - Compute the average of a list of metrics 792 793 Input Parameter: 794 + dm - The DM 795 . numMetrics - The number of metrics to be averaged 796 . weights - Weights for the average 797 - metrics - The metrics to be averaged 798 799 Output Parameter: 800 . metricAvg - The averaged metric 801 802 Level: beginner 803 804 Notes: 805 The weights should sum to unity. 806 807 If weights are not provided then an unweighted average is used. 808 809 .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection() 810 */ 811 PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg) 812 { 813 PetscBool haveWeights = PETSC_TRUE; 814 PetscErrorCode ierr; 815 PetscInt i; 816 PetscReal sum = 0.0, tol = 1.0e-10; 817 818 PetscFunctionBegin; 819 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics); } 820 ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr); 821 ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr); 822 823 /* Default to the unweighted case */ 824 if (!weights) { 825 ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr); 826 haveWeights = PETSC_FALSE; 827 for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; } 828 } 829 830 /* Check weights sum to unity */ 831 for (i = 0; i < numMetrics; ++i) { sum += weights[i]; } 832 if (PetscAbsReal(sum - 1) > tol) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); } 833 834 /* Compute metric average */ 835 for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); } 836 if (!haveWeights) {ierr = PetscFree(weights); } 837 PetscFunctionReturn(0); 838 } 839 840 /* 841 DMPlexMetricAverage2 - Compute the unweighted average of two metrics 842 843 Input Parameter: 844 + dm - The DM 845 . metric1 - The first metric to be averaged 846 - metric2 - The second metric to be averaged 847 848 Output Parameter: 849 . metricAvg - The averaged metric 850 851 Level: beginner 852 853 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3() 854 */ 855 PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg) 856 { 857 PetscErrorCode ierr; 858 PetscReal weights[2] = {0.5, 0.5}; 859 Vec metrics[2] = {metric1, metric2}; 860 861 PetscFunctionBegin; 862 ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr); 863 PetscFunctionReturn(0); 864 } 865 866 /* 867 DMPlexMetricAverage3 - Compute the unweighted average of three metrics 868 869 Input Parameter: 870 + dm - The DM 871 . metric1 - The first metric to be averaged 872 . metric2 - The second metric to be averaged 873 - metric3 - The third metric to be averaged 874 875 Output Parameter: 876 . metricAvg - The averaged metric 877 878 Level: beginner 879 880 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2() 881 */ 882 PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg) 883 { 884 PetscErrorCode ierr; 885 PetscReal weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0}; 886 Vec metrics[3] = {metric1, metric2, metric3}; 887 888 PetscFunctionBegin; 889 ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr); 890 PetscFunctionReturn(0); 891 } 892 893 static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 894 { 895 PetscErrorCode ierr; 896 PetscInt i, j, k, l, m; 897 PetscReal *evals, *evals1; 898 PetscScalar *evecs, *sqrtM1, *isqrtM1; 899 900 PetscFunctionBegin; 901 ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr); 902 for (i = 0; i < dim; ++i) { 903 for (j = 0; j < dim; ++j) { 904 evecs[i*dim+j] = M1[i*dim+j]; 905 } 906 } 907 { 908 PetscScalar *work; 909 PetscBLASInt lwork; 910 911 lwork = 5*dim; 912 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 913 { 914 PetscBLASInt lierr, nb; 915 PetscReal sqrtk; 916 917 /* Compute eigendecomposition of M1 */ 918 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 919 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 920 #if defined(PETSC_USE_COMPLEX) 921 { 922 PetscReal *rwork; 923 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 924 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr)); 925 ierr = PetscFree(rwork);CHKERRQ(ierr); 926 } 927 #else 928 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr)); 929 #endif 930 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 931 ierr = PetscFPTrapPop(); 932 933 /* Compute square root and reciprocal */ 934 for (i = 0; i < dim; ++i) { 935 for (j = 0; j < dim; ++j) { 936 sqrtM1[i*dim+j] = 0.0; 937 isqrtM1[i*dim+j] = 0.0; 938 for (k = 0; k < dim; ++k) { 939 sqrtk = PetscSqrtReal(evals1[k]); 940 sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j]; 941 isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j]; 942 } 943 } 944 } 945 946 /* Map into the space spanned by the eigenvectors of M1 */ 947 for (i = 0; i < dim; ++i) { 948 for (j = 0; j < dim; ++j) { 949 evecs[i*dim+j] = 0.0; 950 for (k = 0; k < dim; ++k) { 951 for (l = 0; l < dim; ++l) { 952 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l]; 953 } 954 } 955 } 956 } 957 958 /* Compute eigendecomposition */ 959 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 960 #if defined(PETSC_USE_COMPLEX) 961 { 962 PetscReal *rwork; 963 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 964 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 965 ierr = PetscFree(rwork);CHKERRQ(ierr); 966 } 967 #else 968 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 969 #endif 970 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 971 ierr = PetscFPTrapPop(); 972 973 /* Modify eigenvalues */ 974 for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]); 975 976 /* Map back to get the intersection */ 977 for (i = 0; i < dim; ++i) { 978 for (j = 0; j < dim; ++j) { 979 M2[i*dim+j] = 0.0; 980 for (k = 0; k < dim; ++k) { 981 for (l = 0; l < dim; ++l) { 982 for (m = 0; m < dim; ++m) { 983 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m]; 984 } 985 } 986 } 987 } 988 } 989 } 990 ierr = PetscFree(work);CHKERRQ(ierr); 991 } 992 ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr); 993 PetscFunctionReturn(0); 994 } 995 996 /* 997 DMPlexMetricIntersection - Compute the intersection of a list of metrics 998 999 Input Parameter: 1000 + dm - The DM 1001 . numMetrics - The number of metrics to be intersected 1002 - metrics - The metrics to be intersected 1003 1004 Output Parameter: 1005 . metricInt - The intersected metric 1006 1007 Level: beginner 1008 1009 Notes: 1010 1011 The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics. 1012 1013 The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2. 1014 1015 .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage() 1016 */ 1017 PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt) 1018 { 1019 PetscErrorCode ierr; 1020 PetscInt dim, vStart, vEnd, v, i; 1021 PetscScalar *met, *meti, *M, *Mi; 1022 1023 PetscFunctionBegin; 1024 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics); } 1025 1026 /* Extract metadata from dm */ 1027 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1028 ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr); 1029 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1030 1031 /* Copy over the first metric */ 1032 ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr); 1033 1034 /* Intersect subsequent metrics in turn */ 1035 if (numMetrics > 1) { 1036 ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr); 1037 for (i = 1; i < numMetrics; ++i) { 1038 ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr); 1039 for (v = vStart; v < vEnd; ++v) { 1040 ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr); 1041 ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr); 1042 ierr = DMPlexMetricIntersection_Private(dim, Mi, M);CHKERRQ(ierr); 1043 } 1044 ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr); 1045 } 1046 ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr); 1047 } 1048 1049 PetscFunctionReturn(0); 1050 } 1051 1052 /* 1053 DMPlexMetricIntersection2 - Compute the intersection of two metrics 1054 1055 Input Parameter: 1056 + dm - The DM 1057 . metric1 - The first metric to be intersected 1058 - metric2 - The second metric to be intersected 1059 1060 Output Parameter: 1061 . metricInt - The intersected metric 1062 1063 Level: beginner 1064 1065 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3() 1066 */ 1067 PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt) 1068 { 1069 PetscErrorCode ierr; 1070 Vec metrics[2] = {metric1, metric2}; 1071 1072 PetscFunctionBegin; 1073 ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr); 1074 PetscFunctionReturn(0); 1075 } 1076 1077 /* 1078 DMPlexMetricIntersection3 - Compute the intersection of three metrics 1079 1080 Input Parameter: 1081 + dm - The DM 1082 . metric1 - The first metric to be intersected 1083 . metric2 - The second metric to be intersected 1084 - metric3 - The third metric to be intersected 1085 1086 Output Parameter: 1087 . metricInt - The intersected metric 1088 1089 Level: beginner 1090 1091 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2() 1092 */ 1093 PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt) 1094 { 1095 PetscErrorCode ierr; 1096 Vec metrics[3] = {metric1, metric2, metric3}; 1097 1098 PetscFunctionBegin; 1099 ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr); 1100 PetscFunctionReturn(0); 1101 } 1102