120282da2SJoe Wallwork #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 220282da2SJoe Wallwork #include <petscblaslapack.h> 320282da2SJoe Wallwork 4fe902aceSJoe Wallwork PetscLogEvent DMPLEX_MetricEnforceSPD, DMPLEX_MetricNormalize, DMPLEX_MetricAverage, DMPLEX_MetricIntersection; 5fe902aceSJoe Wallwork 631b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetFromOptions(DM dm) 731b70465SJoe Wallwork { 8bc00d7afSJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 931b70465SJoe Wallwork MPI_Comm comm; 1093520041SJoe Wallwork PetscBool isotropic = PETSC_FALSE, uniform = PETSC_FALSE, restrictAnisotropyFirst = PETSC_FALSE; 1176f360caSJoe Wallwork PetscBool noInsert = PETSC_FALSE, noSwap = PETSC_FALSE, noMove = PETSC_FALSE, noSurf = PETSC_FALSE; 12cc2eee55SJoe Wallwork PetscInt verbosity = -1, numIter = 3; 13ae8b063eSJoe Wallwork PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 1.0e+05, p = 1.0, target = 1000.0, beta = 1.3, hausd = 0.01; 1431b70465SJoe Wallwork 1531b70465SJoe Wallwork PetscFunctionBegin; 16bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(PetscNew(&plex->metricCtx)); 179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 18d0609cedSBarry Smith PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric"); 199566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL)); 209566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetIsotropic(dm, isotropic)); 219566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_uniform", "Is the metric uniform?", "DMPlexMetricCreateUniform", uniform, &uniform, NULL)); 229566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetUniform(dm, uniform)); 239566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL)); 249566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst)); 259566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_no_insert", "Turn off node insertion and deletion", "DMAdaptMetric", noInsert, &noInsert, NULL)); 269566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNoInsertion(dm, noInsert)); 279566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_no_swap", "Turn off facet swapping", "DMAdaptMetric", noSwap, &noSwap, NULL)); 289566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNoSwapping(dm, noSwap)); 299566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_no_move", "Turn off facet node movement", "DMAdaptMetric", noMove, &noMove, NULL)); 309566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNoMovement(dm, noMove)); 319566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-dm_plex_metric_no_surf", "Turn off surface modification", "DMAdaptMetric", noSurf, &noSurf, NULL)); 329566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNoSurf(dm, noSurf)); 339566063dSJacob Faibussowitsch PetscCall(PetscOptionsBoundedInt("-dm_plex_metric_num_iterations", "Number of ParMmg adaptation iterations", "DMAdaptMetric", numIter, &numIter, NULL, 0)); 349566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNumIterations(dm, numIter)); 359566063dSJacob Faibussowitsch PetscCall(PetscOptionsRangeInt("-dm_plex_metric_verbosity", "Verbosity of metric-based mesh adaptation package (-1 = silent, 10 = maximum)", "DMAdaptMetric", verbosity, &verbosity, NULL, -1, 10)); 369566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetVerbosity(dm, verbosity)); 379566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL)); 389566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetMinimumMagnitude(dm, h_min)); 399566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL)); 409566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetMaximumMagnitude(dm, h_max)); 419566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL)); 429566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetMaximumAnisotropy(dm, a_max)); 439566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL)); 449566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetNormalizationOrder(dm, p)); 459566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL)); 469566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetTargetComplexity(dm, target)); 479566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_gradation_factor", "Metric gradation factor", "DMAdaptMetric", beta, &beta, NULL)); 489566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetGradationFactor(dm, beta)); 499566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-dm_plex_metric_hausdorff_number", "Metric Hausdorff number", "DMAdaptMetric", hausd, &hausd, NULL)); 509566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetHausdorffNumber(dm, hausd)); 51d0609cedSBarry Smith PetscOptionsEnd(); 5231b70465SJoe Wallwork PetscFunctionReturn(0); 5331b70465SJoe Wallwork } 5431b70465SJoe Wallwork 55cb7bfe8cSJoe Wallwork /*@ 5631b70465SJoe Wallwork DMPlexMetricSetIsotropic - Record whether a metric is isotropic 5731b70465SJoe Wallwork 5831b70465SJoe Wallwork Input parameters: 5931b70465SJoe Wallwork + dm - The DM 6031b70465SJoe Wallwork - isotropic - Is the metric isotropic? 6131b70465SJoe Wallwork 6231b70465SJoe Wallwork Level: beginner 6331b70465SJoe Wallwork 64db781477SPatrick Sanan .seealso: `DMPlexMetricIsIsotropic()`, `DMPlexMetricSetUniform()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 65cb7bfe8cSJoe Wallwork @*/ 6631b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic) 6731b70465SJoe Wallwork { 6831b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 6931b70465SJoe Wallwork 7031b70465SJoe Wallwork PetscFunctionBegin; 71bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 7231b70465SJoe Wallwork plex->metricCtx->isotropic = isotropic; 7331b70465SJoe Wallwork PetscFunctionReturn(0); 7431b70465SJoe Wallwork } 7531b70465SJoe Wallwork 76cb7bfe8cSJoe Wallwork /*@ 7793520041SJoe Wallwork DMPlexMetricIsIsotropic - Is a metric isotropic? 7831b70465SJoe Wallwork 7931b70465SJoe Wallwork Input parameters: 8031b70465SJoe Wallwork . dm - The DM 8131b70465SJoe Wallwork 8231b70465SJoe Wallwork Output parameters: 8331b70465SJoe Wallwork . isotropic - Is the metric isotropic? 8431b70465SJoe Wallwork 8531b70465SJoe Wallwork Level: beginner 8631b70465SJoe Wallwork 87db781477SPatrick Sanan .seealso: `DMPlexMetricSetIsotropic()`, `DMPlexMetricIsUniform()`, `DMPlexMetricRestrictAnisotropyFirst()` 88cb7bfe8cSJoe Wallwork @*/ 8931b70465SJoe Wallwork PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic) 9031b70465SJoe Wallwork { 9131b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 9231b70465SJoe Wallwork 9331b70465SJoe Wallwork PetscFunctionBegin; 94bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 9531b70465SJoe Wallwork *isotropic = plex->metricCtx->isotropic; 9631b70465SJoe Wallwork PetscFunctionReturn(0); 9731b70465SJoe Wallwork } 9831b70465SJoe Wallwork 99cb7bfe8cSJoe Wallwork /*@ 10093520041SJoe Wallwork DMPlexMetricSetUniform - Record whether a metric is uniform 10193520041SJoe Wallwork 10293520041SJoe Wallwork Input parameters: 10393520041SJoe Wallwork + dm - The DM 10493520041SJoe Wallwork - uniform - Is the metric uniform? 10593520041SJoe Wallwork 10693520041SJoe Wallwork Level: beginner 10793520041SJoe Wallwork 10893520041SJoe Wallwork Notes: 10993520041SJoe Wallwork 11093520041SJoe Wallwork If the metric is specified as uniform then it is assumed to be isotropic, too. 11193520041SJoe Wallwork 112db781477SPatrick Sanan .seealso: `DMPlexMetricIsUniform()`, `DMPlexMetricSetIsotropic()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 11393520041SJoe Wallwork @*/ 11493520041SJoe Wallwork PetscErrorCode DMPlexMetricSetUniform(DM dm, PetscBool uniform) 11593520041SJoe Wallwork { 11693520041SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 11793520041SJoe Wallwork 11893520041SJoe Wallwork PetscFunctionBegin; 119bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 12093520041SJoe Wallwork plex->metricCtx->uniform = uniform; 12193520041SJoe Wallwork if (uniform) plex->metricCtx->isotropic = uniform; 12293520041SJoe Wallwork PetscFunctionReturn(0); 12393520041SJoe Wallwork } 12493520041SJoe Wallwork 12593520041SJoe Wallwork /*@ 12693520041SJoe Wallwork DMPlexMetricIsUniform - Is a metric uniform? 12793520041SJoe Wallwork 12893520041SJoe Wallwork Input parameters: 12993520041SJoe Wallwork . dm - The DM 13093520041SJoe Wallwork 13193520041SJoe Wallwork Output parameters: 13293520041SJoe Wallwork . uniform - Is the metric uniform? 13393520041SJoe Wallwork 13493520041SJoe Wallwork Level: beginner 13593520041SJoe Wallwork 136db781477SPatrick Sanan .seealso: `DMPlexMetricSetUniform()`, `DMPlexMetricIsIsotropic()`, `DMPlexMetricRestrictAnisotropyFirst()` 13793520041SJoe Wallwork @*/ 13893520041SJoe Wallwork PetscErrorCode DMPlexMetricIsUniform(DM dm, PetscBool *uniform) 13993520041SJoe Wallwork { 14093520041SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 14193520041SJoe Wallwork 14293520041SJoe Wallwork PetscFunctionBegin; 143bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 14493520041SJoe Wallwork *uniform = plex->metricCtx->uniform; 14593520041SJoe Wallwork PetscFunctionReturn(0); 14693520041SJoe Wallwork } 14793520041SJoe Wallwork 14893520041SJoe Wallwork /*@ 14931b70465SJoe Wallwork DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization 15031b70465SJoe Wallwork 15131b70465SJoe Wallwork Input parameters: 15231b70465SJoe Wallwork + dm - The DM 15331b70465SJoe Wallwork - restrictAnisotropyFirst - Should anisotropy be normalized first? 15431b70465SJoe Wallwork 15531b70465SJoe Wallwork Level: beginner 15631b70465SJoe Wallwork 157db781477SPatrick Sanan .seealso: `DMPlexMetricSetIsotropic()`, `DMPlexMetricRestrictAnisotropyFirst()` 158cb7bfe8cSJoe Wallwork @*/ 15931b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst) 16031b70465SJoe Wallwork { 16131b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 16231b70465SJoe Wallwork 16331b70465SJoe Wallwork PetscFunctionBegin; 164bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 16531b70465SJoe Wallwork plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst; 16631b70465SJoe Wallwork PetscFunctionReturn(0); 16731b70465SJoe Wallwork } 16831b70465SJoe Wallwork 169cb7bfe8cSJoe Wallwork /*@ 17031b70465SJoe Wallwork DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after? 17131b70465SJoe Wallwork 17231b70465SJoe Wallwork Input parameters: 17331b70465SJoe Wallwork . dm - The DM 17431b70465SJoe Wallwork 17531b70465SJoe Wallwork Output parameters: 17631b70465SJoe Wallwork . restrictAnisotropyFirst - Is anisotropy be normalized first? 17731b70465SJoe Wallwork 17831b70465SJoe Wallwork Level: beginner 17931b70465SJoe Wallwork 180db781477SPatrick Sanan .seealso: `DMPlexMetricIsIsotropic()`, `DMPlexMetricSetRestrictAnisotropyFirst()` 181cb7bfe8cSJoe Wallwork @*/ 18231b70465SJoe Wallwork PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst) 18331b70465SJoe Wallwork { 18431b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 18531b70465SJoe Wallwork 18631b70465SJoe Wallwork PetscFunctionBegin; 187bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 18831b70465SJoe Wallwork *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst; 18931b70465SJoe Wallwork PetscFunctionReturn(0); 19031b70465SJoe Wallwork } 19131b70465SJoe Wallwork 192cb7bfe8cSJoe Wallwork /*@ 193cc2eee55SJoe Wallwork DMPlexMetricSetNoInsertion - Should node insertion and deletion be turned off? 194cc2eee55SJoe Wallwork 195cc2eee55SJoe Wallwork Input parameters: 196cc2eee55SJoe Wallwork + dm - The DM 197cc2eee55SJoe Wallwork - noInsert - Should node insertion and deletion be turned off? 198cc2eee55SJoe Wallwork 199cc2eee55SJoe Wallwork Level: beginner 200cc2eee55SJoe Wallwork 201cb7bfe8cSJoe Wallwork Notes: 202cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 203cb7bfe8cSJoe Wallwork 204db781477SPatrick Sanan .seealso: `DMPlexMetricNoInsertion()`, `DMPlexMetricSetNoSwapping()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoSurf()` 205cb7bfe8cSJoe Wallwork @*/ 206cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoInsertion(DM dm, PetscBool noInsert) 207cc2eee55SJoe Wallwork { 208cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 209cc2eee55SJoe Wallwork 210cc2eee55SJoe Wallwork PetscFunctionBegin; 211bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 212cc2eee55SJoe Wallwork plex->metricCtx->noInsert = noInsert; 213cc2eee55SJoe Wallwork PetscFunctionReturn(0); 214cc2eee55SJoe Wallwork } 215cc2eee55SJoe Wallwork 216cb7bfe8cSJoe Wallwork /*@ 217cc2eee55SJoe Wallwork DMPlexMetricNoInsertion - Are node insertion and deletion turned off? 218cc2eee55SJoe Wallwork 219cc2eee55SJoe Wallwork Input parameters: 220cc2eee55SJoe Wallwork . dm - The DM 221cc2eee55SJoe Wallwork 222cc2eee55SJoe Wallwork Output parameters: 223cc2eee55SJoe Wallwork . noInsert - Are node insertion and deletion turned off? 224cc2eee55SJoe Wallwork 225cc2eee55SJoe Wallwork Level: beginner 226cc2eee55SJoe Wallwork 227cb7bfe8cSJoe Wallwork Notes: 228cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 229cb7bfe8cSJoe Wallwork 230db781477SPatrick Sanan .seealso: `DMPlexMetricSetNoInsertion()`, `DMPlexMetricNoSwapping()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoSurf()` 231cb7bfe8cSJoe Wallwork @*/ 232cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoInsertion(DM dm, PetscBool *noInsert) 233cc2eee55SJoe Wallwork { 234cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 235cc2eee55SJoe Wallwork 236cc2eee55SJoe Wallwork PetscFunctionBegin; 237bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 238cc2eee55SJoe Wallwork *noInsert = plex->metricCtx->noInsert; 239cc2eee55SJoe Wallwork PetscFunctionReturn(0); 240cc2eee55SJoe Wallwork } 241cc2eee55SJoe Wallwork 242cb7bfe8cSJoe Wallwork /*@ 243cc2eee55SJoe Wallwork DMPlexMetricSetNoSwapping - Should facet swapping be turned off? 244cc2eee55SJoe Wallwork 245cc2eee55SJoe Wallwork Input parameters: 246cc2eee55SJoe Wallwork + dm - The DM 247cc2eee55SJoe Wallwork - noSwap - Should facet swapping be turned off? 248cc2eee55SJoe Wallwork 249cc2eee55SJoe Wallwork Level: beginner 250cc2eee55SJoe Wallwork 251cb7bfe8cSJoe Wallwork Notes: 252cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 253cb7bfe8cSJoe Wallwork 254db781477SPatrick Sanan .seealso: `DMPlexMetricNoSwapping()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoSurf()` 255cb7bfe8cSJoe Wallwork @*/ 256cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoSwapping(DM dm, PetscBool noSwap) 257cc2eee55SJoe Wallwork { 258cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 259cc2eee55SJoe Wallwork 260cc2eee55SJoe Wallwork PetscFunctionBegin; 261bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 262cc2eee55SJoe Wallwork plex->metricCtx->noSwap = noSwap; 263cc2eee55SJoe Wallwork PetscFunctionReturn(0); 264cc2eee55SJoe Wallwork } 265cc2eee55SJoe Wallwork 266cb7bfe8cSJoe Wallwork /*@ 267cc2eee55SJoe Wallwork DMPlexMetricNoSwapping - Is facet swapping turned off? 268cc2eee55SJoe Wallwork 269cc2eee55SJoe Wallwork Input parameters: 270cc2eee55SJoe Wallwork . dm - The DM 271cc2eee55SJoe Wallwork 272cc2eee55SJoe Wallwork Output parameters: 273cc2eee55SJoe Wallwork . noSwap - Is facet swapping turned off? 274cc2eee55SJoe Wallwork 275cc2eee55SJoe Wallwork Level: beginner 276cc2eee55SJoe Wallwork 277cb7bfe8cSJoe Wallwork Notes: 278cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 279cb7bfe8cSJoe Wallwork 280db781477SPatrick Sanan .seealso: `DMPlexMetricSetNoSwapping()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoSurf()` 281cb7bfe8cSJoe Wallwork @*/ 282cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoSwapping(DM dm, PetscBool *noSwap) 283cc2eee55SJoe Wallwork { 284cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 285cc2eee55SJoe Wallwork 286cc2eee55SJoe Wallwork PetscFunctionBegin; 287bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 288cc2eee55SJoe Wallwork *noSwap = plex->metricCtx->noSwap; 289cc2eee55SJoe Wallwork PetscFunctionReturn(0); 290cc2eee55SJoe Wallwork } 291cc2eee55SJoe Wallwork 292cb7bfe8cSJoe Wallwork /*@ 293cc2eee55SJoe Wallwork DMPlexMetricSetNoMovement - Should node movement be turned off? 294cc2eee55SJoe Wallwork 295cc2eee55SJoe Wallwork Input parameters: 296cc2eee55SJoe Wallwork + dm - The DM 297cc2eee55SJoe Wallwork - noMove - Should node movement be turned off? 298cc2eee55SJoe Wallwork 299cc2eee55SJoe Wallwork Level: beginner 300cc2eee55SJoe Wallwork 301cb7bfe8cSJoe Wallwork Notes: 302cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 303cb7bfe8cSJoe Wallwork 304db781477SPatrick Sanan .seealso: `DMPlexMetricNoMovement()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoSwapping()`, `DMPlexMetricSetNoSurf()` 305cb7bfe8cSJoe Wallwork @*/ 306cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoMovement(DM dm, PetscBool noMove) 307cc2eee55SJoe Wallwork { 308cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 309cc2eee55SJoe Wallwork 310cc2eee55SJoe Wallwork PetscFunctionBegin; 311bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 312cc2eee55SJoe Wallwork plex->metricCtx->noMove = noMove; 313cc2eee55SJoe Wallwork PetscFunctionReturn(0); 314cc2eee55SJoe Wallwork } 315cc2eee55SJoe Wallwork 316cb7bfe8cSJoe Wallwork /*@ 317cc2eee55SJoe Wallwork DMPlexMetricNoMovement - Is node movement turned off? 318cc2eee55SJoe Wallwork 319cc2eee55SJoe Wallwork Input parameters: 320cc2eee55SJoe Wallwork . dm - The DM 321cc2eee55SJoe Wallwork 322cc2eee55SJoe Wallwork Output parameters: 323cc2eee55SJoe Wallwork . noMove - Is node movement turned off? 324cc2eee55SJoe Wallwork 325cc2eee55SJoe Wallwork Level: beginner 326cc2eee55SJoe Wallwork 327cb7bfe8cSJoe Wallwork Notes: 328cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 329cb7bfe8cSJoe Wallwork 330db781477SPatrick Sanan .seealso: `DMPlexMetricSetNoMovement()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoSwapping()`, `DMPlexMetricNoSurf()` 331cb7bfe8cSJoe Wallwork @*/ 332cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoMovement(DM dm, PetscBool *noMove) 333cc2eee55SJoe Wallwork { 334cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 335cc2eee55SJoe Wallwork 336cc2eee55SJoe Wallwork PetscFunctionBegin; 337bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 338cc2eee55SJoe Wallwork *noMove = plex->metricCtx->noMove; 339cc2eee55SJoe Wallwork PetscFunctionReturn(0); 340cc2eee55SJoe Wallwork } 341cc2eee55SJoe Wallwork 342cb7bfe8cSJoe Wallwork /*@ 34376f360caSJoe Wallwork DMPlexMetricSetNoSurf - Should surface modification be turned off? 34476f360caSJoe Wallwork 34576f360caSJoe Wallwork Input parameters: 34676f360caSJoe Wallwork + dm - The DM 34776f360caSJoe Wallwork - noSurf - Should surface modification be turned off? 34876f360caSJoe Wallwork 34976f360caSJoe Wallwork Level: beginner 35076f360caSJoe Wallwork 35176f360caSJoe Wallwork Notes: 35276f360caSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 35376f360caSJoe Wallwork 354db781477SPatrick Sanan .seealso: `DMPlexMetricNoSurf()`, `DMPlexMetricSetNoMovement()`, `DMPlexMetricSetNoInsertion()`, `DMPlexMetricSetNoSwapping()` 35576f360caSJoe Wallwork @*/ 35676f360caSJoe Wallwork PetscErrorCode DMPlexMetricSetNoSurf(DM dm, PetscBool noSurf) 35776f360caSJoe Wallwork { 35876f360caSJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 35976f360caSJoe Wallwork 36076f360caSJoe Wallwork PetscFunctionBegin; 361bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 36276f360caSJoe Wallwork plex->metricCtx->noSurf = noSurf; 36376f360caSJoe Wallwork PetscFunctionReturn(0); 36476f360caSJoe Wallwork } 36576f360caSJoe Wallwork 36676f360caSJoe Wallwork /*@ 36776f360caSJoe Wallwork DMPlexMetricNoSurf - Is surface modification turned off? 36876f360caSJoe Wallwork 36976f360caSJoe Wallwork Input parameters: 37076f360caSJoe Wallwork . dm - The DM 37176f360caSJoe Wallwork 37276f360caSJoe Wallwork Output parameters: 37376f360caSJoe Wallwork . noSurf - Is surface modification turned off? 37476f360caSJoe Wallwork 37576f360caSJoe Wallwork Level: beginner 37676f360caSJoe Wallwork 37776f360caSJoe Wallwork Notes: 37876f360caSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 37976f360caSJoe Wallwork 380db781477SPatrick Sanan .seealso: `DMPlexMetricSetNoSurf()`, `DMPlexMetricNoMovement()`, `DMPlexMetricNoInsertion()`, `DMPlexMetricNoSwapping()` 38176f360caSJoe Wallwork @*/ 38276f360caSJoe Wallwork PetscErrorCode DMPlexMetricNoSurf(DM dm, PetscBool *noSurf) 38376f360caSJoe Wallwork { 38476f360caSJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 38576f360caSJoe Wallwork 38676f360caSJoe Wallwork PetscFunctionBegin; 387bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 38876f360caSJoe Wallwork *noSurf = plex->metricCtx->noSurf; 38976f360caSJoe Wallwork PetscFunctionReturn(0); 39076f360caSJoe Wallwork } 39176f360caSJoe Wallwork 39276f360caSJoe Wallwork /*@ 39331b70465SJoe Wallwork DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude 39431b70465SJoe Wallwork 39531b70465SJoe Wallwork Input parameters: 39631b70465SJoe Wallwork + dm - The DM 39731b70465SJoe Wallwork - h_min - The minimum tolerated metric magnitude 39831b70465SJoe Wallwork 39931b70465SJoe Wallwork Level: beginner 40031b70465SJoe Wallwork 401db781477SPatrick Sanan .seealso: `DMPlexMetricGetMinimumMagnitude()`, `DMPlexMetricSetMaximumMagnitude()` 402cb7bfe8cSJoe Wallwork @*/ 40331b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min) 40431b70465SJoe Wallwork { 40531b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 40631b70465SJoe Wallwork 40731b70465SJoe Wallwork PetscFunctionBegin; 408bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 409bc00d7afSJoe Wallwork PetscCheck(h_min > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric magnitudes must be in (0, inf)"); 41031b70465SJoe Wallwork plex->metricCtx->h_min = h_min; 41131b70465SJoe Wallwork PetscFunctionReturn(0); 41231b70465SJoe Wallwork } 41331b70465SJoe Wallwork 414cb7bfe8cSJoe Wallwork /*@ 41531b70465SJoe Wallwork DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude 41631b70465SJoe Wallwork 41731b70465SJoe Wallwork Input parameters: 41831b70465SJoe Wallwork . dm - The DM 41931b70465SJoe Wallwork 420cc2eee55SJoe Wallwork Output parameters: 42131b70465SJoe Wallwork . h_min - The minimum tolerated metric magnitude 42231b70465SJoe Wallwork 42331b70465SJoe Wallwork Level: beginner 42431b70465SJoe Wallwork 425db781477SPatrick Sanan .seealso: `DMPlexMetricSetMinimumMagnitude()`, `DMPlexMetricGetMaximumMagnitude()` 426cb7bfe8cSJoe Wallwork @*/ 42731b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min) 42831b70465SJoe Wallwork { 42931b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 43031b70465SJoe Wallwork 43131b70465SJoe Wallwork PetscFunctionBegin; 432bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 43331b70465SJoe Wallwork *h_min = plex->metricCtx->h_min; 43431b70465SJoe Wallwork PetscFunctionReturn(0); 43531b70465SJoe Wallwork } 43631b70465SJoe Wallwork 437cb7bfe8cSJoe Wallwork /*@ 43831b70465SJoe Wallwork DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude 43931b70465SJoe Wallwork 44031b70465SJoe Wallwork Input parameters: 44131b70465SJoe Wallwork + dm - The DM 44231b70465SJoe Wallwork - h_max - The maximum tolerated metric magnitude 44331b70465SJoe Wallwork 44431b70465SJoe Wallwork Level: beginner 44531b70465SJoe Wallwork 446db781477SPatrick Sanan .seealso: `DMPlexMetricGetMaximumMagnitude()`, `DMPlexMetricSetMinimumMagnitude()` 447cb7bfe8cSJoe Wallwork @*/ 44831b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max) 44931b70465SJoe Wallwork { 45031b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 45131b70465SJoe Wallwork 45231b70465SJoe Wallwork PetscFunctionBegin; 453bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 454bc00d7afSJoe Wallwork PetscCheck(h_max > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric magnitudes must be in (0, inf)"); 45531b70465SJoe Wallwork plex->metricCtx->h_max = h_max; 45631b70465SJoe Wallwork PetscFunctionReturn(0); 45731b70465SJoe Wallwork } 45831b70465SJoe Wallwork 459cb7bfe8cSJoe Wallwork /*@ 46031b70465SJoe Wallwork DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude 46131b70465SJoe Wallwork 46231b70465SJoe Wallwork Input parameters: 46331b70465SJoe Wallwork . dm - The DM 46431b70465SJoe Wallwork 465cc2eee55SJoe Wallwork Output parameters: 46631b70465SJoe Wallwork . h_max - The maximum tolerated metric magnitude 46731b70465SJoe Wallwork 46831b70465SJoe Wallwork Level: beginner 46931b70465SJoe Wallwork 470db781477SPatrick Sanan .seealso: `DMPlexMetricSetMaximumMagnitude()`, `DMPlexMetricGetMinimumMagnitude()` 471cb7bfe8cSJoe Wallwork @*/ 47231b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max) 47331b70465SJoe Wallwork { 47431b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 47531b70465SJoe Wallwork 47631b70465SJoe Wallwork PetscFunctionBegin; 477bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 47831b70465SJoe Wallwork *h_max = plex->metricCtx->h_max; 47931b70465SJoe Wallwork PetscFunctionReturn(0); 48031b70465SJoe Wallwork } 48131b70465SJoe Wallwork 482cb7bfe8cSJoe Wallwork /*@ 48331b70465SJoe Wallwork DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy 48431b70465SJoe Wallwork 48531b70465SJoe Wallwork Input parameters: 48631b70465SJoe Wallwork + dm - The DM 48731b70465SJoe Wallwork - a_max - The maximum tolerated metric anisotropy 48831b70465SJoe Wallwork 48931b70465SJoe Wallwork Level: beginner 49031b70465SJoe Wallwork 49131b70465SJoe Wallwork Note: If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one. 49231b70465SJoe Wallwork 493db781477SPatrick Sanan .seealso: `DMPlexMetricGetMaximumAnisotropy()`, `DMPlexMetricSetMaximumMagnitude()` 494cb7bfe8cSJoe Wallwork @*/ 49531b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max) 49631b70465SJoe Wallwork { 49731b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 49831b70465SJoe Wallwork 49931b70465SJoe Wallwork PetscFunctionBegin; 500bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 501bc00d7afSJoe Wallwork PetscCheck(a_max >= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Anisotropy must be in [1, inf)"); 50231b70465SJoe Wallwork plex->metricCtx->a_max = a_max; 50331b70465SJoe Wallwork PetscFunctionReturn(0); 50431b70465SJoe Wallwork } 50531b70465SJoe Wallwork 506cb7bfe8cSJoe Wallwork /*@ 50731b70465SJoe Wallwork DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy 50831b70465SJoe Wallwork 50931b70465SJoe Wallwork Input parameters: 51031b70465SJoe Wallwork . dm - The DM 51131b70465SJoe Wallwork 512cc2eee55SJoe Wallwork Output parameters: 51331b70465SJoe Wallwork . a_max - The maximum tolerated metric anisotropy 51431b70465SJoe Wallwork 51531b70465SJoe Wallwork Level: beginner 51631b70465SJoe Wallwork 517db781477SPatrick Sanan .seealso: `DMPlexMetricSetMaximumAnisotropy()`, `DMPlexMetricGetMaximumMagnitude()` 518cb7bfe8cSJoe Wallwork @*/ 51931b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max) 52031b70465SJoe Wallwork { 52131b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 52231b70465SJoe Wallwork 52331b70465SJoe Wallwork PetscFunctionBegin; 524bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 52531b70465SJoe Wallwork *a_max = plex->metricCtx->a_max; 52631b70465SJoe Wallwork PetscFunctionReturn(0); 52731b70465SJoe Wallwork } 52831b70465SJoe Wallwork 529cb7bfe8cSJoe Wallwork /*@ 53031b70465SJoe Wallwork DMPlexMetricSetTargetComplexity - Set the target metric complexity 53131b70465SJoe Wallwork 53231b70465SJoe Wallwork Input parameters: 53331b70465SJoe Wallwork + dm - The DM 53431b70465SJoe Wallwork - targetComplexity - The target metric complexity 53531b70465SJoe Wallwork 53631b70465SJoe Wallwork Level: beginner 53731b70465SJoe Wallwork 538db781477SPatrick Sanan .seealso: `DMPlexMetricGetTargetComplexity()`, `DMPlexMetricSetNormalizationOrder()` 539cb7bfe8cSJoe Wallwork @*/ 54031b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity) 54131b70465SJoe Wallwork { 54231b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 54331b70465SJoe Wallwork 54431b70465SJoe Wallwork PetscFunctionBegin; 545bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 546bc00d7afSJoe Wallwork PetscCheck(targetComplexity > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric complexity must be in (0, inf)"); 54731b70465SJoe Wallwork plex->metricCtx->targetComplexity = targetComplexity; 54831b70465SJoe Wallwork PetscFunctionReturn(0); 54931b70465SJoe Wallwork } 55031b70465SJoe Wallwork 551cb7bfe8cSJoe Wallwork /*@ 55231b70465SJoe Wallwork DMPlexMetricGetTargetComplexity - Get the target metric complexity 55331b70465SJoe Wallwork 55431b70465SJoe Wallwork Input parameters: 55531b70465SJoe Wallwork . dm - The DM 55631b70465SJoe Wallwork 557cc2eee55SJoe Wallwork Output parameters: 55831b70465SJoe Wallwork . targetComplexity - The target metric complexity 55931b70465SJoe Wallwork 56031b70465SJoe Wallwork Level: beginner 56131b70465SJoe Wallwork 562db781477SPatrick Sanan .seealso: `DMPlexMetricSetTargetComplexity()`, `DMPlexMetricGetNormalizationOrder()` 563cb7bfe8cSJoe Wallwork @*/ 56431b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity) 56531b70465SJoe Wallwork { 56631b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 56731b70465SJoe Wallwork 56831b70465SJoe Wallwork PetscFunctionBegin; 569bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 57031b70465SJoe Wallwork *targetComplexity = plex->metricCtx->targetComplexity; 57131b70465SJoe Wallwork PetscFunctionReturn(0); 57231b70465SJoe Wallwork } 57331b70465SJoe Wallwork 574cb7bfe8cSJoe Wallwork /*@ 57531b70465SJoe Wallwork DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization 57631b70465SJoe Wallwork 57731b70465SJoe Wallwork Input parameters: 57831b70465SJoe Wallwork + dm - The DM 57931b70465SJoe Wallwork - p - The normalization order 58031b70465SJoe Wallwork 58131b70465SJoe Wallwork Level: beginner 58231b70465SJoe Wallwork 583db781477SPatrick Sanan .seealso: `DMPlexMetricGetNormalizationOrder()`, `DMPlexMetricSetTargetComplexity()` 584cb7bfe8cSJoe Wallwork @*/ 58531b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p) 58631b70465SJoe Wallwork { 58731b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 58831b70465SJoe Wallwork 58931b70465SJoe Wallwork PetscFunctionBegin; 590bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 591bc00d7afSJoe Wallwork PetscCheck(p >= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Normalization order must be in [1, inf)"); 59231b70465SJoe Wallwork plex->metricCtx->p = p; 59331b70465SJoe Wallwork PetscFunctionReturn(0); 59431b70465SJoe Wallwork } 59531b70465SJoe Wallwork 596cb7bfe8cSJoe Wallwork /*@ 59731b70465SJoe Wallwork DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization 59831b70465SJoe Wallwork 59931b70465SJoe Wallwork Input parameters: 60031b70465SJoe Wallwork . dm - The DM 60131b70465SJoe Wallwork 602cc2eee55SJoe Wallwork Output parameters: 60331b70465SJoe Wallwork . p - The normalization order 60431b70465SJoe Wallwork 60531b70465SJoe Wallwork Level: beginner 60631b70465SJoe Wallwork 607db781477SPatrick Sanan .seealso: `DMPlexMetricSetNormalizationOrder()`, `DMPlexMetricGetTargetComplexity()` 608cb7bfe8cSJoe Wallwork @*/ 60931b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p) 61031b70465SJoe Wallwork { 61131b70465SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 61231b70465SJoe Wallwork 61331b70465SJoe Wallwork PetscFunctionBegin; 614bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 61531b70465SJoe Wallwork *p = plex->metricCtx->p; 61631b70465SJoe Wallwork PetscFunctionReturn(0); 61731b70465SJoe Wallwork } 61831b70465SJoe Wallwork 619cb7bfe8cSJoe Wallwork /*@ 620cc2eee55SJoe Wallwork DMPlexMetricSetGradationFactor - Set the metric gradation factor 621cc2eee55SJoe Wallwork 622cc2eee55SJoe Wallwork Input parameters: 623cc2eee55SJoe Wallwork + dm - The DM 624cc2eee55SJoe Wallwork - beta - The metric gradation factor 625cc2eee55SJoe Wallwork 626cc2eee55SJoe Wallwork Level: beginner 627cc2eee55SJoe Wallwork 628cc2eee55SJoe Wallwork Notes: 629cc2eee55SJoe Wallwork 630cc2eee55SJoe Wallwork The gradation factor is the maximum tolerated length ratio between adjacent edges. 631cc2eee55SJoe Wallwork 632cc2eee55SJoe Wallwork Turn off gradation by passing the value -1. Otherwise, pass a positive value. 633cc2eee55SJoe Wallwork 634cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 635cb7bfe8cSJoe Wallwork 636db781477SPatrick Sanan .seealso: `DMPlexMetricGetGradationFactor()`, `DMPlexMetricSetHausdorffNumber()` 637cb7bfe8cSJoe Wallwork @*/ 638cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetGradationFactor(DM dm, PetscReal beta) 639cc2eee55SJoe Wallwork { 640cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 641cc2eee55SJoe Wallwork 642cc2eee55SJoe Wallwork PetscFunctionBegin; 643bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 644bc00d7afSJoe Wallwork PetscCheck(beta > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric gradation factor must be in (0, inf)"); 645cc2eee55SJoe Wallwork plex->metricCtx->gradationFactor = beta; 646cc2eee55SJoe Wallwork PetscFunctionReturn(0); 647cc2eee55SJoe Wallwork } 648cc2eee55SJoe Wallwork 649cb7bfe8cSJoe Wallwork /*@ 650cc2eee55SJoe Wallwork DMPlexMetricGetGradationFactor - Get the metric gradation factor 651cc2eee55SJoe Wallwork 652cc2eee55SJoe Wallwork Input parameters: 653cc2eee55SJoe Wallwork . dm - The DM 654cc2eee55SJoe Wallwork 655cc2eee55SJoe Wallwork Output parameters: 656cc2eee55SJoe Wallwork . beta - The metric gradation factor 657cc2eee55SJoe Wallwork 658cc2eee55SJoe Wallwork Level: beginner 659cc2eee55SJoe Wallwork 660cb7bfe8cSJoe Wallwork Notes: 661cb7bfe8cSJoe Wallwork 662cb7bfe8cSJoe Wallwork The gradation factor is the maximum tolerated length ratio between adjacent edges. 663cb7bfe8cSJoe Wallwork 664cb7bfe8cSJoe Wallwork The value -1 implies that gradation is turned off. 665cb7bfe8cSJoe Wallwork 666cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 667cc2eee55SJoe Wallwork 668db781477SPatrick Sanan .seealso: `DMPlexMetricSetGradationFactor()`, `DMPlexMetricGetHausdorffNumber()` 669cb7bfe8cSJoe Wallwork @*/ 670cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetGradationFactor(DM dm, PetscReal *beta) 671cc2eee55SJoe Wallwork { 672cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 673cc2eee55SJoe Wallwork 674cc2eee55SJoe Wallwork PetscFunctionBegin; 675bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 676cc2eee55SJoe Wallwork *beta = plex->metricCtx->gradationFactor; 677cc2eee55SJoe Wallwork PetscFunctionReturn(0); 678cc2eee55SJoe Wallwork } 679cc2eee55SJoe Wallwork 680cb7bfe8cSJoe Wallwork /*@ 681ae8b063eSJoe Wallwork DMPlexMetricSetHausdorffNumber - Set the metric Hausdorff number 682ae8b063eSJoe Wallwork 683ae8b063eSJoe Wallwork Input parameters: 684ae8b063eSJoe Wallwork + dm - The DM 685ae8b063eSJoe Wallwork - hausd - The metric Hausdorff number 686ae8b063eSJoe Wallwork 687ae8b063eSJoe Wallwork Level: beginner 688ae8b063eSJoe Wallwork 689ae8b063eSJoe Wallwork Notes: 690ae8b063eSJoe Wallwork 691ae8b063eSJoe Wallwork The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the 692ae8b063eSJoe Wallwork boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the 693ae8b063eSJoe Wallwork high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for 694ae8b063eSJoe Wallwork an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease 695ae8b063eSJoe Wallwork (resp. increase) the Hausdorff parameter. (Taken from 696ae8b063eSJoe Wallwork https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd). 697ae8b063eSJoe Wallwork 698ae8b063eSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 699ae8b063eSJoe Wallwork 700db781477SPatrick Sanan .seealso: `DMPlexMetricSetGradationFactor()`, `DMPlexMetricGetHausdorffNumber()` 701ae8b063eSJoe Wallwork @*/ 702ae8b063eSJoe Wallwork PetscErrorCode DMPlexMetricSetHausdorffNumber(DM dm, PetscReal hausd) 703ae8b063eSJoe Wallwork { 704ae8b063eSJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 705ae8b063eSJoe Wallwork 706ae8b063eSJoe Wallwork PetscFunctionBegin; 707bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 708bc00d7afSJoe Wallwork PetscCheck(hausd > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Metric Hausdorff number must be in (0, inf)"); 709ae8b063eSJoe Wallwork plex->metricCtx->hausdorffNumber = hausd; 710ae8b063eSJoe Wallwork PetscFunctionReturn(0); 711ae8b063eSJoe Wallwork } 712ae8b063eSJoe Wallwork 713ae8b063eSJoe Wallwork /*@ 714ae8b063eSJoe Wallwork DMPlexMetricGetHausdorffNumber - Get the metric Hausdorff number 715ae8b063eSJoe Wallwork 716ae8b063eSJoe Wallwork Input parameters: 717ae8b063eSJoe Wallwork . dm - The DM 718ae8b063eSJoe Wallwork 719ae8b063eSJoe Wallwork Output parameters: 720ae8b063eSJoe Wallwork . hausd - The metric Hausdorff number 721ae8b063eSJoe Wallwork 722ae8b063eSJoe Wallwork Level: beginner 723ae8b063eSJoe Wallwork 724ae8b063eSJoe Wallwork Notes: 725ae8b063eSJoe Wallwork 726ae8b063eSJoe Wallwork The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the 727ae8b063eSJoe Wallwork boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the 728ae8b063eSJoe Wallwork high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for 729ae8b063eSJoe Wallwork an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease 730ae8b063eSJoe Wallwork (resp. increase) the Hausdorff parameter. (Taken from 731ae8b063eSJoe Wallwork https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd). 732ae8b063eSJoe Wallwork 733ae8b063eSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 734ae8b063eSJoe Wallwork 735db781477SPatrick Sanan .seealso: `DMPlexMetricGetGradationFactor()`, `DMPlexMetricSetHausdorffNumber()` 736ae8b063eSJoe Wallwork @*/ 737ae8b063eSJoe Wallwork PetscErrorCode DMPlexMetricGetHausdorffNumber(DM dm, PetscReal *hausd) 738ae8b063eSJoe Wallwork { 739ae8b063eSJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 740ae8b063eSJoe Wallwork 741ae8b063eSJoe Wallwork PetscFunctionBegin; 742bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 743ae8b063eSJoe Wallwork *hausd = plex->metricCtx->hausdorffNumber; 744ae8b063eSJoe Wallwork PetscFunctionReturn(0); 745ae8b063eSJoe Wallwork } 746ae8b063eSJoe Wallwork 747ae8b063eSJoe Wallwork /*@ 748cc2eee55SJoe Wallwork DMPlexMetricSetVerbosity - Set the verbosity of the mesh adaptation package 749cc2eee55SJoe Wallwork 750cc2eee55SJoe Wallwork Input parameters: 751cc2eee55SJoe Wallwork + dm - The DM 752cc2eee55SJoe Wallwork - verbosity - The verbosity, where -1 is silent and 10 is maximum 753cc2eee55SJoe Wallwork 754cb7bfe8cSJoe Wallwork Level: beginner 755cb7bfe8cSJoe Wallwork 756cb7bfe8cSJoe Wallwork Notes: 757cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 758cb7bfe8cSJoe Wallwork 759db781477SPatrick Sanan .seealso: `DMPlexMetricGetVerbosity()`, `DMPlexMetricSetNumIterations()` 760cb7bfe8cSJoe Wallwork @*/ 761cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetVerbosity(DM dm, PetscInt verbosity) 762cc2eee55SJoe Wallwork { 763cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 764cc2eee55SJoe Wallwork 765cc2eee55SJoe Wallwork PetscFunctionBegin; 766bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 767cc2eee55SJoe Wallwork plex->metricCtx->verbosity = verbosity; 768cc2eee55SJoe Wallwork PetscFunctionReturn(0); 769cc2eee55SJoe Wallwork } 770cc2eee55SJoe Wallwork 771cb7bfe8cSJoe Wallwork /*@ 772cc2eee55SJoe Wallwork DMPlexMetricGetVerbosity - Get the verbosity of the mesh adaptation package 773cc2eee55SJoe Wallwork 774cc2eee55SJoe Wallwork Input parameters: 775cc2eee55SJoe Wallwork . dm - The DM 776cc2eee55SJoe Wallwork 777cc2eee55SJoe Wallwork Output parameters: 778cc2eee55SJoe Wallwork . verbosity - The verbosity, where -1 is silent and 10 is maximum 779cc2eee55SJoe Wallwork 780cb7bfe8cSJoe Wallwork Level: beginner 781cb7bfe8cSJoe Wallwork 782cb7bfe8cSJoe Wallwork Notes: 783cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic). 784cb7bfe8cSJoe Wallwork 785db781477SPatrick Sanan .seealso: `DMPlexMetricSetVerbosity()`, `DMPlexMetricGetNumIterations()` 786cb7bfe8cSJoe Wallwork @*/ 787cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetVerbosity(DM dm, PetscInt *verbosity) 788cc2eee55SJoe Wallwork { 789cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 790cc2eee55SJoe Wallwork 791cc2eee55SJoe Wallwork PetscFunctionBegin; 792bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 793cc2eee55SJoe Wallwork *verbosity = plex->metricCtx->verbosity; 794cc2eee55SJoe Wallwork PetscFunctionReturn(0); 795cc2eee55SJoe Wallwork } 796cc2eee55SJoe Wallwork 797cb7bfe8cSJoe Wallwork /*@ 798cc2eee55SJoe Wallwork DMPlexMetricSetNumIterations - Set the number of parallel adaptation iterations 799cc2eee55SJoe Wallwork 800cc2eee55SJoe Wallwork Input parameters: 801cc2eee55SJoe Wallwork + dm - The DM 802cc2eee55SJoe Wallwork - numIter - the number of parallel adaptation iterations 803cc2eee55SJoe Wallwork 804cb7bfe8cSJoe Wallwork Level: beginner 805cb7bfe8cSJoe Wallwork 806cb7bfe8cSJoe Wallwork Notes: 807cb7bfe8cSJoe Wallwork This is only used by ParMmg (not Pragmatic or Mmg). 808cc2eee55SJoe Wallwork 809db781477SPatrick Sanan .seealso: `DMPlexMetricSetVerbosity()`, `DMPlexMetricGetNumIterations()` 810cb7bfe8cSJoe Wallwork @*/ 811cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNumIterations(DM dm, PetscInt numIter) 812cc2eee55SJoe Wallwork { 813cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 814cc2eee55SJoe Wallwork 815cc2eee55SJoe Wallwork PetscFunctionBegin; 816bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 817cc2eee55SJoe Wallwork plex->metricCtx->numIter = numIter; 818cc2eee55SJoe Wallwork PetscFunctionReturn(0); 819cc2eee55SJoe Wallwork } 820cc2eee55SJoe Wallwork 821cb7bfe8cSJoe Wallwork /*@ 822cc2eee55SJoe Wallwork DMPlexMetricGetNumIterations - Get the number of parallel adaptation iterations 823cc2eee55SJoe Wallwork 824cc2eee55SJoe Wallwork Input parameters: 825cc2eee55SJoe Wallwork . dm - The DM 826cc2eee55SJoe Wallwork 827cc2eee55SJoe Wallwork Output parameters: 828cc2eee55SJoe Wallwork . numIter - the number of parallel adaptation iterations 829cc2eee55SJoe Wallwork 830cb7bfe8cSJoe Wallwork Level: beginner 831cb7bfe8cSJoe Wallwork 832cb7bfe8cSJoe Wallwork Notes: 833cb7bfe8cSJoe Wallwork This is only used by Mmg and ParMmg (not Pragmatic or Mmg). 834cc2eee55SJoe Wallwork 835db781477SPatrick Sanan .seealso: `DMPlexMetricSetNumIterations()`, `DMPlexMetricGetVerbosity()` 836cb7bfe8cSJoe Wallwork @*/ 837cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetNumIterations(DM dm, PetscInt *numIter) 838cc2eee55SJoe Wallwork { 839cc2eee55SJoe Wallwork DM_Plex *plex = (DM_Plex *) dm->data; 840cc2eee55SJoe Wallwork 841cc2eee55SJoe Wallwork PetscFunctionBegin; 842bc00d7afSJoe Wallwork if (!plex->metricCtx) PetscCall(DMPlexMetricSetFromOptions(dm)); 843cc2eee55SJoe Wallwork *numIter = plex->metricCtx->numIter; 844cc2eee55SJoe Wallwork PetscFunctionReturn(0); 845cc2eee55SJoe Wallwork } 846cc2eee55SJoe Wallwork 84720282da2SJoe Wallwork PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric) 84820282da2SJoe Wallwork { 84920282da2SJoe Wallwork MPI_Comm comm; 85020282da2SJoe Wallwork PetscFE fe; 85120282da2SJoe Wallwork PetscInt dim; 85220282da2SJoe Wallwork 85320282da2SJoe Wallwork PetscFunctionBegin; 85420282da2SJoe Wallwork 85520282da2SJoe Wallwork /* Extract metadata from dm */ 8569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8579566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 85820282da2SJoe Wallwork 85920282da2SJoe Wallwork /* Create a P1 field of the requested size */ 8609566063dSJacob Faibussowitsch PetscCall(PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe)); 8619566063dSJacob Faibussowitsch PetscCall(DMSetField(dm, f, NULL, (PetscObject)fe)); 8629566063dSJacob Faibussowitsch PetscCall(DMCreateDS(dm)); 8639566063dSJacob Faibussowitsch PetscCall(PetscFEDestroy(&fe)); 8649566063dSJacob Faibussowitsch PetscCall(DMCreateLocalVector(dm, metric)); 86520282da2SJoe Wallwork 86620282da2SJoe Wallwork PetscFunctionReturn(0); 86720282da2SJoe Wallwork } 86820282da2SJoe Wallwork 869cb7bfe8cSJoe Wallwork /*@ 87020282da2SJoe Wallwork DMPlexMetricCreate - Create a Riemannian metric field 87120282da2SJoe Wallwork 87220282da2SJoe Wallwork Input parameters: 87320282da2SJoe Wallwork + dm - The DM 87420282da2SJoe Wallwork - f - The field number to use 87520282da2SJoe Wallwork 87620282da2SJoe Wallwork Output parameter: 87720282da2SJoe Wallwork . metric - The metric 87820282da2SJoe Wallwork 87920282da2SJoe Wallwork Level: beginner 88020282da2SJoe Wallwork 88131b70465SJoe Wallwork Notes: 88231b70465SJoe Wallwork 88331b70465SJoe Wallwork It is assumed that the DM is comprised of simplices. 88431b70465SJoe Wallwork 88531b70465SJoe Wallwork Command line options for Riemannian metrics: 88631b70465SJoe Wallwork 887cb7bfe8cSJoe Wallwork + -dm_plex_metric_isotropic - Is the metric isotropic? 88893520041SJoe Wallwork . -dm_plex_metric_uniform - Is the metric uniform? 889cb7bfe8cSJoe Wallwork . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 890cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 891cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 892cb7bfe8cSJoe Wallwork . -dm_plex_metric_a_max - Maximum tolerated anisotropy 893cb7bfe8cSJoe Wallwork . -dm_plex_metric_p - L-p normalization order 89467b8a455SSatish Balay - -dm_plex_metric_target_complexity - Target metric complexity 895cb7bfe8cSJoe Wallwork 896cb7bfe8cSJoe Wallwork Switching between remeshers can be achieved using 897cb7bfe8cSJoe Wallwork 89867b8a455SSatish Balay . -dm_adaptor <pragmatic/mmg/parmmg> - specify dm adaptor to use 899cb7bfe8cSJoe Wallwork 900cb7bfe8cSJoe Wallwork Further options that are only relevant to Mmg and ParMmg: 901cb7bfe8cSJoe Wallwork 902cb7bfe8cSJoe Wallwork + -dm_plex_metric_gradation_factor - Maximum ratio by which edge lengths may grow during gradation 903cb7bfe8cSJoe Wallwork . -dm_plex_metric_num_iterations - Number of parallel mesh adaptation iterations for ParMmg 904cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_insert - Should node insertion/deletion be turned off? 905cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_swap - Should facet swapping be turned off? 906cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_move - Should node movement be turned off? 907cb7bfe8cSJoe Wallwork - -dm_plex_metric_verbosity - Choose a verbosity level from -1 (silent) to 10 (maximum). 90820282da2SJoe Wallwork 909db781477SPatrick Sanan .seealso: `DMPlexMetricCreateUniform()`, `DMPlexMetricCreateIsotropic()` 910cb7bfe8cSJoe Wallwork @*/ 91120282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric) 91220282da2SJoe Wallwork { 91393520041SJoe Wallwork PetscBool isotropic, uniform; 91420282da2SJoe Wallwork PetscInt coordDim, Nd; 91520282da2SJoe Wallwork 91620282da2SJoe Wallwork PetscFunctionBegin; 9179566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &coordDim)); 91820282da2SJoe Wallwork Nd = coordDim*coordDim; 9199566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 9209566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 92193520041SJoe Wallwork if (uniform) { 92293520041SJoe Wallwork MPI_Comm comm; 92393520041SJoe Wallwork 9249566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 925bc00d7afSJoe Wallwork PetscCheck(isotropic, comm, PETSC_ERR_SUP, "Uniform anisotropic metrics not supported"); 9269566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, metric)); 9279566063dSJacob Faibussowitsch PetscCall(VecSetSizes(*metric, 1, PETSC_DECIDE)); 9289566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(*metric)); 929f6db075bSJoe Wallwork } else if (isotropic) PetscCall(DMPlexP1FieldCreate_Private(dm, f, 1, metric)); 930f6db075bSJoe Wallwork else PetscCall(DMPlexP1FieldCreate_Private(dm, f, Nd, metric)); 93120282da2SJoe Wallwork PetscFunctionReturn(0); 93220282da2SJoe Wallwork } 93320282da2SJoe Wallwork 934cb7bfe8cSJoe Wallwork /*@ 93520282da2SJoe Wallwork DMPlexMetricCreateUniform - Construct a uniform isotropic metric 93620282da2SJoe Wallwork 93720282da2SJoe Wallwork Input parameters: 93820282da2SJoe Wallwork + dm - The DM 93920282da2SJoe Wallwork . f - The field number to use 94020282da2SJoe Wallwork - alpha - Scaling parameter for the diagonal 94120282da2SJoe Wallwork 94220282da2SJoe Wallwork Output parameter: 94320282da2SJoe Wallwork . metric - The uniform metric 94420282da2SJoe Wallwork 94520282da2SJoe Wallwork Level: beginner 94620282da2SJoe Wallwork 94793520041SJoe Wallwork Note: In this case, the metric is constant in space and so is only specified for a single vertex. 94820282da2SJoe Wallwork 949db781477SPatrick Sanan .seealso: `DMPlexMetricCreate()`, `DMPlexMetricCreateIsotropic()` 950cb7bfe8cSJoe Wallwork @*/ 95120282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric) 95220282da2SJoe Wallwork { 95320282da2SJoe Wallwork PetscFunctionBegin; 9549566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetUniform(dm, PETSC_TRUE)); 9559566063dSJacob Faibussowitsch PetscCall(DMPlexMetricCreate(dm, f, metric)); 9562c71b3e2SJacob Faibussowitsch PetscCheck(alpha, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined"); 957bc00d7afSJoe Wallwork PetscCheck(alpha > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Uniform metric scaling should be in (0, inf)"); 9589566063dSJacob Faibussowitsch PetscCall(VecSet(*metric, alpha)); 9599566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(*metric)); 9609566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd(*metric)); 96120282da2SJoe Wallwork PetscFunctionReturn(0); 96220282da2SJoe Wallwork } 96320282da2SJoe Wallwork 96493520041SJoe Wallwork static void identity(PetscInt dim, PetscInt Nf, PetscInt NfAux, 96593520041SJoe Wallwork const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 96693520041SJoe Wallwork const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 96793520041SJoe Wallwork PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 96893520041SJoe Wallwork { 96993520041SJoe Wallwork f0[0] = u[0]; 97093520041SJoe Wallwork } 97193520041SJoe Wallwork 972cb7bfe8cSJoe Wallwork /*@ 97320282da2SJoe Wallwork DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator 97420282da2SJoe Wallwork 97520282da2SJoe Wallwork Input parameters: 97620282da2SJoe Wallwork + dm - The DM 97720282da2SJoe Wallwork . f - The field number to use 97820282da2SJoe Wallwork - indicator - The error indicator 97920282da2SJoe Wallwork 98020282da2SJoe Wallwork Output parameter: 98120282da2SJoe Wallwork . metric - The isotropic metric 98220282da2SJoe Wallwork 98320282da2SJoe Wallwork Level: beginner 98420282da2SJoe Wallwork 98520282da2SJoe Wallwork Notes: 98620282da2SJoe Wallwork 98720282da2SJoe Wallwork It is assumed that the DM is comprised of simplices. 98820282da2SJoe Wallwork 98993520041SJoe Wallwork The indicator needs to be a scalar field. If it is not defined vertex-wise, then it is projected appropriately. 99020282da2SJoe Wallwork 991db781477SPatrick Sanan .seealso: `DMPlexMetricCreate()`, `DMPlexMetricCreateUniform()` 992cb7bfe8cSJoe Wallwork @*/ 99320282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric) 99420282da2SJoe Wallwork { 99593520041SJoe Wallwork PetscInt m, n; 99620282da2SJoe Wallwork 99720282da2SJoe Wallwork PetscFunctionBegin; 9989566063dSJacob Faibussowitsch PetscCall(DMPlexMetricSetIsotropic(dm, PETSC_TRUE)); 9999566063dSJacob Faibussowitsch PetscCall(DMPlexMetricCreate(dm, f, metric)); 10009566063dSJacob Faibussowitsch PetscCall(VecGetSize(indicator, &m)); 10019566063dSJacob Faibussowitsch PetscCall(VecGetSize(*metric, &n)); 10029566063dSJacob Faibussowitsch if (m == n) PetscCall(VecCopy(indicator, *metric)); 100393520041SJoe Wallwork else { 100493520041SJoe Wallwork DM dmIndi; 100593520041SJoe Wallwork void (*funcs[1])(PetscInt, PetscInt, PetscInt, 100693520041SJoe Wallwork const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 100793520041SJoe Wallwork const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 100893520041SJoe Wallwork PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 100993520041SJoe Wallwork 10109566063dSJacob Faibussowitsch PetscCall(VecGetDM(indicator, &dmIndi)); 101193520041SJoe Wallwork funcs[0] = identity; 10129566063dSJacob Faibussowitsch PetscCall(DMProjectFieldLocal(dmIndi, 0.0, indicator, funcs, INSERT_VALUES, *metric)); 101320282da2SJoe Wallwork } 101420282da2SJoe Wallwork PetscFunctionReturn(0); 101520282da2SJoe Wallwork } 101620282da2SJoe Wallwork 1017f6db075bSJoe Wallwork /*@ 1018f6db075bSJoe Wallwork DMPlexMetricDeterminantCreate - Create the determinant field for a Riemannian metric 1019f6db075bSJoe Wallwork 1020f6db075bSJoe Wallwork Input parameters: 1021f6db075bSJoe Wallwork + dm - The DM of the metric field 1022f6db075bSJoe Wallwork - f - The field number to use 1023f6db075bSJoe Wallwork 1024f6db075bSJoe Wallwork Output parameter: 1025f6db075bSJoe Wallwork + determinant - The determinant field 1026f6db075bSJoe Wallwork - dmDet - The corresponding DM 1027f6db075bSJoe Wallwork 1028f6db075bSJoe Wallwork Level: beginner 1029f6db075bSJoe Wallwork 1030f6db075bSJoe Wallwork .seealso: DMPlexMetricCreateUniform(), DMPlexMetricCreateIsotropic(), DMPlexMetricCreate() 1031f6db075bSJoe Wallwork @*/ 1032f6db075bSJoe Wallwork PetscErrorCode DMPlexMetricDeterminantCreate(DM dm, PetscInt f, Vec *determinant, DM *dmDet) 1033f6db075bSJoe Wallwork { 1034f6db075bSJoe Wallwork PetscBool uniform; 1035f6db075bSJoe Wallwork 1036f6db075bSJoe Wallwork PetscFunctionBegin; 1037f6db075bSJoe Wallwork PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 1038f6db075bSJoe Wallwork PetscCall(DMClone(dm, dmDet)); 1039f6db075bSJoe Wallwork if (uniform) { 1040f6db075bSJoe Wallwork MPI_Comm comm; 1041f6db075bSJoe Wallwork 1042f6db075bSJoe Wallwork PetscCall(PetscObjectGetComm((PetscObject) *dmDet, &comm)); 1043f6db075bSJoe Wallwork PetscCall(VecCreate(comm, determinant)); 1044f6db075bSJoe Wallwork PetscCall(VecSetSizes(*determinant, 1, PETSC_DECIDE)); 1045f6db075bSJoe Wallwork PetscCall(VecSetFromOptions(*determinant)); 1046f6db075bSJoe Wallwork } else PetscCall(DMPlexP1FieldCreate_Private(*dmDet, f, 1, determinant)); 1047f6db075bSJoe Wallwork PetscFunctionReturn(0); 1048f6db075bSJoe Wallwork } 1049f6db075bSJoe Wallwork 105082490253SJoe Wallwork static PetscErrorCode LAPACKsyevFail(PetscInt dim, PetscScalar Mpos[]) 105182490253SJoe Wallwork { 105282490253SJoe Wallwork PetscInt i, j; 105382490253SJoe Wallwork 105482490253SJoe Wallwork PetscFunctionBegin; 105582490253SJoe Wallwork PetscPrintf(PETSC_COMM_SELF, "Failed to apply LAPACKsyev to the matrix\n"); 105682490253SJoe Wallwork for (i = 0; i < dim; ++i) { 105782490253SJoe Wallwork if (i == 0) PetscPrintf(PETSC_COMM_SELF, " [["); 105882490253SJoe Wallwork else PetscPrintf(PETSC_COMM_SELF, " ["); 105982490253SJoe Wallwork for (j = 0; j < dim; ++j) { 106063a3b9bcSJacob Faibussowitsch if (j < dim-1) PetscPrintf(PETSC_COMM_SELF, "%15.8e, ", (double)PetscAbsScalar(Mpos[i*dim+j])); 106163a3b9bcSJacob Faibussowitsch else PetscPrintf(PETSC_COMM_SELF, "%15.8e", (double)PetscAbsScalar(Mpos[i*dim+j])); 106282490253SJoe Wallwork } 106382490253SJoe Wallwork if (i < dim-1) PetscPrintf(PETSC_COMM_SELF, "]\n"); 106482490253SJoe Wallwork else PetscPrintf(PETSC_COMM_SELF, "]]\n"); 106582490253SJoe Wallwork } 106682490253SJoe Wallwork PetscFunctionReturn(0); 106782490253SJoe Wallwork } 106882490253SJoe Wallwork 10693f07679eSJoe Wallwork static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[], PetscScalar *detMp) 107020282da2SJoe Wallwork { 107120282da2SJoe Wallwork PetscInt i, j, k; 107220282da2SJoe Wallwork 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); 107320282da2SJoe Wallwork PetscScalar *Mpos; 107420282da2SJoe Wallwork 107520282da2SJoe Wallwork PetscFunctionBegin; 10769566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(dim*dim, &Mpos, dim, &eigs)); 107720282da2SJoe Wallwork 107820282da2SJoe Wallwork /* Symmetrize */ 107920282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 108020282da2SJoe Wallwork Mpos[i*dim+i] = Mp[i*dim+i]; 108120282da2SJoe Wallwork for (j = i+1; j < dim; ++j) { 108220282da2SJoe Wallwork Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 108320282da2SJoe Wallwork Mpos[j*dim+i] = Mpos[i*dim+j]; 108420282da2SJoe Wallwork } 108520282da2SJoe Wallwork } 108620282da2SJoe Wallwork 108720282da2SJoe Wallwork /* Compute eigendecomposition */ 108893520041SJoe Wallwork if (dim == 1) { 108993520041SJoe Wallwork 109093520041SJoe Wallwork /* Isotropic case */ 109193520041SJoe Wallwork eigs[0] = PetscRealPart(Mpos[0]); 109293520041SJoe Wallwork Mpos[0] = 1.0; 109393520041SJoe Wallwork } else { 109493520041SJoe Wallwork 109593520041SJoe Wallwork /* Anisotropic case */ 109620282da2SJoe Wallwork PetscScalar *work; 109720282da2SJoe Wallwork PetscBLASInt lwork; 109820282da2SJoe Wallwork 109920282da2SJoe Wallwork lwork = 5*dim; 11009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(5*dim, &work)); 110120282da2SJoe Wallwork { 110220282da2SJoe Wallwork PetscBLASInt lierr; 110320282da2SJoe Wallwork PetscBLASInt nb; 110420282da2SJoe Wallwork 11059566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(dim, &nb)); 11069566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 110720282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX) 110820282da2SJoe Wallwork { 110920282da2SJoe Wallwork PetscReal *rwork; 11109566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3*dim, &rwork)); 111120282da2SJoe Wallwork PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr)); 11129566063dSJacob Faibussowitsch PetscCall(PetscFree(rwork)); 111320282da2SJoe Wallwork } 111420282da2SJoe Wallwork #else 111520282da2SJoe Wallwork PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr)); 111620282da2SJoe Wallwork #endif 111782490253SJoe Wallwork if (lierr) { 111882490253SJoe Wallwork for (i = 0; i < dim; ++i) { 111982490253SJoe Wallwork Mpos[i*dim+i] = Mp[i*dim+i]; 112082490253SJoe Wallwork for (j = i+1; j < dim; ++j) { 112182490253SJoe Wallwork Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]); 112282490253SJoe Wallwork Mpos[j*dim+i] = Mpos[i*dim+j]; 112382490253SJoe Wallwork } 112482490253SJoe Wallwork } 112582490253SJoe Wallwork LAPACKsyevFail(dim, Mpos); 112698921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 112782490253SJoe Wallwork } 11289566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 112920282da2SJoe Wallwork } 11309566063dSJacob Faibussowitsch PetscCall(PetscFree(work)); 113120282da2SJoe Wallwork } 113220282da2SJoe Wallwork 113320282da2SJoe Wallwork /* Reflect to positive orthant and enforce maximum and minimum size */ 113420282da2SJoe Wallwork max_eig = 0.0; 113520282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 113620282da2SJoe Wallwork eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i]))); 113720282da2SJoe Wallwork max_eig = PetscMax(eigs[i], max_eig); 113820282da2SJoe Wallwork } 113920282da2SJoe Wallwork 11403f07679eSJoe Wallwork /* Enforce maximum anisotropy and compute determinant */ 11413f07679eSJoe Wallwork *detMp = 1.0; 114220282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 114320282da2SJoe Wallwork if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min); 11443f07679eSJoe Wallwork *detMp *= eigs[i]; 114520282da2SJoe Wallwork } 114620282da2SJoe Wallwork 114720282da2SJoe Wallwork /* Reconstruct Hessian */ 114820282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 114920282da2SJoe Wallwork for (j = 0; j < dim; ++j) { 115020282da2SJoe Wallwork Mp[i*dim+j] = 0.0; 115120282da2SJoe Wallwork for (k = 0; k < dim; ++k) { 115220282da2SJoe Wallwork Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j]; 115320282da2SJoe Wallwork } 115420282da2SJoe Wallwork } 115520282da2SJoe Wallwork } 11569566063dSJacob Faibussowitsch PetscCall(PetscFree2(Mpos, eigs)); 115720282da2SJoe Wallwork 115820282da2SJoe Wallwork PetscFunctionReturn(0); 115920282da2SJoe Wallwork } 116020282da2SJoe Wallwork 1161cb7bfe8cSJoe Wallwork /*@ 116220282da2SJoe Wallwork DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric 116320282da2SJoe Wallwork 116420282da2SJoe Wallwork Input parameters: 116520282da2SJoe Wallwork + dm - The DM 11663f07679eSJoe Wallwork . metricIn - The metric 116799abec2bSJoe Wallwork . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 11683f07679eSJoe Wallwork - restrictAnisotropy - Should maximum anisotropy be enforced? 116920282da2SJoe Wallwork 117020282da2SJoe Wallwork Output parameter: 11713f07679eSJoe Wallwork + metricOut - The metric 11723f07679eSJoe Wallwork - determinant - Its determinant 117320282da2SJoe Wallwork 117420282da2SJoe Wallwork Level: beginner 117520282da2SJoe Wallwork 1176cb7bfe8cSJoe Wallwork Notes: 1177cb7bfe8cSJoe Wallwork 1178cb7bfe8cSJoe Wallwork Relevant command line options: 1179cb7bfe8cSJoe Wallwork 118093520041SJoe Wallwork + -dm_plex_metric_isotropic - Is the metric isotropic? 118193520041SJoe Wallwork . -dm_plex_metric_uniform - Is the metric uniform? 118293520041SJoe Wallwork . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 1183cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 1184cb7bfe8cSJoe Wallwork - -dm_plex_metric_a_max - Maximum tolerated anisotropy 1185cb7bfe8cSJoe Wallwork 1186db781477SPatrick Sanan .seealso: `DMPlexMetricNormalize()`, `DMPlexMetricIntersection()` 1187cb7bfe8cSJoe Wallwork @*/ 11885241a91fSJoe Wallwork PetscErrorCode DMPlexMetricEnforceSPD(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metricOut, Vec determinant) 118920282da2SJoe Wallwork { 11903f07679eSJoe Wallwork DM dmDet; 119193520041SJoe Wallwork PetscBool isotropic, uniform; 119220282da2SJoe Wallwork PetscInt dim, vStart, vEnd, v; 11933f07679eSJoe Wallwork PetscScalar *met, *det; 119420282da2SJoe Wallwork PetscReal h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0; 119520282da2SJoe Wallwork 119620282da2SJoe Wallwork PetscFunctionBegin; 11979566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_MetricEnforceSPD,0,0,0,0)); 119820282da2SJoe Wallwork 119920282da2SJoe Wallwork /* Extract metadata from dm */ 12009566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 120120282da2SJoe Wallwork if (restrictSizes) { 12029566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMinimumMagnitude(dm, &h_min)); 12039566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMaximumMagnitude(dm, &h_max)); 120499abec2bSJoe Wallwork h_min = PetscMax(h_min, 1.0e-30); 120599abec2bSJoe Wallwork h_max = PetscMin(h_max, 1.0e+30); 1206bc00d7afSJoe Wallwork PetscCheck(h_min < h_max, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum metric magnitude should be smaller than maximum metric magnitude"); 120799abec2bSJoe Wallwork } 120899abec2bSJoe Wallwork if (restrictAnisotropy) { 12099566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMaximumAnisotropy(dm, &a_max)); 121099abec2bSJoe Wallwork a_max = PetscMin(a_max, 1.0e+30); 121120282da2SJoe Wallwork } 121220282da2SJoe Wallwork 121393520041SJoe Wallwork /* Setup output metric */ 12145241a91fSJoe Wallwork PetscCall(VecCopy(metricIn, metricOut)); 121593520041SJoe Wallwork 121693520041SJoe Wallwork /* Enforce SPD and extract determinant */ 12175241a91fSJoe Wallwork PetscCall(VecGetArray(metricOut, &met)); 12189566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 12199566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 122093520041SJoe Wallwork if (uniform) { 1221d1a5b989SMatthew G. Knepley PetscCheck(isotropic, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform anisotropic metrics cannot exist"); 122293520041SJoe Wallwork 122393520041SJoe Wallwork /* Uniform case */ 12245241a91fSJoe Wallwork PetscCall(VecGetArray(determinant, &det)); 12259566063dSJacob Faibussowitsch PetscCall(DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det)); 12265241a91fSJoe Wallwork PetscCall(VecRestoreArray(determinant, &det)); 122793520041SJoe Wallwork } else { 122893520041SJoe Wallwork 122993520041SJoe Wallwork /* Spatially varying case */ 123093520041SJoe Wallwork PetscInt nrow; 123193520041SJoe Wallwork 123293520041SJoe Wallwork if (isotropic) nrow = 1; 123393520041SJoe Wallwork else nrow = dim; 12345241a91fSJoe Wallwork PetscCall(VecGetDM(determinant, &dmDet)); 12359566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 12365241a91fSJoe Wallwork PetscCall(VecGetArray(determinant, &det)); 123720282da2SJoe Wallwork for (v = vStart; v < vEnd; ++v) { 12383f07679eSJoe Wallwork PetscScalar *vmet, *vdet; 12399566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dm, v, met, &vmet)); 12409566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dmDet, v, det, &vdet)); 12419566063dSJacob Faibussowitsch PetscCall(DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, vmet, vdet)); 124220282da2SJoe Wallwork } 12435241a91fSJoe Wallwork PetscCall(VecRestoreArray(determinant, &det)); 124493520041SJoe Wallwork } 12455241a91fSJoe Wallwork PetscCall(VecRestoreArray(metricOut, &met)); 1246fe902aceSJoe Wallwork 12479566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_MetricEnforceSPD,0,0,0,0)); 124820282da2SJoe Wallwork PetscFunctionReturn(0); 124920282da2SJoe Wallwork } 125020282da2SJoe Wallwork 125120282da2SJoe Wallwork static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 125220282da2SJoe Wallwork const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 125320282da2SJoe Wallwork const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 125420282da2SJoe Wallwork PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 125520282da2SJoe Wallwork { 125620282da2SJoe Wallwork const PetscScalar p = constants[0]; 125720282da2SJoe Wallwork 1258985ad86eSJose E. Roman f0[0] = PetscPowScalar(u[0], p/(2.0*p + dim)); 125920282da2SJoe Wallwork } 126020282da2SJoe Wallwork 1261cb7bfe8cSJoe Wallwork /*@ 126220282da2SJoe Wallwork DMPlexMetricNormalize - Apply L-p normalization to a metric 126320282da2SJoe Wallwork 126420282da2SJoe Wallwork Input parameters: 126520282da2SJoe Wallwork + dm - The DM 126620282da2SJoe Wallwork . metricIn - The unnormalized metric 126716522936SJoe Wallwork . restrictSizes - Should maximum/minimum metric magnitudes be enforced? 126816522936SJoe Wallwork - restrictAnisotropy - Should maximum metric anisotropy be enforced? 126920282da2SJoe Wallwork 127020282da2SJoe Wallwork Output parameter: 127120282da2SJoe Wallwork . metricOut - The normalized metric 127220282da2SJoe Wallwork 127320282da2SJoe Wallwork Level: beginner 127420282da2SJoe Wallwork 1275cb7bfe8cSJoe Wallwork Notes: 1276cb7bfe8cSJoe Wallwork 1277cb7bfe8cSJoe Wallwork Relevant command line options: 1278cb7bfe8cSJoe Wallwork 127993520041SJoe Wallwork + -dm_plex_metric_isotropic - Is the metric isotropic? 128093520041SJoe Wallwork . -dm_plex_metric_uniform - Is the metric uniform? 128193520041SJoe Wallwork . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization? 1282cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_min - Minimum tolerated metric magnitude 1283cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max - Maximum tolerated metric magnitude 1284cb7bfe8cSJoe Wallwork . -dm_plex_metric_a_max - Maximum tolerated anisotropy 1285cb7bfe8cSJoe Wallwork . -dm_plex_metric_p - L-p normalization order 1286cb7bfe8cSJoe Wallwork - -dm_plex_metric_target_complexity - Target metric complexity 1287cb7bfe8cSJoe Wallwork 1288db781477SPatrick Sanan .seealso: `DMPlexMetricEnforceSPD()`, `DMPlexMetricIntersection()` 1289cb7bfe8cSJoe Wallwork @*/ 12905241a91fSJoe Wallwork PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metricOut, Vec determinant) 129120282da2SJoe Wallwork { 12923f07679eSJoe Wallwork DM dmDet; 129320282da2SJoe Wallwork MPI_Comm comm; 129493520041SJoe Wallwork PetscBool restrictAnisotropyFirst, isotropic, uniform; 129520282da2SJoe Wallwork PetscDS ds; 129620282da2SJoe Wallwork PetscInt dim, Nd, vStart, vEnd, v, i; 12973f07679eSJoe Wallwork PetscScalar *met, *det, integral, constants[1]; 129893520041SJoe Wallwork PetscReal p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, fact, target, realIntegral; 129920282da2SJoe Wallwork 130020282da2SJoe Wallwork PetscFunctionBegin; 13019566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_MetricNormalize,0,0,0,0)); 130220282da2SJoe Wallwork 130320282da2SJoe Wallwork /* Extract metadata from dm */ 13049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 13059566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13069566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 13079566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 130893520041SJoe Wallwork if (isotropic) Nd = 1; 130993520041SJoe Wallwork else Nd = dim*dim; 131020282da2SJoe Wallwork 131120282da2SJoe Wallwork /* Set up metric and ensure it is SPD */ 13129566063dSJacob Faibussowitsch PetscCall(DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst)); 13135241a91fSJoe Wallwork PetscCall(DMPlexMetricEnforceSPD(dm, metricIn, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), metricOut, determinant)); 131420282da2SJoe Wallwork 131520282da2SJoe Wallwork /* Compute global normalization factor */ 13169566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetTargetComplexity(dm, &target)); 13179566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetNormalizationOrder(dm, &p)); 131816522936SJoe Wallwork constants[0] = p; 131993520041SJoe Wallwork if (uniform) { 1320bc00d7afSJoe Wallwork PetscCheck(isotropic, comm, PETSC_ERR_SUP, "Uniform anisotropic metrics not supported"); 132193520041SJoe Wallwork DM dmTmp; 132293520041SJoe Wallwork Vec tmp; 132393520041SJoe Wallwork 13249566063dSJacob Faibussowitsch PetscCall(DMClone(dm, &dmTmp)); 13259566063dSJacob Faibussowitsch PetscCall(DMPlexP1FieldCreate_Private(dmTmp, 0, 1, &tmp)); 13269566063dSJacob Faibussowitsch PetscCall(VecGetArray(determinant, &det)); 13279566063dSJacob Faibussowitsch PetscCall(VecSet(tmp, det[0])); 13289566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(determinant, &det)); 13299566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmTmp, &ds)); 13309566063dSJacob Faibussowitsch PetscCall(PetscDSSetConstants(ds, 1, constants)); 13319566063dSJacob Faibussowitsch PetscCall(PetscDSSetObjective(ds, 0, detMFunc)); 13329566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dmTmp, tmp, &integral, NULL)); 13339566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tmp)); 13349566063dSJacob Faibussowitsch PetscCall(DMDestroy(&dmTmp)); 133593520041SJoe Wallwork } else { 13369566063dSJacob Faibussowitsch PetscCall(VecGetDM(determinant, &dmDet)); 13379566063dSJacob Faibussowitsch PetscCall(DMGetDS(dmDet, &ds)); 13389566063dSJacob Faibussowitsch PetscCall(PetscDSSetConstants(ds, 1, constants)); 13399566063dSJacob Faibussowitsch PetscCall(PetscDSSetObjective(ds, 0, detMFunc)); 13409566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dmDet, determinant, &integral, NULL)); 134193520041SJoe Wallwork } 13423f07679eSJoe Wallwork realIntegral = PetscRealPart(integral); 1343bc00d7afSJoe Wallwork PetscCheck(realIntegral > 1.0e-30, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Global metric normalization factor must be in (0, inf). Is the input metric positive-definite?"); 13443f07679eSJoe Wallwork factGlob = PetscPowReal(target/realIntegral, 2.0/dim); 134520282da2SJoe Wallwork 134620282da2SJoe Wallwork /* Apply local scaling */ 134720282da2SJoe Wallwork if (restrictSizes) { 13489566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMinimumMagnitude(dm, &h_min)); 13499566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMaximumMagnitude(dm, &h_max)); 135016522936SJoe Wallwork h_min = PetscMax(h_min, 1.0e-30); 135116522936SJoe Wallwork h_max = PetscMin(h_max, 1.0e+30); 1352bc00d7afSJoe Wallwork PetscCheck(h_min < h_max, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Minimum metric magnitude should be smaller than maximum metric magnitude"); 135316522936SJoe Wallwork } 135416522936SJoe Wallwork if (restrictAnisotropy && !restrictAnisotropyFirst) { 13559566063dSJacob Faibussowitsch PetscCall(DMPlexMetricGetMaximumAnisotropy(dm, &a_max)); 135616522936SJoe Wallwork a_max = PetscMin(a_max, 1.0e+30); 135720282da2SJoe Wallwork } 13585241a91fSJoe Wallwork PetscCall(VecGetArray(metricOut, &met)); 13599566063dSJacob Faibussowitsch PetscCall(VecGetArray(determinant, &det)); 136093520041SJoe Wallwork if (uniform) { 136193520041SJoe Wallwork 136293520041SJoe Wallwork /* Uniform case */ 136393520041SJoe Wallwork met[0] *= factGlob * PetscPowReal(PetscAbsScalar(det[0]), -1.0/(2*p+dim)); 13649566063dSJacob Faibussowitsch if (restrictSizes) PetscCall(DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det)); 136593520041SJoe Wallwork } else { 136693520041SJoe Wallwork 136793520041SJoe Wallwork /* Spatially varying case */ 136893520041SJoe Wallwork PetscInt nrow; 136993520041SJoe Wallwork 137093520041SJoe Wallwork if (isotropic) nrow = 1; 137193520041SJoe Wallwork else nrow = dim; 13729566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 13735241a91fSJoe Wallwork PetscCall(VecGetDM(determinant, &dmDet)); 137420282da2SJoe Wallwork for (v = vStart; v < vEnd; ++v) { 13753f07679eSJoe Wallwork PetscScalar *Mp, *detM; 137620282da2SJoe Wallwork 13779566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dm, v, met, &Mp)); 13789566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dmDet, v, det, &detM)); 13793f07679eSJoe Wallwork fact = factGlob * PetscPowReal(PetscAbsScalar(detM[0]), -1.0/(2*p+dim)); 138020282da2SJoe Wallwork for (i = 0; i < Nd; ++i) Mp[i] *= fact; 13819566063dSJacob Faibussowitsch if (restrictSizes) PetscCall(DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, Mp, detM)); 138293520041SJoe Wallwork } 138320282da2SJoe Wallwork } 13849566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(determinant, &det)); 13855241a91fSJoe Wallwork PetscCall(VecRestoreArray(metricOut, &met)); 138620282da2SJoe Wallwork 13879566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_MetricNormalize,0,0,0,0)); 138820282da2SJoe Wallwork PetscFunctionReturn(0); 138920282da2SJoe Wallwork } 139020282da2SJoe Wallwork 1391cb7bfe8cSJoe Wallwork /*@ 139220282da2SJoe Wallwork DMPlexMetricAverage - Compute the average of a list of metrics 139320282da2SJoe Wallwork 1394f1a722f8SMatthew G. Knepley Input Parameters: 139520282da2SJoe Wallwork + dm - The DM 139620282da2SJoe Wallwork . numMetrics - The number of metrics to be averaged 139720282da2SJoe Wallwork . weights - Weights for the average 139820282da2SJoe Wallwork - metrics - The metrics to be averaged 139920282da2SJoe Wallwork 140020282da2SJoe Wallwork Output Parameter: 140120282da2SJoe Wallwork . metricAvg - The averaged metric 140220282da2SJoe Wallwork 140320282da2SJoe Wallwork Level: beginner 140420282da2SJoe Wallwork 140520282da2SJoe Wallwork Notes: 140620282da2SJoe Wallwork The weights should sum to unity. 140720282da2SJoe Wallwork 140820282da2SJoe Wallwork If weights are not provided then an unweighted average is used. 140920282da2SJoe Wallwork 1410db781477SPatrick Sanan .seealso: `DMPlexMetricAverage2()`, `DMPlexMetricAverage3()`, `DMPlexMetricIntersection()` 1411cb7bfe8cSJoe Wallwork @*/ 14125241a91fSJoe Wallwork PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec metricAvg) 141320282da2SJoe Wallwork { 141420282da2SJoe Wallwork PetscBool haveWeights = PETSC_TRUE; 141593520041SJoe Wallwork PetscInt i, m, n; 141620282da2SJoe Wallwork PetscReal sum = 0.0, tol = 1.0e-10; 141720282da2SJoe Wallwork 141820282da2SJoe Wallwork PetscFunctionBegin; 14199566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_MetricAverage,0,0,0,0)); 142063a3b9bcSJacob Faibussowitsch PetscCheck(numMetrics >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %" PetscInt_FMT " < 1 metrics", numMetrics); 14215241a91fSJoe Wallwork PetscCall(VecSet(metricAvg, 0.0)); 14225241a91fSJoe Wallwork PetscCall(VecGetSize(metricAvg, &m)); 142393520041SJoe Wallwork for (i = 0; i < numMetrics; ++i) { 14249566063dSJacob Faibussowitsch PetscCall(VecGetSize(metrics[i], &n)); 14255f80ce2aSJacob Faibussowitsch PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Averaging different metric types not implemented"); 142693520041SJoe Wallwork } 142720282da2SJoe Wallwork 142820282da2SJoe Wallwork /* Default to the unweighted case */ 142920282da2SJoe Wallwork if (!weights) { 14309566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numMetrics, &weights)); 143120282da2SJoe Wallwork haveWeights = PETSC_FALSE; 143220282da2SJoe Wallwork for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; } 143320282da2SJoe Wallwork } 143420282da2SJoe Wallwork 143520282da2SJoe Wallwork /* Check weights sum to unity */ 143693520041SJoe Wallwork for (i = 0; i < numMetrics; ++i) sum += weights[i]; 14375f80ce2aSJacob Faibussowitsch PetscCheck(PetscAbsReal(sum - 1) <= tol, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); 143820282da2SJoe Wallwork 143920282da2SJoe Wallwork /* Compute metric average */ 14405241a91fSJoe Wallwork for (i = 0; i < numMetrics; ++i) PetscCall(VecAXPY(metricAvg, weights[i], metrics[i])); 14419566063dSJacob Faibussowitsch if (!haveWeights) PetscCall(PetscFree(weights)); 1442fe902aceSJoe Wallwork 14439566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_MetricAverage,0,0,0,0)); 144420282da2SJoe Wallwork PetscFunctionReturn(0); 144520282da2SJoe Wallwork } 144620282da2SJoe Wallwork 1447cb7bfe8cSJoe Wallwork /*@ 144820282da2SJoe Wallwork DMPlexMetricAverage2 - Compute the unweighted average of two metrics 144920282da2SJoe Wallwork 1450f1a722f8SMatthew G. Knepley Input Parameters: 145120282da2SJoe Wallwork + dm - The DM 145220282da2SJoe Wallwork . metric1 - The first metric to be averaged 145320282da2SJoe Wallwork - metric2 - The second metric to be averaged 145420282da2SJoe Wallwork 145520282da2SJoe Wallwork Output Parameter: 145620282da2SJoe Wallwork . metricAvg - The averaged metric 145720282da2SJoe Wallwork 145820282da2SJoe Wallwork Level: beginner 145920282da2SJoe Wallwork 1460db781477SPatrick Sanan .seealso: `DMPlexMetricAverage()`, `DMPlexMetricAverage3()` 1461cb7bfe8cSJoe Wallwork @*/ 14625241a91fSJoe Wallwork PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec metricAvg) 146320282da2SJoe Wallwork { 146420282da2SJoe Wallwork PetscReal weights[2] = {0.5, 0.5}; 146520282da2SJoe Wallwork Vec metrics[2] = {metric1, metric2}; 146620282da2SJoe Wallwork 146720282da2SJoe Wallwork PetscFunctionBegin; 14689566063dSJacob Faibussowitsch PetscCall(DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg)); 146920282da2SJoe Wallwork PetscFunctionReturn(0); 147020282da2SJoe Wallwork } 147120282da2SJoe Wallwork 1472cb7bfe8cSJoe Wallwork /*@ 147320282da2SJoe Wallwork DMPlexMetricAverage3 - Compute the unweighted average of three metrics 147420282da2SJoe Wallwork 1475f1a722f8SMatthew G. Knepley Input Parameters: 147620282da2SJoe Wallwork + dm - The DM 147720282da2SJoe Wallwork . metric1 - The first metric to be averaged 147820282da2SJoe Wallwork . metric2 - The second metric to be averaged 147920282da2SJoe Wallwork - metric3 - The third metric to be averaged 148020282da2SJoe Wallwork 148120282da2SJoe Wallwork Output Parameter: 148220282da2SJoe Wallwork . metricAvg - The averaged metric 148320282da2SJoe Wallwork 148420282da2SJoe Wallwork Level: beginner 148520282da2SJoe Wallwork 1486db781477SPatrick Sanan .seealso: `DMPlexMetricAverage()`, `DMPlexMetricAverage2()` 1487cb7bfe8cSJoe Wallwork @*/ 14885241a91fSJoe Wallwork PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec metricAvg) 148920282da2SJoe Wallwork { 149020282da2SJoe Wallwork PetscReal weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0}; 149120282da2SJoe Wallwork Vec metrics[3] = {metric1, metric2, metric3}; 149220282da2SJoe Wallwork 149320282da2SJoe Wallwork PetscFunctionBegin; 14949566063dSJacob Faibussowitsch PetscCall(DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg)); 149520282da2SJoe Wallwork PetscFunctionReturn(0); 149620282da2SJoe Wallwork } 149720282da2SJoe Wallwork 149820282da2SJoe Wallwork static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[]) 149920282da2SJoe Wallwork { 150020282da2SJoe Wallwork PetscInt i, j, k, l, m; 1501*e2606525SJoe Wallwork PetscReal *evals; 150220282da2SJoe Wallwork PetscScalar *evecs, *sqrtM1, *isqrtM1; 150320282da2SJoe Wallwork 150420282da2SJoe Wallwork PetscFunctionBegin; 150593520041SJoe Wallwork 150693520041SJoe Wallwork /* Isotropic case */ 150793520041SJoe Wallwork if (dim == 1) { 15086f71502aSJoe Wallwork M2[0] = (PetscScalar)PetscMax(PetscRealPart(M1[0]), PetscRealPart(M2[0])); 150993520041SJoe Wallwork PetscFunctionReturn(0); 151093520041SJoe Wallwork } 151193520041SJoe Wallwork 151293520041SJoe Wallwork /* Anisotropic case */ 1513*e2606525SJoe Wallwork PetscCall(PetscMalloc4(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals)); 151420282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 151520282da2SJoe Wallwork for (j = 0; j < dim; ++j) { 151620282da2SJoe Wallwork evecs[i*dim+j] = M1[i*dim+j]; 151720282da2SJoe Wallwork } 151820282da2SJoe Wallwork } 151920282da2SJoe Wallwork { 152020282da2SJoe Wallwork PetscScalar *work; 152120282da2SJoe Wallwork PetscBLASInt lwork; 152220282da2SJoe Wallwork 152320282da2SJoe Wallwork lwork = 5*dim; 15249566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(5*dim, &work)); 152520282da2SJoe Wallwork { 152620282da2SJoe Wallwork PetscBLASInt lierr, nb; 1527*e2606525SJoe Wallwork PetscReal sqrtj; 152820282da2SJoe Wallwork 152920282da2SJoe Wallwork /* Compute eigendecomposition of M1 */ 15309566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(dim, &nb)); 15319566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 153220282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX) 153320282da2SJoe Wallwork { 153420282da2SJoe Wallwork PetscReal *rwork; 15359566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3*dim, &rwork)); 1536*e2606525SJoe Wallwork PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 15379566063dSJacob Faibussowitsch PetscCall(PetscFree(rwork)); 153820282da2SJoe Wallwork } 153920282da2SJoe Wallwork #else 1540*e2606525SJoe Wallwork PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 154120282da2SJoe Wallwork #endif 154282490253SJoe Wallwork if (lierr) { 154382490253SJoe Wallwork LAPACKsyevFail(dim, M1); 154498921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 154582490253SJoe Wallwork } 15469566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 154720282da2SJoe Wallwork 1548*e2606525SJoe Wallwork /* Compute square root and the reciprocal thereof */ 154920282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 155020282da2SJoe Wallwork for (k = 0; k < dim; ++k) { 1551*e2606525SJoe Wallwork sqrtM1[i*dim+k] = 0.0; 1552*e2606525SJoe Wallwork isqrtM1[i*dim+k] = 0.0; 1553*e2606525SJoe Wallwork for (j = 0; j < dim; ++j) { 1554*e2606525SJoe Wallwork sqrtj = PetscSqrtReal(evals[j]); 1555*e2606525SJoe Wallwork sqrtM1[i*dim+k] += evecs[j*dim+i] * sqrtj * evecs[j*dim+k]; 1556*e2606525SJoe Wallwork isqrtM1[i*dim+k] += evecs[j*dim+i] * (1.0/sqrtj) * evecs[j*dim+k]; 155720282da2SJoe Wallwork } 155820282da2SJoe Wallwork } 155920282da2SJoe Wallwork } 156020282da2SJoe Wallwork 1561*e2606525SJoe Wallwork /* Map M2 into the space spanned by the eigenvectors of M1 */ 156220282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 156320282da2SJoe Wallwork for (l = 0; l < dim; ++l) { 1564*e2606525SJoe Wallwork evecs[i*dim+l] = 0.0; 1565*e2606525SJoe Wallwork for (j = 0; j < dim; ++j) { 1566*e2606525SJoe Wallwork for (k = 0; k < dim; ++k) { 1567*e2606525SJoe Wallwork evecs[i*dim+l] += isqrtM1[j*dim+i] * M2[j*dim+k] * isqrtM1[k*dim+l]; 156820282da2SJoe Wallwork } 156920282da2SJoe Wallwork } 157020282da2SJoe Wallwork } 157120282da2SJoe Wallwork } 157220282da2SJoe Wallwork 157320282da2SJoe Wallwork /* Compute eigendecomposition */ 15749566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 157520282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX) 157620282da2SJoe Wallwork { 157720282da2SJoe Wallwork PetscReal *rwork; 15789566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(3*dim, &rwork)); 157920282da2SJoe Wallwork PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr)); 15809566063dSJacob Faibussowitsch PetscCall(PetscFree(rwork)); 158120282da2SJoe Wallwork } 158220282da2SJoe Wallwork #else 158320282da2SJoe Wallwork PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr)); 158420282da2SJoe Wallwork #endif 158582490253SJoe Wallwork if (lierr) { 158682490253SJoe Wallwork for (i = 0; i < dim; ++i) { 158782490253SJoe Wallwork for (l = 0; l < dim; ++l) { 1588*e2606525SJoe Wallwork evecs[i*dim+l] = 0.0; 1589*e2606525SJoe Wallwork for (j = 0; j < dim; ++j) { 1590*e2606525SJoe Wallwork for (k = 0; k < dim; ++k) { 1591*e2606525SJoe Wallwork evecs[i*dim+l] += isqrtM1[j*dim+i] * M2[j*dim+k] * isqrtM1[k*dim+l]; 159282490253SJoe Wallwork } 159382490253SJoe Wallwork } 159482490253SJoe Wallwork } 159582490253SJoe Wallwork } 159682490253SJoe Wallwork LAPACKsyevFail(dim, evecs); 159798921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr); 159882490253SJoe Wallwork } 15999566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 160020282da2SJoe Wallwork 160120282da2SJoe Wallwork /* Modify eigenvalues */ 1602*e2606525SJoe Wallwork for (i = 0; i < dim; ++i) evals[i] = PetscMax(evals[i], 1.0); 160320282da2SJoe Wallwork 160420282da2SJoe Wallwork /* Map back to get the intersection */ 160520282da2SJoe Wallwork for (i = 0; i < dim; ++i) { 1606*e2606525SJoe Wallwork for (m = 0; m < dim; ++m) { 1607*e2606525SJoe Wallwork M2[i*dim+m] = 0.0; 160820282da2SJoe Wallwork for (j = 0; j < dim; ++j) { 160920282da2SJoe Wallwork for (k = 0; k < dim; ++k) { 161020282da2SJoe Wallwork for (l = 0; l < dim; ++l) { 1611*e2606525SJoe Wallwork M2[i*dim+m] += sqrtM1[j*dim+i] * evecs[j*dim+k] * evals[k] * evecs[l*dim+k] * sqrtM1[l*dim+m]; 161220282da2SJoe Wallwork } 161320282da2SJoe Wallwork } 161420282da2SJoe Wallwork } 161520282da2SJoe Wallwork } 161620282da2SJoe Wallwork } 161720282da2SJoe Wallwork } 16189566063dSJacob Faibussowitsch PetscCall(PetscFree(work)); 161920282da2SJoe Wallwork } 1620*e2606525SJoe Wallwork PetscCall(PetscFree4(evecs, sqrtM1, isqrtM1, evals)); 162120282da2SJoe Wallwork PetscFunctionReturn(0); 162220282da2SJoe Wallwork } 162320282da2SJoe Wallwork 1624cb7bfe8cSJoe Wallwork /*@ 162520282da2SJoe Wallwork DMPlexMetricIntersection - Compute the intersection of a list of metrics 162620282da2SJoe Wallwork 1627f1a722f8SMatthew G. Knepley Input Parameters: 162820282da2SJoe Wallwork + dm - The DM 162920282da2SJoe Wallwork . numMetrics - The number of metrics to be intersected 163020282da2SJoe Wallwork - metrics - The metrics to be intersected 163120282da2SJoe Wallwork 163220282da2SJoe Wallwork Output Parameter: 163320282da2SJoe Wallwork . metricInt - The intersected metric 163420282da2SJoe Wallwork 163520282da2SJoe Wallwork Level: beginner 163620282da2SJoe Wallwork 163720282da2SJoe Wallwork Notes: 163820282da2SJoe Wallwork 1639*e2606525SJoe Wallwork The intersection of a list of metrics has the minimal ellipsoid which fits within the ellipsoids of the component metrics. 164020282da2SJoe Wallwork 1641*e2606525SJoe Wallwork The implementation used here is only consistent with the minimal ellipsoid definition in the case numMetrics = 2. 164220282da2SJoe Wallwork 1643db781477SPatrick Sanan .seealso: `DMPlexMetricIntersection2()`, `DMPlexMetricIntersection3()`, `DMPlexMetricAverage()` 1644cb7bfe8cSJoe Wallwork @*/ 16455241a91fSJoe Wallwork PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec metricInt) 164620282da2SJoe Wallwork { 164793520041SJoe Wallwork PetscBool isotropic, uniform; 164893520041SJoe Wallwork PetscInt v, i, m, n; 164993520041SJoe Wallwork PetscScalar *met, *meti; 165020282da2SJoe Wallwork 165120282da2SJoe Wallwork PetscFunctionBegin; 16529566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_MetricIntersection,0,0,0,0)); 165363a3b9bcSJacob Faibussowitsch PetscCheck(numMetrics >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %" PetscInt_FMT " < 1 metrics", numMetrics); 165420282da2SJoe Wallwork 165520282da2SJoe Wallwork /* Copy over the first metric */ 16565241a91fSJoe Wallwork PetscCall(VecCopy(metrics[0], metricInt)); 165793520041SJoe Wallwork if (numMetrics == 1) PetscFunctionReturn(0); 16585241a91fSJoe Wallwork PetscCall(VecGetSize(metricInt, &m)); 165993520041SJoe Wallwork for (i = 0; i < numMetrics; ++i) { 16609566063dSJacob Faibussowitsch PetscCall(VecGetSize(metrics[i], &n)); 166108401ef6SPierre Jolivet PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Intersecting different metric types not implemented"); 166293520041SJoe Wallwork } 166320282da2SJoe Wallwork 166420282da2SJoe Wallwork /* Intersect subsequent metrics in turn */ 16659566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsUniform(dm, &uniform)); 16669566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); 166793520041SJoe Wallwork if (uniform) { 166893520041SJoe Wallwork 166993520041SJoe Wallwork /* Uniform case */ 16705241a91fSJoe Wallwork PetscCall(VecGetArray(metricInt, &met)); 167193520041SJoe Wallwork for (i = 1; i < numMetrics; ++i) { 16729566063dSJacob Faibussowitsch PetscCall(VecGetArray(metrics[i], &meti)); 16739566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIntersection_Private(1, meti, met)); 16749566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(metrics[i], &meti)); 167593520041SJoe Wallwork } 16765241a91fSJoe Wallwork PetscCall(VecRestoreArray(metricInt, &met)); 167793520041SJoe Wallwork } else { 167893520041SJoe Wallwork 167993520041SJoe Wallwork /* Spatially varying case */ 168093520041SJoe Wallwork PetscInt dim, vStart, vEnd, nrow; 168193520041SJoe Wallwork PetscScalar *M, *Mi; 168293520041SJoe Wallwork 16839566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 168493520041SJoe Wallwork if (isotropic) nrow = 1; 168593520041SJoe Wallwork else nrow = dim; 16869566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 16875241a91fSJoe Wallwork PetscCall(VecGetArray(metricInt, &met)); 168820282da2SJoe Wallwork for (i = 1; i < numMetrics; ++i) { 16899566063dSJacob Faibussowitsch PetscCall(VecGetArray(metrics[i], &meti)); 169020282da2SJoe Wallwork for (v = vStart; v < vEnd; ++v) { 16919566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dm, v, met, &M)); 16929566063dSJacob Faibussowitsch PetscCall(DMPlexPointLocalRef(dm, v, meti, &Mi)); 16939566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIntersection_Private(nrow, Mi, M)); 169420282da2SJoe Wallwork } 16959566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(metrics[i], &meti)); 169620282da2SJoe Wallwork } 16975241a91fSJoe Wallwork PetscCall(VecRestoreArray(metricInt, &met)); 169820282da2SJoe Wallwork } 1699fe902aceSJoe Wallwork 17009566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_MetricIntersection,0,0,0,0)); 170120282da2SJoe Wallwork PetscFunctionReturn(0); 170220282da2SJoe Wallwork } 170320282da2SJoe Wallwork 1704cb7bfe8cSJoe Wallwork /*@ 170520282da2SJoe Wallwork DMPlexMetricIntersection2 - Compute the intersection of two metrics 170620282da2SJoe Wallwork 1707f1a722f8SMatthew G. Knepley Input Parameters: 170820282da2SJoe Wallwork + dm - The DM 170920282da2SJoe Wallwork . metric1 - The first metric to be intersected 171020282da2SJoe Wallwork - metric2 - The second metric to be intersected 171120282da2SJoe Wallwork 171220282da2SJoe Wallwork Output Parameter: 171320282da2SJoe Wallwork . metricInt - The intersected metric 171420282da2SJoe Wallwork 171520282da2SJoe Wallwork Level: beginner 171620282da2SJoe Wallwork 1717db781477SPatrick Sanan .seealso: `DMPlexMetricIntersection()`, `DMPlexMetricIntersection3()` 1718cb7bfe8cSJoe Wallwork @*/ 17195241a91fSJoe Wallwork PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec metricInt) 172020282da2SJoe Wallwork { 172120282da2SJoe Wallwork Vec metrics[2] = {metric1, metric2}; 172220282da2SJoe Wallwork 172320282da2SJoe Wallwork PetscFunctionBegin; 17249566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIntersection(dm, 2, metrics, metricInt)); 172520282da2SJoe Wallwork PetscFunctionReturn(0); 172620282da2SJoe Wallwork } 172720282da2SJoe Wallwork 1728cb7bfe8cSJoe Wallwork /*@ 172920282da2SJoe Wallwork DMPlexMetricIntersection3 - Compute the intersection of three metrics 173020282da2SJoe Wallwork 1731f1a722f8SMatthew G. Knepley Input Parameters: 173220282da2SJoe Wallwork + dm - The DM 173320282da2SJoe Wallwork . metric1 - The first metric to be intersected 173420282da2SJoe Wallwork . metric2 - The second metric to be intersected 173520282da2SJoe Wallwork - metric3 - The third metric to be intersected 173620282da2SJoe Wallwork 173720282da2SJoe Wallwork Output Parameter: 173820282da2SJoe Wallwork . metricInt - The intersected metric 173920282da2SJoe Wallwork 174020282da2SJoe Wallwork Level: beginner 174120282da2SJoe Wallwork 1742db781477SPatrick Sanan .seealso: `DMPlexMetricIntersection()`, `DMPlexMetricIntersection2()` 1743cb7bfe8cSJoe Wallwork @*/ 17445241a91fSJoe Wallwork PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec metricInt) 174520282da2SJoe Wallwork { 174620282da2SJoe Wallwork Vec metrics[3] = {metric1, metric2, metric3}; 174720282da2SJoe Wallwork 174820282da2SJoe Wallwork PetscFunctionBegin; 17499566063dSJacob Faibussowitsch PetscCall(DMPlexMetricIntersection(dm, 3, metrics, metricInt)); 175020282da2SJoe Wallwork PetscFunctionReturn(0); 175120282da2SJoe Wallwork } 1752