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 and anisotropy be enforced? 717 718 Output parameter: 719 . metricOut - The normalized metric 720 721 Level: beginner 722 723 .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection() 724 */ 725 PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, Vec *metricOut) 726 { 727 DMPlexMetricCtx *user; 728 MPI_Comm comm; 729 PetscDS ds; 730 PetscErrorCode ierr; 731 PetscInt dim, Nd, vStart, vEnd, v, i; 732 PetscScalar *met, integral, constants[1]; 733 PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, target; 734 735 PetscFunctionBegin; 736 737 /* Extract metadata from dm */ 738 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 739 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 740 Nd = dim*dim; 741 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 742 ierr = DMGetApplicationContext(dm, (void**)&user);CHKERRQ(ierr); 743 if (restrictSizes && user->restrictAnisotropyFirst && user->a_max > 1.0) a_max = user->a_max; 744 if (PetscAbsReal(user->p) >= 1.0) p = user->p; 745 else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric normalization order %f should be greater than one.", user->p); 746 constants[0] = p; 747 if (user->targetComplexity > 0.0) target = user->targetComplexity; 748 else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Target metric complexity %f should be positive.", user->targetComplexity); 749 750 /* Set up metric and ensure it is SPD */ 751 ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr); 752 ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr); 753 ierr = DMPlexMetricEnforceSPD(dm, PETSC_FALSE, *metricOut);CHKERRQ(ierr); 754 755 /* Compute global normalization factor */ 756 ierr = DMGetDS(dm, &ds);CHKERRQ(ierr); 757 ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr); 758 ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr); 759 ierr = DMPlexComputeIntegralFEM(dm, *metricOut, &integral, NULL);CHKERRQ(ierr); 760 factGlob = PetscPowReal(target/PetscRealPart(integral), 2.0/dim); 761 762 /* Apply local scaling */ 763 a_max = 0.0; 764 if (restrictSizes) { 765 if (user->h_max > h_min) h_max = PetscMin(h_max, user->h_max); 766 if (user->h_min > 0.0) h_min = PetscMax(h_min, user->h_min); 767 if (!user->restrictAnisotropyFirst && user->a_max > 1.0) a_max = user->a_max; 768 } 769 ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr); 770 for (v = vStart; v < vEnd; ++v) { 771 PetscScalar *Mp; 772 PetscReal detM, fact; 773 774 ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr); 775 if (dim == 2) DMPlex_Det2D_Scalar_Internal(&detM, Mp); 776 else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detM, Mp); 777 else SETERRQ1(comm, PETSC_ERR_SUP, "Dimension %d not supported", dim); 778 fact = factGlob * PetscPowReal(PetscAbsReal(detM), -1.0/(2*p+dim)); 779 for (i = 0; i < Nd; ++i) Mp[i] *= fact; 780 if (restrictSizes) { ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, Mp);CHKERRQ(ierr); } 781 } 782 ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr); 783 784 PetscFunctionReturn(0); 785 } 786 787 /* 788 DMPlexMetricAverage - Compute the average of a list of metrics 789 790 Input Parameter: 791 + dm - The DM 792 . numMetrics - The number of metrics to be averaged 793 . weights - Weights for the average 794 - metrics - The metrics to be averaged 795 796 Output Parameter: 797 . metricAvg - The averaged metric 798 799 Level: beginner 800 801 Notes: 802 The weights should sum to unity. 803 804 If weights are not provided then an unweighted average is used. 805 806 .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection() 807 */ 808 PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg) 809 { 810 PetscBool haveWeights = PETSC_TRUE; 811 PetscErrorCode ierr; 812 PetscInt i; 813 PetscReal sum = 0.0, tol = 1.0e-10; 814 815 PetscFunctionBegin; 816 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics); } 817 ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr); 818 ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr); 819 820 /* Default to the unweighted case */ 821 if (!weights) { 822 ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr); 823 haveWeights = PETSC_FALSE; 824 for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; } 825 } 826 827 /* Check weights sum to unity */ 828 for (i = 0; i < numMetrics; ++i) { sum += weights[i]; } 829 if (PetscAbsReal(sum - 1) > tol) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); } 830 831 /* Compute metric average */ 832 for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); } 833 if (!haveWeights) {ierr = PetscFree(weights); } 834 PetscFunctionReturn(0); 835 } 836 837 /* 838 DMPlexMetricAverage2 - Compute the unweighted average of two metrics 839 840 Input Parameter: 841 + dm - The DM 842 . metric1 - The first metric to be averaged 843 - metric2 - The second metric to be averaged 844 845 Output Parameter: 846 . metricAvg - The averaged metric 847 848 Level: beginner 849 850 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3() 851 */ 852 PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg) 853 { 854 PetscErrorCode ierr; 855 PetscReal weights[2] = {0.5, 0.5}; 856 Vec metrics[2] = {metric1, metric2}; 857 858 PetscFunctionBegin; 859 ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr); 860 PetscFunctionReturn(0); 861 } 862 863 /* 864 DMPlexMetricAverage3 - Compute the unweighted average of three metrics 865 866 Input Parameter: 867 + dm - The DM 868 . metric1 - The first metric to be averaged 869 . metric2 - The second metric to be averaged 870 - metric3 - The third metric to be averaged 871 872 Output Parameter: 873 . metricAvg - The averaged metric 874 875 Level: beginner 876 877 .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2() 878 */ 879 PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg) 880 { 881 PetscErrorCode ierr; 882 PetscReal weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0}; 883 Vec metrics[3] = {metric1, metric2, metric3}; 884 885 PetscFunctionBegin; 886 ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr); 887 PetscFunctionReturn(0); 888 } 889 890 static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 891 { 892 PetscErrorCode ierr; 893 PetscInt i, j, k, l, m; 894 PetscReal *evals, *evals1; 895 PetscScalar *evecs, *sqrtM1, *isqrtM1; 896 897 PetscFunctionBegin; 898 ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr); 899 for (i = 0; i < dim; ++i) { 900 for (j = 0; j < dim; ++j) { 901 evecs[i*dim+j] = M1[i*dim+j]; 902 } 903 } 904 { 905 PetscScalar *work; 906 PetscBLASInt lwork; 907 908 lwork = 5*dim; 909 ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr); 910 { 911 PetscBLASInt lierr, nb; 912 PetscReal sqrtk; 913 914 /* Compute eigendecomposition of M1 */ 915 ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr); 916 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 917 #if defined(PETSC_USE_COMPLEX) 918 { 919 PetscReal *rwork; 920 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 921 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr)); 922 ierr = PetscFree(rwork);CHKERRQ(ierr); 923 } 924 #else 925 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr)); 926 #endif 927 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 928 ierr = PetscFPTrapPop(); 929 930 /* Compute square root and reciprocal */ 931 for (i = 0; i < dim; ++i) { 932 for (j = 0; j < dim; ++j) { 933 sqrtM1[i*dim+j] = 0.0; 934 isqrtM1[i*dim+j] = 0.0; 935 for (k = 0; k < dim; ++k) { 936 sqrtk = PetscSqrtReal(evals1[k]); 937 sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j]; 938 isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j]; 939 } 940 } 941 } 942 943 /* Map into the space spanned by the eigenvectors of M1 */ 944 for (i = 0; i < dim; ++i) { 945 for (j = 0; j < dim; ++j) { 946 evecs[i*dim+j] = 0.0; 947 for (k = 0; k < dim; ++k) { 948 for (l = 0; l < dim; ++l) { 949 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l]; 950 } 951 } 952 } 953 } 954 955 /* Compute eigendecomposition */ 956 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 957 #if defined(PETSC_USE_COMPLEX) 958 { 959 PetscReal *rwork; 960 ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr); 961 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 962 ierr = PetscFree(rwork);CHKERRQ(ierr); 963 } 964 #else 965 PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 966 #endif 967 if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 968 ierr = PetscFPTrapPop(); 969 970 /* Modify eigenvalues */ 971 for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]); 972 973 /* Map back to get the intersection */ 974 for (i = 0; i < dim; ++i) { 975 for (j = 0; j < dim; ++j) { 976 M2[i*dim+j] = 0.0; 977 for (k = 0; k < dim; ++k) { 978 for (l = 0; l < dim; ++l) { 979 for (m = 0; m < dim; ++m) { 980 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m]; 981 } 982 } 983 } 984 } 985 } 986 } 987 ierr = PetscFree(work);CHKERRQ(ierr); 988 } 989 ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr); 990 PetscFunctionReturn(0); 991 } 992 993 /* 994 DMPlexMetricIntersection - Compute the intersection of a list of metrics 995 996 Input Parameter: 997 + dm - The DM 998 . numMetrics - The number of metrics to be intersected 999 - metrics - The metrics to be intersected 1000 1001 Output Parameter: 1002 . metricInt - The intersected metric 1003 1004 Level: beginner 1005 1006 Notes: 1007 1008 The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics. 1009 1010 The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2. 1011 1012 .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage() 1013 */ 1014 PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt) 1015 { 1016 PetscErrorCode ierr; 1017 PetscInt dim, vStart, vEnd, v, i; 1018 PetscScalar *met, *meti, *M, *Mi; 1019 1020 PetscFunctionBegin; 1021 if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics); } 1022 1023 /* Extract metadata from dm */ 1024 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1025 ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr); 1026 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1027 1028 /* Copy over the first metric */ 1029 ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr); 1030 1031 /* Intersect subsequent metrics in turn */ 1032 if (numMetrics > 1) { 1033 ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr); 1034 for (i = 1; i < numMetrics; ++i) { 1035 ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr); 1036 for (v = vStart; v < vEnd; ++v) { 1037 ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr); 1038 ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr); 1039 ierr = DMPlexMetricIntersection_Private(dim, Mi, M);CHKERRQ(ierr); 1040 } 1041 ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr); 1042 } 1043 ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr); 1044 } 1045 1046 PetscFunctionReturn(0); 1047 } 1048 1049 /* 1050 DMPlexMetricIntersection2 - Compute the intersection of two metrics 1051 1052 Input Parameter: 1053 + dm - The DM 1054 . metric1 - The first metric to be intersected 1055 - metric2 - The second metric to be intersected 1056 1057 Output Parameter: 1058 . metricInt - The intersected metric 1059 1060 Level: beginner 1061 1062 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3() 1063 */ 1064 PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt) 1065 { 1066 PetscErrorCode ierr; 1067 Vec metrics[2] = {metric1, metric2}; 1068 1069 PetscFunctionBegin; 1070 ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr); 1071 PetscFunctionReturn(0); 1072 } 1073 1074 /* 1075 DMPlexMetricIntersection3 - Compute the intersection of three metrics 1076 1077 Input Parameter: 1078 + dm - The DM 1079 . metric1 - The first metric to be intersected 1080 . metric2 - The second metric to be intersected 1081 - metric3 - The third metric to be intersected 1082 1083 Output Parameter: 1084 . metricInt - The intersected metric 1085 1086 Level: beginner 1087 1088 .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2() 1089 */ 1090 PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt) 1091 { 1092 PetscErrorCode ierr; 1093 Vec metrics[3] = {metric1, metric2, metric3}; 1094 1095 PetscFunctionBegin; 1096 ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr); 1097 PetscFunctionReturn(0); 1098 } 1099