xref: /petsc/src/dm/impls/plex/plexmetric.c (revision 76f360cab9a894a1e3778f6e07f6e3594616bf3a)
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 {
831b70465SJoe Wallwork   MPI_Comm       comm;
993520041SJoe Wallwork   PetscBool      isotropic = PETSC_FALSE, uniform = PETSC_FALSE, restrictAnisotropyFirst = PETSC_FALSE;
10*76f360caSJoe Wallwork   PetscBool      noInsert = PETSC_FALSE, noSwap = PETSC_FALSE, noMove = PETSC_FALSE, noSurf = PETSC_FALSE;
1131b70465SJoe Wallwork   PetscErrorCode ierr;
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;
1631b70465SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1731b70465SJoe Wallwork   ierr = PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric");CHKERRQ(ierr);
1831b70465SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL);CHKERRQ(ierr);
19cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetIsotropic(dm, isotropic);CHKERRQ(ierr);
2093520041SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_uniform", "Is the metric uniform?", "DMPlexMetricCreateUniform", uniform, &uniform, NULL);CHKERRQ(ierr);
2193520041SJoe Wallwork   ierr = DMPlexMetricSetUniform(dm, uniform);CHKERRQ(ierr);
2231b70465SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL);CHKERRQ(ierr);
23cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst);CHKERRQ(ierr);
24cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_insert", "Turn off node insertion and deletion", "DMAdaptMetric", noInsert, &noInsert, NULL);CHKERRQ(ierr);
25cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoInsertion(dm, noInsert);CHKERRQ(ierr);
26cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_swap", "Turn off facet swapping", "DMAdaptMetric", noSwap, &noSwap, NULL);CHKERRQ(ierr);
27cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoSwapping(dm, noSwap);CHKERRQ(ierr);
28cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_move", "Turn off facet node movement", "DMAdaptMetric", noMove, &noMove, NULL);CHKERRQ(ierr);
29cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoMovement(dm, noMove);CHKERRQ(ierr);
30*76f360caSJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_surf", "Turn off surface modification", "DMAdaptMetric", noSurf, &noSurf, NULL);CHKERRQ(ierr);
31*76f360caSJoe Wallwork   ierr = DMPlexMetricSetNoSurf(dm, noSurf);CHKERRQ(ierr);
32cc2eee55SJoe Wallwork   ierr = PetscOptionsBoundedInt("-dm_plex_metric_num_iterations", "Number of ParMmg adaptation iterations", "DMAdaptMetric", numIter, &numIter, NULL, 0);CHKERRQ(ierr);
33cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNumIterations(dm, numIter);CHKERRQ(ierr);
34cc2eee55SJoe Wallwork   ierr = PetscOptionsRangeInt("-dm_plex_metric_verbosity", "Verbosity of metric-based mesh adaptation package (-1 = silent, 10 = maximum)", "DMAdaptMetric", verbosity, &verbosity, NULL, -1, 10);CHKERRQ(ierr);
35cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetVerbosity(dm, verbosity);CHKERRQ(ierr);
3631b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL);CHKERRQ(ierr);
3731b70465SJoe Wallwork   ierr = DMPlexMetricSetMinimumMagnitude(dm, h_min);CHKERRQ(ierr);
3831b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL);CHKERRQ(ierr);
3931b70465SJoe Wallwork   ierr = DMPlexMetricSetMaximumMagnitude(dm, h_max);CHKERRQ(ierr);
4031b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL);CHKERRQ(ierr);
4131b70465SJoe Wallwork   ierr = DMPlexMetricSetMaximumAnisotropy(dm, a_max);CHKERRQ(ierr);
4231b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL);CHKERRQ(ierr);
4331b70465SJoe Wallwork   ierr = DMPlexMetricSetNormalizationOrder(dm, p);CHKERRQ(ierr);
4431b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL);CHKERRQ(ierr);
4531b70465SJoe Wallwork   ierr = DMPlexMetricSetTargetComplexity(dm, target);CHKERRQ(ierr);
46cc2eee55SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_gradation_factor", "Metric gradation factor", "DMAdaptMetric", beta, &beta, NULL);CHKERRQ(ierr);
47cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetGradationFactor(dm, beta);CHKERRQ(ierr);
48ae8b063eSJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_hausdorff_number", "Metric Hausdorff number", "DMAdaptMetric", hausd, &hausd, NULL);CHKERRQ(ierr);
49ae8b063eSJoe Wallwork   ierr = DMPlexMetricSetHausdorffNumber(dm, hausd);CHKERRQ(ierr);
5031b70465SJoe Wallwork   ierr = PetscOptionsEnd();CHKERRQ(ierr);
5131b70465SJoe Wallwork   PetscFunctionReturn(0);
5231b70465SJoe Wallwork }
5331b70465SJoe Wallwork 
54cb7bfe8cSJoe Wallwork /*@
5531b70465SJoe Wallwork   DMPlexMetricSetIsotropic - Record whether a metric is isotropic
5631b70465SJoe Wallwork 
5731b70465SJoe Wallwork   Input parameters:
5831b70465SJoe Wallwork + dm        - The DM
5931b70465SJoe Wallwork - isotropic - Is the metric isotropic?
6031b70465SJoe Wallwork 
6131b70465SJoe Wallwork   Level: beginner
6231b70465SJoe Wallwork 
6393520041SJoe Wallwork .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetUniform(), DMPlexMetricSetRestrictAnisotropyFirst()
64cb7bfe8cSJoe Wallwork @*/
6531b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic)
6631b70465SJoe Wallwork {
6731b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
6831b70465SJoe Wallwork   PetscErrorCode ierr;
6931b70465SJoe Wallwork 
7031b70465SJoe Wallwork   PetscFunctionBegin;
7131b70465SJoe Wallwork   if (!plex->metricCtx) {
7231b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
7331b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
7431b70465SJoe Wallwork   }
7531b70465SJoe Wallwork   plex->metricCtx->isotropic = isotropic;
7631b70465SJoe Wallwork   PetscFunctionReturn(0);
7731b70465SJoe Wallwork }
7831b70465SJoe Wallwork 
79cb7bfe8cSJoe Wallwork /*@
8093520041SJoe Wallwork   DMPlexMetricIsIsotropic - Is a metric isotropic?
8131b70465SJoe Wallwork 
8231b70465SJoe Wallwork   Input parameters:
8331b70465SJoe Wallwork . dm        - The DM
8431b70465SJoe Wallwork 
8531b70465SJoe Wallwork   Output parameters:
8631b70465SJoe Wallwork . isotropic - Is the metric isotropic?
8731b70465SJoe Wallwork 
8831b70465SJoe Wallwork   Level: beginner
8931b70465SJoe Wallwork 
9093520041SJoe Wallwork .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricIsUniform(), DMPlexMetricRestrictAnisotropyFirst()
91cb7bfe8cSJoe Wallwork @*/
9231b70465SJoe Wallwork PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic)
9331b70465SJoe Wallwork {
9431b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
9531b70465SJoe Wallwork   PetscErrorCode ierr;
9631b70465SJoe Wallwork 
9731b70465SJoe Wallwork   PetscFunctionBegin;
9831b70465SJoe Wallwork   if (!plex->metricCtx) {
9931b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
10031b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
10131b70465SJoe Wallwork   }
10231b70465SJoe Wallwork   *isotropic = plex->metricCtx->isotropic;
10331b70465SJoe Wallwork   PetscFunctionReturn(0);
10431b70465SJoe Wallwork }
10531b70465SJoe Wallwork 
106cb7bfe8cSJoe Wallwork /*@
10793520041SJoe Wallwork   DMPlexMetricSetUniform - Record whether a metric is uniform
10893520041SJoe Wallwork 
10993520041SJoe Wallwork   Input parameters:
11093520041SJoe Wallwork + dm      - The DM
11193520041SJoe Wallwork - uniform - Is the metric uniform?
11293520041SJoe Wallwork 
11393520041SJoe Wallwork   Level: beginner
11493520041SJoe Wallwork 
11593520041SJoe Wallwork   Notes:
11693520041SJoe Wallwork 
11793520041SJoe Wallwork   If the metric is specified as uniform then it is assumed to be isotropic, too.
11893520041SJoe Wallwork 
11993520041SJoe Wallwork .seealso: DMPlexMetricIsUniform(), DMPlexMetricSetIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst()
12093520041SJoe Wallwork @*/
12193520041SJoe Wallwork PetscErrorCode DMPlexMetricSetUniform(DM dm, PetscBool uniform)
12293520041SJoe Wallwork {
12393520041SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
12493520041SJoe Wallwork   PetscErrorCode ierr;
12593520041SJoe Wallwork 
12693520041SJoe Wallwork   PetscFunctionBegin;
12793520041SJoe Wallwork   if (!plex->metricCtx) {
12893520041SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
12993520041SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
13093520041SJoe Wallwork   }
13193520041SJoe Wallwork   plex->metricCtx->uniform = uniform;
13293520041SJoe Wallwork   if (uniform) plex->metricCtx->isotropic = uniform;
13393520041SJoe Wallwork   PetscFunctionReturn(0);
13493520041SJoe Wallwork }
13593520041SJoe Wallwork 
13693520041SJoe Wallwork /*@
13793520041SJoe Wallwork   DMPlexMetricIsUniform - Is a metric uniform?
13893520041SJoe Wallwork 
13993520041SJoe Wallwork   Input parameters:
14093520041SJoe Wallwork . dm      - The DM
14193520041SJoe Wallwork 
14293520041SJoe Wallwork   Output parameters:
14393520041SJoe Wallwork . uniform - Is the metric uniform?
14493520041SJoe Wallwork 
14593520041SJoe Wallwork   Level: beginner
14693520041SJoe Wallwork 
14793520041SJoe Wallwork .seealso: DMPlexMetricSetUniform(), DMPlexMetricIsIsotropic(), DMPlexMetricRestrictAnisotropyFirst()
14893520041SJoe Wallwork @*/
14993520041SJoe Wallwork PetscErrorCode DMPlexMetricIsUniform(DM dm, PetscBool *uniform)
15093520041SJoe Wallwork {
15193520041SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
15293520041SJoe Wallwork   PetscErrorCode ierr;
15393520041SJoe Wallwork 
15493520041SJoe Wallwork   PetscFunctionBegin;
15593520041SJoe Wallwork   if (!plex->metricCtx) {
15693520041SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
15793520041SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
15893520041SJoe Wallwork   }
15993520041SJoe Wallwork   *uniform = plex->metricCtx->uniform;
16093520041SJoe Wallwork   PetscFunctionReturn(0);
16193520041SJoe Wallwork }
16293520041SJoe Wallwork 
16393520041SJoe Wallwork /*@
16431b70465SJoe Wallwork   DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization
16531b70465SJoe Wallwork 
16631b70465SJoe Wallwork   Input parameters:
16731b70465SJoe Wallwork + dm                      - The DM
16831b70465SJoe Wallwork - restrictAnisotropyFirst - Should anisotropy be normalized first?
16931b70465SJoe Wallwork 
17031b70465SJoe Wallwork   Level: beginner
17131b70465SJoe Wallwork 
17231b70465SJoe Wallwork .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst()
173cb7bfe8cSJoe Wallwork @*/
17431b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst)
17531b70465SJoe Wallwork {
17631b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
17731b70465SJoe Wallwork   PetscErrorCode ierr;
17831b70465SJoe Wallwork 
17931b70465SJoe Wallwork   PetscFunctionBegin;
18031b70465SJoe Wallwork   if (!plex->metricCtx) {
18131b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
18231b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
18331b70465SJoe Wallwork   }
18431b70465SJoe Wallwork   plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst;
18531b70465SJoe Wallwork   PetscFunctionReturn(0);
18631b70465SJoe Wallwork }
18731b70465SJoe Wallwork 
188cb7bfe8cSJoe Wallwork /*@
18931b70465SJoe Wallwork   DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after?
19031b70465SJoe Wallwork 
19131b70465SJoe Wallwork   Input parameters:
19231b70465SJoe Wallwork . dm                      - The DM
19331b70465SJoe Wallwork 
19431b70465SJoe Wallwork   Output parameters:
19531b70465SJoe Wallwork . restrictAnisotropyFirst - Is anisotropy be normalized first?
19631b70465SJoe Wallwork 
19731b70465SJoe Wallwork   Level: beginner
19831b70465SJoe Wallwork 
19931b70465SJoe Wallwork .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst()
200cb7bfe8cSJoe Wallwork @*/
20131b70465SJoe Wallwork PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst)
20231b70465SJoe Wallwork {
20331b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
20431b70465SJoe Wallwork   PetscErrorCode ierr;
20531b70465SJoe Wallwork 
20631b70465SJoe Wallwork   PetscFunctionBegin;
20731b70465SJoe Wallwork   if (!plex->metricCtx) {
20831b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
20931b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
21031b70465SJoe Wallwork   }
21131b70465SJoe Wallwork   *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst;
21231b70465SJoe Wallwork   PetscFunctionReturn(0);
21331b70465SJoe Wallwork }
21431b70465SJoe Wallwork 
215cb7bfe8cSJoe Wallwork /*@
216cc2eee55SJoe Wallwork   DMPlexMetricSetNoInsertion - Should node insertion and deletion be turned off?
217cc2eee55SJoe Wallwork 
218cc2eee55SJoe Wallwork   Input parameters:
219cc2eee55SJoe Wallwork + dm       - The DM
220cc2eee55SJoe Wallwork - noInsert - Should node insertion and deletion be turned off?
221cc2eee55SJoe Wallwork 
222cc2eee55SJoe Wallwork   Level: beginner
223cc2eee55SJoe Wallwork 
224cb7bfe8cSJoe Wallwork   Notes:
225cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
226cb7bfe8cSJoe Wallwork 
227*76f360caSJoe Wallwork .seealso: DMPlexMetricNoInsertion(), DMPlexMetricSetNoSwapping(), DMPlexMetricSetNoMovement(), DMPlexMetricSetNoSurf()
228cb7bfe8cSJoe Wallwork @*/
229cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoInsertion(DM dm, PetscBool noInsert)
230cc2eee55SJoe Wallwork {
231cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
232cc2eee55SJoe Wallwork   PetscErrorCode ierr;
233cc2eee55SJoe Wallwork 
234cc2eee55SJoe Wallwork   PetscFunctionBegin;
235cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
236cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
237cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
238cc2eee55SJoe Wallwork   }
239cc2eee55SJoe Wallwork   plex->metricCtx->noInsert = noInsert;
240cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
241cc2eee55SJoe Wallwork }
242cc2eee55SJoe Wallwork 
243cb7bfe8cSJoe Wallwork /*@
244cc2eee55SJoe Wallwork   DMPlexMetricNoInsertion - Are node insertion and deletion turned off?
245cc2eee55SJoe Wallwork 
246cc2eee55SJoe Wallwork   Input parameters:
247cc2eee55SJoe Wallwork . dm       - The DM
248cc2eee55SJoe Wallwork 
249cc2eee55SJoe Wallwork   Output parameters:
250cc2eee55SJoe Wallwork . noInsert - Are node insertion and deletion turned off?
251cc2eee55SJoe Wallwork 
252cc2eee55SJoe Wallwork   Level: beginner
253cc2eee55SJoe Wallwork 
254cb7bfe8cSJoe Wallwork   Notes:
255cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
256cb7bfe8cSJoe Wallwork 
257*76f360caSJoe Wallwork .seealso: DMPlexMetricSetNoInsertion(), DMPlexMetricNoSwapping(), DMPlexMetricNoMovement(), DMPlexMetricNoSurf()
258cb7bfe8cSJoe Wallwork @*/
259cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoInsertion(DM dm, PetscBool *noInsert)
260cc2eee55SJoe Wallwork {
261cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
262cc2eee55SJoe Wallwork   PetscErrorCode ierr;
263cc2eee55SJoe Wallwork 
264cc2eee55SJoe Wallwork   PetscFunctionBegin;
265cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
266cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
267cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
268cc2eee55SJoe Wallwork   }
269cc2eee55SJoe Wallwork   *noInsert = plex->metricCtx->noInsert;
270cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
271cc2eee55SJoe Wallwork }
272cc2eee55SJoe Wallwork 
273cb7bfe8cSJoe Wallwork /*@
274cc2eee55SJoe Wallwork   DMPlexMetricSetNoSwapping - Should facet swapping be turned off?
275cc2eee55SJoe Wallwork 
276cc2eee55SJoe Wallwork   Input parameters:
277cc2eee55SJoe Wallwork + dm     - The DM
278cc2eee55SJoe Wallwork - noSwap - Should facet swapping be turned off?
279cc2eee55SJoe Wallwork 
280cc2eee55SJoe Wallwork   Level: beginner
281cc2eee55SJoe Wallwork 
282cb7bfe8cSJoe Wallwork   Notes:
283cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
284cb7bfe8cSJoe Wallwork 
285*76f360caSJoe Wallwork .seealso: DMPlexMetricNoSwapping(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoMovement(), DMPlexMetricSetNoSurf()
286cb7bfe8cSJoe Wallwork @*/
287cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoSwapping(DM dm, PetscBool noSwap)
288cc2eee55SJoe Wallwork {
289cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
290cc2eee55SJoe Wallwork   PetscErrorCode ierr;
291cc2eee55SJoe Wallwork 
292cc2eee55SJoe Wallwork   PetscFunctionBegin;
293cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
294cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
295cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
296cc2eee55SJoe Wallwork   }
297cc2eee55SJoe Wallwork   plex->metricCtx->noSwap = noSwap;
298cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
299cc2eee55SJoe Wallwork }
300cc2eee55SJoe Wallwork 
301cb7bfe8cSJoe Wallwork /*@
302cc2eee55SJoe Wallwork   DMPlexMetricNoSwapping - Is facet swapping turned off?
303cc2eee55SJoe Wallwork 
304cc2eee55SJoe Wallwork   Input parameters:
305cc2eee55SJoe Wallwork . dm     - The DM
306cc2eee55SJoe Wallwork 
307cc2eee55SJoe Wallwork   Output parameters:
308cc2eee55SJoe Wallwork . noSwap - Is facet swapping turned off?
309cc2eee55SJoe Wallwork 
310cc2eee55SJoe Wallwork   Level: beginner
311cc2eee55SJoe Wallwork 
312cb7bfe8cSJoe Wallwork   Notes:
313cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
314cb7bfe8cSJoe Wallwork 
315*76f360caSJoe Wallwork .seealso: DMPlexMetricSetNoSwapping(), DMPlexMetricNoInsertion(), DMPlexMetricNoMovement(), DMPlexMetricNoSurf()
316cb7bfe8cSJoe Wallwork @*/
317cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoSwapping(DM dm, PetscBool *noSwap)
318cc2eee55SJoe Wallwork {
319cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
320cc2eee55SJoe Wallwork   PetscErrorCode ierr;
321cc2eee55SJoe Wallwork 
322cc2eee55SJoe Wallwork   PetscFunctionBegin;
323cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
324cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
325cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
326cc2eee55SJoe Wallwork   }
327cc2eee55SJoe Wallwork   *noSwap = plex->metricCtx->noSwap;
328cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
329cc2eee55SJoe Wallwork }
330cc2eee55SJoe Wallwork 
331cb7bfe8cSJoe Wallwork /*@
332cc2eee55SJoe Wallwork   DMPlexMetricSetNoMovement - Should node movement be turned off?
333cc2eee55SJoe Wallwork 
334cc2eee55SJoe Wallwork   Input parameters:
335cc2eee55SJoe Wallwork + dm     - The DM
336cc2eee55SJoe Wallwork - noMove - Should node movement be turned off?
337cc2eee55SJoe Wallwork 
338cc2eee55SJoe Wallwork   Level: beginner
339cc2eee55SJoe Wallwork 
340cb7bfe8cSJoe Wallwork   Notes:
341cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
342cb7bfe8cSJoe Wallwork 
343*76f360caSJoe Wallwork .seealso: DMPlexMetricNoMovement(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoSwapping(), DMPlexMetricSetNoSurf()
344cb7bfe8cSJoe Wallwork @*/
345cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoMovement(DM dm, PetscBool noMove)
346cc2eee55SJoe Wallwork {
347cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
348cc2eee55SJoe Wallwork   PetscErrorCode ierr;
349cc2eee55SJoe Wallwork 
350cc2eee55SJoe Wallwork   PetscFunctionBegin;
351cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
352cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
353cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
354cc2eee55SJoe Wallwork   }
355cc2eee55SJoe Wallwork   plex->metricCtx->noMove = noMove;
356cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
357cc2eee55SJoe Wallwork }
358cc2eee55SJoe Wallwork 
359cb7bfe8cSJoe Wallwork /*@
360cc2eee55SJoe Wallwork   DMPlexMetricNoMovement - Is node movement turned off?
361cc2eee55SJoe Wallwork 
362cc2eee55SJoe Wallwork   Input parameters:
363cc2eee55SJoe Wallwork . dm     - The DM
364cc2eee55SJoe Wallwork 
365cc2eee55SJoe Wallwork   Output parameters:
366cc2eee55SJoe Wallwork . noMove - Is node movement turned off?
367cc2eee55SJoe Wallwork 
368cc2eee55SJoe Wallwork   Level: beginner
369cc2eee55SJoe Wallwork 
370cb7bfe8cSJoe Wallwork   Notes:
371cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
372cb7bfe8cSJoe Wallwork 
373*76f360caSJoe Wallwork .seealso: DMPlexMetricSetNoMovement(), DMPlexMetricNoInsertion(), DMPlexMetricNoSwapping(), DMPlexMetricNoSurf()
374cb7bfe8cSJoe Wallwork @*/
375cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoMovement(DM dm, PetscBool *noMove)
376cc2eee55SJoe Wallwork {
377cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
378cc2eee55SJoe Wallwork   PetscErrorCode ierr;
379cc2eee55SJoe Wallwork 
380cc2eee55SJoe Wallwork   PetscFunctionBegin;
381cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
382cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
383cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
384cc2eee55SJoe Wallwork   }
385cc2eee55SJoe Wallwork   *noMove = plex->metricCtx->noMove;
386cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
387cc2eee55SJoe Wallwork }
388cc2eee55SJoe Wallwork 
389cb7bfe8cSJoe Wallwork /*@
390*76f360caSJoe Wallwork   DMPlexMetricSetNoSurf - Should surface modification be turned off?
391*76f360caSJoe Wallwork 
392*76f360caSJoe Wallwork   Input parameters:
393*76f360caSJoe Wallwork + dm     - The DM
394*76f360caSJoe Wallwork - noSurf - Should surface modification be turned off?
395*76f360caSJoe Wallwork 
396*76f360caSJoe Wallwork   Level: beginner
397*76f360caSJoe Wallwork 
398*76f360caSJoe Wallwork   Notes:
399*76f360caSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
400*76f360caSJoe Wallwork 
401*76f360caSJoe Wallwork .seealso: DMPlexMetricNoSurf(), DMPlexMetricSetNoMovement(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoSwapping()
402*76f360caSJoe Wallwork @*/
403*76f360caSJoe Wallwork PetscErrorCode DMPlexMetricSetNoSurf(DM dm, PetscBool noSurf)
404*76f360caSJoe Wallwork {
405*76f360caSJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
406*76f360caSJoe Wallwork   PetscErrorCode ierr;
407*76f360caSJoe Wallwork 
408*76f360caSJoe Wallwork   PetscFunctionBegin;
409*76f360caSJoe Wallwork   if (!plex->metricCtx) {
410*76f360caSJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
411*76f360caSJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
412*76f360caSJoe Wallwork   }
413*76f360caSJoe Wallwork   plex->metricCtx->noSurf = noSurf;
414*76f360caSJoe Wallwork   PetscFunctionReturn(0);
415*76f360caSJoe Wallwork }
416*76f360caSJoe Wallwork 
417*76f360caSJoe Wallwork /*@
418*76f360caSJoe Wallwork   DMPlexMetricNoSurf - Is surface modification turned off?
419*76f360caSJoe Wallwork 
420*76f360caSJoe Wallwork   Input parameters:
421*76f360caSJoe Wallwork . dm     - The DM
422*76f360caSJoe Wallwork 
423*76f360caSJoe Wallwork   Output parameters:
424*76f360caSJoe Wallwork . noSurf - Is surface modification turned off?
425*76f360caSJoe Wallwork 
426*76f360caSJoe Wallwork   Level: beginner
427*76f360caSJoe Wallwork 
428*76f360caSJoe Wallwork   Notes:
429*76f360caSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
430*76f360caSJoe Wallwork 
431*76f360caSJoe Wallwork .seealso: DMPlexMetricSetNoSurf(), DMPlexMetricNoMovement(), DMPlexMetricNoInsertion(), DMPlexMetricNoSwapping()
432*76f360caSJoe Wallwork @*/
433*76f360caSJoe Wallwork PetscErrorCode DMPlexMetricNoSurf(DM dm, PetscBool *noSurf)
434*76f360caSJoe Wallwork {
435*76f360caSJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
436*76f360caSJoe Wallwork   PetscErrorCode ierr;
437*76f360caSJoe Wallwork 
438*76f360caSJoe Wallwork   PetscFunctionBegin;
439*76f360caSJoe Wallwork   if (!plex->metricCtx) {
440*76f360caSJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
441*76f360caSJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
442*76f360caSJoe Wallwork   }
443*76f360caSJoe Wallwork   *noSurf = plex->metricCtx->noSurf;
444*76f360caSJoe Wallwork   PetscFunctionReturn(0);
445*76f360caSJoe Wallwork }
446*76f360caSJoe Wallwork 
447*76f360caSJoe Wallwork /*@
44831b70465SJoe Wallwork   DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude
44931b70465SJoe Wallwork 
45031b70465SJoe Wallwork   Input parameters:
45131b70465SJoe Wallwork + dm    - The DM
45231b70465SJoe Wallwork - h_min - The minimum tolerated metric magnitude
45331b70465SJoe Wallwork 
45431b70465SJoe Wallwork   Level: beginner
45531b70465SJoe Wallwork 
45631b70465SJoe Wallwork .seealso: DMPlexMetricGetMinimumMagnitude(), DMPlexMetricSetMaximumMagnitude()
457cb7bfe8cSJoe Wallwork @*/
45831b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min)
45931b70465SJoe Wallwork {
46031b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
46131b70465SJoe Wallwork   PetscErrorCode ierr;
46231b70465SJoe Wallwork 
46331b70465SJoe Wallwork   PetscFunctionBegin;
46431b70465SJoe Wallwork   if (!plex->metricCtx) {
46531b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
46631b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
46731b70465SJoe Wallwork   }
4682c71b3e2SJacob Faibussowitsch   PetscCheckFalse(h_min <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_min);
46931b70465SJoe Wallwork   plex->metricCtx->h_min = h_min;
47031b70465SJoe Wallwork   PetscFunctionReturn(0);
47131b70465SJoe Wallwork }
47231b70465SJoe Wallwork 
473cb7bfe8cSJoe Wallwork /*@
47431b70465SJoe Wallwork   DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude
47531b70465SJoe Wallwork 
47631b70465SJoe Wallwork   Input parameters:
47731b70465SJoe Wallwork . dm    - The DM
47831b70465SJoe Wallwork 
479cc2eee55SJoe Wallwork   Output parameters:
48031b70465SJoe Wallwork . h_min - The minimum tolerated metric magnitude
48131b70465SJoe Wallwork 
48231b70465SJoe Wallwork   Level: beginner
48331b70465SJoe Wallwork 
48431b70465SJoe Wallwork .seealso: DMPlexMetricSetMinimumMagnitude(), DMPlexMetricGetMaximumMagnitude()
485cb7bfe8cSJoe Wallwork @*/
48631b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min)
48731b70465SJoe Wallwork {
48831b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
48931b70465SJoe Wallwork   PetscErrorCode ierr;
49031b70465SJoe Wallwork 
49131b70465SJoe Wallwork   PetscFunctionBegin;
49231b70465SJoe Wallwork   if (!plex->metricCtx) {
49331b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
49431b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
49531b70465SJoe Wallwork   }
49631b70465SJoe Wallwork   *h_min = plex->metricCtx->h_min;
49731b70465SJoe Wallwork   PetscFunctionReturn(0);
49831b70465SJoe Wallwork }
49931b70465SJoe Wallwork 
500cb7bfe8cSJoe Wallwork /*@
50131b70465SJoe Wallwork   DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude
50231b70465SJoe Wallwork 
50331b70465SJoe Wallwork   Input parameters:
50431b70465SJoe Wallwork + dm    - The DM
50531b70465SJoe Wallwork - h_max - The maximum tolerated metric magnitude
50631b70465SJoe Wallwork 
50731b70465SJoe Wallwork   Level: beginner
50831b70465SJoe Wallwork 
50931b70465SJoe Wallwork .seealso: DMPlexMetricGetMaximumMagnitude(), DMPlexMetricSetMinimumMagnitude()
510cb7bfe8cSJoe Wallwork @*/
51131b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max)
51231b70465SJoe Wallwork {
51331b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
51431b70465SJoe Wallwork   PetscErrorCode ierr;
51531b70465SJoe Wallwork 
51631b70465SJoe Wallwork   PetscFunctionBegin;
51731b70465SJoe Wallwork   if (!plex->metricCtx) {
51831b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
51931b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
52031b70465SJoe Wallwork   }
5212c71b3e2SJacob Faibussowitsch   PetscCheckFalse(h_max <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_max);
52231b70465SJoe Wallwork   plex->metricCtx->h_max = h_max;
52331b70465SJoe Wallwork   PetscFunctionReturn(0);
52431b70465SJoe Wallwork }
52531b70465SJoe Wallwork 
526cb7bfe8cSJoe Wallwork /*@
52731b70465SJoe Wallwork   DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude
52831b70465SJoe Wallwork 
52931b70465SJoe Wallwork   Input parameters:
53031b70465SJoe Wallwork . dm    - The DM
53131b70465SJoe Wallwork 
532cc2eee55SJoe Wallwork   Output parameters:
53331b70465SJoe Wallwork . h_max - The maximum tolerated metric magnitude
53431b70465SJoe Wallwork 
53531b70465SJoe Wallwork   Level: beginner
53631b70465SJoe Wallwork 
53731b70465SJoe Wallwork .seealso: DMPlexMetricSetMaximumMagnitude(), DMPlexMetricGetMinimumMagnitude()
538cb7bfe8cSJoe Wallwork @*/
53931b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max)
54031b70465SJoe Wallwork {
54131b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
54231b70465SJoe Wallwork   PetscErrorCode ierr;
54331b70465SJoe Wallwork 
54431b70465SJoe Wallwork   PetscFunctionBegin;
54531b70465SJoe Wallwork   if (!plex->metricCtx) {
54631b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
54731b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
54831b70465SJoe Wallwork   }
54931b70465SJoe Wallwork   *h_max = plex->metricCtx->h_max;
55031b70465SJoe Wallwork   PetscFunctionReturn(0);
55131b70465SJoe Wallwork }
55231b70465SJoe Wallwork 
553cb7bfe8cSJoe Wallwork /*@
55431b70465SJoe Wallwork   DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy
55531b70465SJoe Wallwork 
55631b70465SJoe Wallwork   Input parameters:
55731b70465SJoe Wallwork + dm    - The DM
55831b70465SJoe Wallwork - a_max - The maximum tolerated metric anisotropy
55931b70465SJoe Wallwork 
56031b70465SJoe Wallwork   Level: beginner
56131b70465SJoe Wallwork 
56231b70465SJoe Wallwork   Note: If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one.
56331b70465SJoe Wallwork 
56431b70465SJoe Wallwork .seealso: DMPlexMetricGetMaximumAnisotropy(), DMPlexMetricSetMaximumMagnitude()
565cb7bfe8cSJoe Wallwork @*/
56631b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max)
56731b70465SJoe Wallwork {
56831b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
56931b70465SJoe Wallwork   PetscErrorCode ierr;
57031b70465SJoe Wallwork 
57131b70465SJoe Wallwork   PetscFunctionBegin;
57231b70465SJoe Wallwork   if (!plex->metricCtx) {
57331b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
57431b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
57531b70465SJoe Wallwork   }
5762c71b3e2SJacob Faibussowitsch   PetscCheckFalse(a_max < 1.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Anisotropy must be at least one, not %.4e", a_max);
57731b70465SJoe Wallwork   plex->metricCtx->a_max = a_max;
57831b70465SJoe Wallwork   PetscFunctionReturn(0);
57931b70465SJoe Wallwork }
58031b70465SJoe Wallwork 
581cb7bfe8cSJoe Wallwork /*@
58231b70465SJoe Wallwork   DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy
58331b70465SJoe Wallwork 
58431b70465SJoe Wallwork   Input parameters:
58531b70465SJoe Wallwork . dm    - The DM
58631b70465SJoe Wallwork 
587cc2eee55SJoe Wallwork   Output parameters:
58831b70465SJoe Wallwork . a_max - The maximum tolerated metric anisotropy
58931b70465SJoe Wallwork 
59031b70465SJoe Wallwork   Level: beginner
59131b70465SJoe Wallwork 
59231b70465SJoe Wallwork .seealso: DMPlexMetricSetMaximumAnisotropy(), DMPlexMetricGetMaximumMagnitude()
593cb7bfe8cSJoe Wallwork @*/
59431b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max)
59531b70465SJoe Wallwork {
59631b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
59731b70465SJoe Wallwork   PetscErrorCode ierr;
59831b70465SJoe Wallwork 
59931b70465SJoe Wallwork   PetscFunctionBegin;
60031b70465SJoe Wallwork   if (!plex->metricCtx) {
60131b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
60231b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
60331b70465SJoe Wallwork   }
60431b70465SJoe Wallwork   *a_max = plex->metricCtx->a_max;
60531b70465SJoe Wallwork   PetscFunctionReturn(0);
60631b70465SJoe Wallwork }
60731b70465SJoe Wallwork 
608cb7bfe8cSJoe Wallwork /*@
60931b70465SJoe Wallwork   DMPlexMetricSetTargetComplexity - Set the target metric complexity
61031b70465SJoe Wallwork 
61131b70465SJoe Wallwork   Input parameters:
61231b70465SJoe Wallwork + dm               - The DM
61331b70465SJoe Wallwork - targetComplexity - The target metric complexity
61431b70465SJoe Wallwork 
61531b70465SJoe Wallwork   Level: beginner
61631b70465SJoe Wallwork 
61731b70465SJoe Wallwork .seealso: DMPlexMetricGetTargetComplexity(), DMPlexMetricSetNormalizationOrder()
618cb7bfe8cSJoe Wallwork @*/
61931b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity)
62031b70465SJoe Wallwork {
62131b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
62231b70465SJoe Wallwork   PetscErrorCode ierr;
62331b70465SJoe Wallwork 
62431b70465SJoe Wallwork   PetscFunctionBegin;
62531b70465SJoe Wallwork   if (!plex->metricCtx) {
62631b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
62731b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
62831b70465SJoe Wallwork   }
6292c71b3e2SJacob Faibussowitsch   PetscCheckFalse(targetComplexity <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric complexity must be positive");
63031b70465SJoe Wallwork   plex->metricCtx->targetComplexity = targetComplexity;
63131b70465SJoe Wallwork   PetscFunctionReturn(0);
63231b70465SJoe Wallwork }
63331b70465SJoe Wallwork 
634cb7bfe8cSJoe Wallwork /*@
63531b70465SJoe Wallwork   DMPlexMetricGetTargetComplexity - Get the target metric complexity
63631b70465SJoe Wallwork 
63731b70465SJoe Wallwork   Input parameters:
63831b70465SJoe Wallwork . dm               - The DM
63931b70465SJoe Wallwork 
640cc2eee55SJoe Wallwork   Output parameters:
64131b70465SJoe Wallwork . targetComplexity - The target metric complexity
64231b70465SJoe Wallwork 
64331b70465SJoe Wallwork   Level: beginner
64431b70465SJoe Wallwork 
64531b70465SJoe Wallwork .seealso: DMPlexMetricSetTargetComplexity(), DMPlexMetricGetNormalizationOrder()
646cb7bfe8cSJoe Wallwork @*/
64731b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity)
64831b70465SJoe Wallwork {
64931b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
65031b70465SJoe Wallwork   PetscErrorCode ierr;
65131b70465SJoe Wallwork 
65231b70465SJoe Wallwork   PetscFunctionBegin;
65331b70465SJoe Wallwork   if (!plex->metricCtx) {
65431b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
65531b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
65631b70465SJoe Wallwork   }
65731b70465SJoe Wallwork   *targetComplexity = plex->metricCtx->targetComplexity;
65831b70465SJoe Wallwork   PetscFunctionReturn(0);
65931b70465SJoe Wallwork }
66031b70465SJoe Wallwork 
661cb7bfe8cSJoe Wallwork /*@
66231b70465SJoe Wallwork   DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization
66331b70465SJoe Wallwork 
66431b70465SJoe Wallwork   Input parameters:
66531b70465SJoe Wallwork + dm - The DM
66631b70465SJoe Wallwork - p  - The normalization order
66731b70465SJoe Wallwork 
66831b70465SJoe Wallwork   Level: beginner
66931b70465SJoe Wallwork 
67031b70465SJoe Wallwork .seealso: DMPlexMetricGetNormalizationOrder(), DMPlexMetricSetTargetComplexity()
671cb7bfe8cSJoe Wallwork @*/
67231b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p)
67331b70465SJoe Wallwork {
67431b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
67531b70465SJoe Wallwork   PetscErrorCode ierr;
67631b70465SJoe Wallwork 
67731b70465SJoe Wallwork   PetscFunctionBegin;
67831b70465SJoe Wallwork   if (!plex->metricCtx) {
67931b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
68031b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
68131b70465SJoe Wallwork   }
6822c71b3e2SJacob Faibussowitsch   PetscCheckFalse(p < 1.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Normalization order must be one or greater");
68331b70465SJoe Wallwork   plex->metricCtx->p = p;
68431b70465SJoe Wallwork   PetscFunctionReturn(0);
68531b70465SJoe Wallwork }
68631b70465SJoe Wallwork 
687cb7bfe8cSJoe Wallwork /*@
68831b70465SJoe Wallwork   DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization
68931b70465SJoe Wallwork 
69031b70465SJoe Wallwork   Input parameters:
69131b70465SJoe Wallwork . dm - The DM
69231b70465SJoe Wallwork 
693cc2eee55SJoe Wallwork   Output parameters:
69431b70465SJoe Wallwork . p - The normalization order
69531b70465SJoe Wallwork 
69631b70465SJoe Wallwork   Level: beginner
69731b70465SJoe Wallwork 
69831b70465SJoe Wallwork .seealso: DMPlexMetricSetNormalizationOrder(), DMPlexMetricGetTargetComplexity()
699cb7bfe8cSJoe Wallwork @*/
70031b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p)
70131b70465SJoe Wallwork {
70231b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
70331b70465SJoe Wallwork   PetscErrorCode ierr;
70431b70465SJoe Wallwork 
70531b70465SJoe Wallwork   PetscFunctionBegin;
70631b70465SJoe Wallwork   if (!plex->metricCtx) {
70731b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
70831b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
70931b70465SJoe Wallwork   }
71031b70465SJoe Wallwork   *p = plex->metricCtx->p;
71131b70465SJoe Wallwork   PetscFunctionReturn(0);
71231b70465SJoe Wallwork }
71331b70465SJoe Wallwork 
714cb7bfe8cSJoe Wallwork /*@
715cc2eee55SJoe Wallwork   DMPlexMetricSetGradationFactor - Set the metric gradation factor
716cc2eee55SJoe Wallwork 
717cc2eee55SJoe Wallwork   Input parameters:
718cc2eee55SJoe Wallwork + dm   - The DM
719cc2eee55SJoe Wallwork - beta - The metric gradation factor
720cc2eee55SJoe Wallwork 
721cc2eee55SJoe Wallwork   Level: beginner
722cc2eee55SJoe Wallwork 
723cc2eee55SJoe Wallwork   Notes:
724cc2eee55SJoe Wallwork 
725cc2eee55SJoe Wallwork   The gradation factor is the maximum tolerated length ratio between adjacent edges.
726cc2eee55SJoe Wallwork 
727cc2eee55SJoe Wallwork   Turn off gradation by passing the value -1. Otherwise, pass a positive value.
728cc2eee55SJoe Wallwork 
729cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
730cb7bfe8cSJoe Wallwork 
731ae8b063eSJoe Wallwork .seealso: DMPlexMetricGetGradationFactor(), DMPlexMetricSetHausdorffNumber()
732cb7bfe8cSJoe Wallwork @*/
733cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetGradationFactor(DM dm, PetscReal beta)
734cc2eee55SJoe Wallwork {
735cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
736cc2eee55SJoe Wallwork   PetscErrorCode ierr;
737cc2eee55SJoe Wallwork 
738cc2eee55SJoe Wallwork   PetscFunctionBegin;
739cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
740cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
741cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
742cc2eee55SJoe Wallwork   }
743cc2eee55SJoe Wallwork   plex->metricCtx->gradationFactor = beta;
744cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
745cc2eee55SJoe Wallwork }
746cc2eee55SJoe Wallwork 
747cb7bfe8cSJoe Wallwork /*@
748cc2eee55SJoe Wallwork   DMPlexMetricGetGradationFactor - Get the metric gradation factor
749cc2eee55SJoe Wallwork 
750cc2eee55SJoe Wallwork   Input parameters:
751cc2eee55SJoe Wallwork . dm   - The DM
752cc2eee55SJoe Wallwork 
753cc2eee55SJoe Wallwork   Output parameters:
754cc2eee55SJoe Wallwork . beta - The metric gradation factor
755cc2eee55SJoe Wallwork 
756cc2eee55SJoe Wallwork   Level: beginner
757cc2eee55SJoe Wallwork 
758cb7bfe8cSJoe Wallwork   Notes:
759cb7bfe8cSJoe Wallwork 
760cb7bfe8cSJoe Wallwork   The gradation factor is the maximum tolerated length ratio between adjacent edges.
761cb7bfe8cSJoe Wallwork 
762cb7bfe8cSJoe Wallwork   The value -1 implies that gradation is turned off.
763cb7bfe8cSJoe Wallwork 
764cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
765cc2eee55SJoe Wallwork 
766ae8b063eSJoe Wallwork .seealso: DMPlexMetricSetGradationFactor(), DMPlexMetricGetHausdorffNumber()
767cb7bfe8cSJoe Wallwork @*/
768cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetGradationFactor(DM dm, PetscReal *beta)
769cc2eee55SJoe Wallwork {
770cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
771cc2eee55SJoe Wallwork   PetscErrorCode ierr;
772cc2eee55SJoe Wallwork 
773cc2eee55SJoe Wallwork   PetscFunctionBegin;
774cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
775cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
776cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
777cc2eee55SJoe Wallwork   }
778cc2eee55SJoe Wallwork   *beta = plex->metricCtx->gradationFactor;
779cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
780cc2eee55SJoe Wallwork }
781cc2eee55SJoe Wallwork 
782cb7bfe8cSJoe Wallwork /*@
783ae8b063eSJoe Wallwork   DMPlexMetricSetHausdorffNumber - Set the metric Hausdorff number
784ae8b063eSJoe Wallwork 
785ae8b063eSJoe Wallwork   Input parameters:
786ae8b063eSJoe Wallwork + dm    - The DM
787ae8b063eSJoe Wallwork - hausd - The metric Hausdorff number
788ae8b063eSJoe Wallwork 
789ae8b063eSJoe Wallwork   Level: beginner
790ae8b063eSJoe Wallwork 
791ae8b063eSJoe Wallwork   Notes:
792ae8b063eSJoe Wallwork 
793ae8b063eSJoe Wallwork   The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the
794ae8b063eSJoe Wallwork   boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the
795ae8b063eSJoe Wallwork   high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for
796ae8b063eSJoe Wallwork   an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease
797ae8b063eSJoe Wallwork   (resp. increase) the Hausdorff parameter. (Taken from
798ae8b063eSJoe Wallwork   https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd).
799ae8b063eSJoe Wallwork 
800ae8b063eSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
801ae8b063eSJoe Wallwork 
802ae8b063eSJoe Wallwork .seealso: DMPlexMetricSetGradationFactor(), DMPlexMetricGetHausdorffNumber()
803ae8b063eSJoe Wallwork @*/
804ae8b063eSJoe Wallwork PetscErrorCode DMPlexMetricSetHausdorffNumber(DM dm, PetscReal hausd)
805ae8b063eSJoe Wallwork {
806ae8b063eSJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
807ae8b063eSJoe Wallwork   PetscErrorCode ierr;
808ae8b063eSJoe Wallwork 
809ae8b063eSJoe Wallwork   PetscFunctionBegin;
810ae8b063eSJoe Wallwork   if (!plex->metricCtx) {
811ae8b063eSJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
812ae8b063eSJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
813ae8b063eSJoe Wallwork   }
814ae8b063eSJoe Wallwork   plex->metricCtx->hausdorffNumber = hausd;
815ae8b063eSJoe Wallwork   PetscFunctionReturn(0);
816ae8b063eSJoe Wallwork }
817ae8b063eSJoe Wallwork 
818ae8b063eSJoe Wallwork /*@
819ae8b063eSJoe Wallwork   DMPlexMetricGetHausdorffNumber - Get the metric Hausdorff number
820ae8b063eSJoe Wallwork 
821ae8b063eSJoe Wallwork   Input parameters:
822ae8b063eSJoe Wallwork . dm    - The DM
823ae8b063eSJoe Wallwork 
824ae8b063eSJoe Wallwork   Output parameters:
825ae8b063eSJoe Wallwork . hausd - The metric Hausdorff number
826ae8b063eSJoe Wallwork 
827ae8b063eSJoe Wallwork   Level: beginner
828ae8b063eSJoe Wallwork 
829ae8b063eSJoe Wallwork   Notes:
830ae8b063eSJoe Wallwork 
831ae8b063eSJoe Wallwork   The Hausdorff number imposes the maximal distance between the piecewise linear approximation of the
832ae8b063eSJoe Wallwork   boundary and the reconstructed ideal boundary. Thus, a low Hausdorff parameter leads to refine the
833ae8b063eSJoe Wallwork   high curvature areas. By default, the Hausdorff value is set to 0.01, which is a suitable value for
834ae8b063eSJoe Wallwork   an object of size 1 in each direction. For smaller (resp. larger) objects, you may need to decrease
835ae8b063eSJoe Wallwork   (resp. increase) the Hausdorff parameter. (Taken from
836ae8b063eSJoe Wallwork   https://www.mmgtools.org/mmg-remesher-try-mmg/mmg-remesher-options/mmg-remesher-option-hausd).
837ae8b063eSJoe Wallwork 
838ae8b063eSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
839ae8b063eSJoe Wallwork 
840ae8b063eSJoe Wallwork .seealso: DMPlexMetricGetGradationFactor(), DMPlexMetricSetHausdorffNumber()
841ae8b063eSJoe Wallwork @*/
842ae8b063eSJoe Wallwork PetscErrorCode DMPlexMetricGetHausdorffNumber(DM dm, PetscReal *hausd)
843ae8b063eSJoe Wallwork {
844ae8b063eSJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
845ae8b063eSJoe Wallwork   PetscErrorCode ierr;
846ae8b063eSJoe Wallwork 
847ae8b063eSJoe Wallwork   PetscFunctionBegin;
848ae8b063eSJoe Wallwork   if (!plex->metricCtx) {
849ae8b063eSJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
850ae8b063eSJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
851ae8b063eSJoe Wallwork   }
852ae8b063eSJoe Wallwork   *hausd = plex->metricCtx->hausdorffNumber;
853ae8b063eSJoe Wallwork   PetscFunctionReturn(0);
854ae8b063eSJoe Wallwork }
855ae8b063eSJoe Wallwork 
856ae8b063eSJoe Wallwork /*@
857cc2eee55SJoe Wallwork   DMPlexMetricSetVerbosity - Set the verbosity of the mesh adaptation package
858cc2eee55SJoe Wallwork 
859cc2eee55SJoe Wallwork   Input parameters:
860cc2eee55SJoe Wallwork + dm        - The DM
861cc2eee55SJoe Wallwork - verbosity - The verbosity, where -1 is silent and 10 is maximum
862cc2eee55SJoe Wallwork 
863cb7bfe8cSJoe Wallwork   Level: beginner
864cb7bfe8cSJoe Wallwork 
865cb7bfe8cSJoe Wallwork   Notes:
866cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
867cb7bfe8cSJoe Wallwork 
868cc2eee55SJoe Wallwork .seealso: DMPlexMetricGetVerbosity(), DMPlexMetricSetNumIterations()
869cb7bfe8cSJoe Wallwork @*/
870cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetVerbosity(DM dm, PetscInt verbosity)
871cc2eee55SJoe Wallwork {
872cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
873cc2eee55SJoe Wallwork   PetscErrorCode ierr;
874cc2eee55SJoe Wallwork 
875cc2eee55SJoe Wallwork   PetscFunctionBegin;
876cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
877cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
878cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
879cc2eee55SJoe Wallwork   }
880cc2eee55SJoe Wallwork   plex->metricCtx->verbosity = verbosity;
881cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
882cc2eee55SJoe Wallwork }
883cc2eee55SJoe Wallwork 
884cb7bfe8cSJoe Wallwork /*@
885cc2eee55SJoe Wallwork   DMPlexMetricGetVerbosity - Get the verbosity of the mesh adaptation package
886cc2eee55SJoe Wallwork 
887cc2eee55SJoe Wallwork   Input parameters:
888cc2eee55SJoe Wallwork . dm        - The DM
889cc2eee55SJoe Wallwork 
890cc2eee55SJoe Wallwork   Output parameters:
891cc2eee55SJoe Wallwork . verbosity - The verbosity, where -1 is silent and 10 is maximum
892cc2eee55SJoe Wallwork 
893cb7bfe8cSJoe Wallwork   Level: beginner
894cb7bfe8cSJoe Wallwork 
895cb7bfe8cSJoe Wallwork   Notes:
896cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic).
897cb7bfe8cSJoe Wallwork 
898cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations()
899cb7bfe8cSJoe Wallwork @*/
900cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetVerbosity(DM dm, PetscInt *verbosity)
901cc2eee55SJoe Wallwork {
902cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
903cc2eee55SJoe Wallwork   PetscErrorCode ierr;
904cc2eee55SJoe Wallwork 
905cc2eee55SJoe Wallwork   PetscFunctionBegin;
906cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
907cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
908cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
909cc2eee55SJoe Wallwork   }
910cc2eee55SJoe Wallwork   *verbosity = plex->metricCtx->verbosity;
911cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
912cc2eee55SJoe Wallwork }
913cc2eee55SJoe Wallwork 
914cb7bfe8cSJoe Wallwork /*@
915cc2eee55SJoe Wallwork   DMPlexMetricSetNumIterations - Set the number of parallel adaptation iterations
916cc2eee55SJoe Wallwork 
917cc2eee55SJoe Wallwork   Input parameters:
918cc2eee55SJoe Wallwork + dm      - The DM
919cc2eee55SJoe Wallwork - numIter - the number of parallel adaptation iterations
920cc2eee55SJoe Wallwork 
921cb7bfe8cSJoe Wallwork   Level: beginner
922cb7bfe8cSJoe Wallwork 
923cb7bfe8cSJoe Wallwork   Notes:
924cb7bfe8cSJoe Wallwork   This is only used by ParMmg (not Pragmatic or Mmg).
925cc2eee55SJoe Wallwork 
926cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations()
927cb7bfe8cSJoe Wallwork @*/
928cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNumIterations(DM dm, PetscInt numIter)
929cc2eee55SJoe Wallwork {
930cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
931cc2eee55SJoe Wallwork   PetscErrorCode ierr;
932cc2eee55SJoe Wallwork 
933cc2eee55SJoe Wallwork   PetscFunctionBegin;
934cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
935cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
936cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
937cc2eee55SJoe Wallwork   }
938cc2eee55SJoe Wallwork   plex->metricCtx->numIter = numIter;
939cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
940cc2eee55SJoe Wallwork }
941cc2eee55SJoe Wallwork 
942cb7bfe8cSJoe Wallwork /*@
943cc2eee55SJoe Wallwork   DMPlexMetricGetNumIterations - Get the number of parallel adaptation iterations
944cc2eee55SJoe Wallwork 
945cc2eee55SJoe Wallwork   Input parameters:
946cc2eee55SJoe Wallwork . dm      - The DM
947cc2eee55SJoe Wallwork 
948cc2eee55SJoe Wallwork   Output parameters:
949cc2eee55SJoe Wallwork . numIter - the number of parallel adaptation iterations
950cc2eee55SJoe Wallwork 
951cb7bfe8cSJoe Wallwork   Level: beginner
952cb7bfe8cSJoe Wallwork 
953cb7bfe8cSJoe Wallwork   Notes:
954cb7bfe8cSJoe Wallwork   This is only used by Mmg and ParMmg (not Pragmatic or Mmg).
955cc2eee55SJoe Wallwork 
956cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetNumIterations(), DMPlexMetricGetVerbosity()
957cb7bfe8cSJoe Wallwork @*/
958cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetNumIterations(DM dm, PetscInt *numIter)
959cc2eee55SJoe Wallwork {
960cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
961cc2eee55SJoe Wallwork   PetscErrorCode ierr;
962cc2eee55SJoe Wallwork 
963cc2eee55SJoe Wallwork   PetscFunctionBegin;
964cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
965cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
966cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
967cc2eee55SJoe Wallwork   }
968cc2eee55SJoe Wallwork   *numIter = plex->metricCtx->numIter;
969cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
970cc2eee55SJoe Wallwork }
971cc2eee55SJoe Wallwork 
97220282da2SJoe Wallwork PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric)
97320282da2SJoe Wallwork {
97420282da2SJoe Wallwork   MPI_Comm       comm;
97520282da2SJoe Wallwork   PetscErrorCode ierr;
97620282da2SJoe Wallwork   PetscFE        fe;
97720282da2SJoe Wallwork   PetscInt       dim;
97820282da2SJoe Wallwork 
97920282da2SJoe Wallwork   PetscFunctionBegin;
98020282da2SJoe Wallwork 
98120282da2SJoe Wallwork   /* Extract metadata from dm */
98220282da2SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
98320282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
98420282da2SJoe Wallwork 
98520282da2SJoe Wallwork   /* Create a P1 field of the requested size */
98620282da2SJoe Wallwork   ierr = PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe);CHKERRQ(ierr);
98720282da2SJoe Wallwork   ierr = DMSetField(dm, f, NULL, (PetscObject)fe);CHKERRQ(ierr);
98820282da2SJoe Wallwork   ierr = DMCreateDS(dm);CHKERRQ(ierr);
98920282da2SJoe Wallwork   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
99020282da2SJoe Wallwork   ierr = DMCreateLocalVector(dm, metric);CHKERRQ(ierr);
99120282da2SJoe Wallwork 
99220282da2SJoe Wallwork   PetscFunctionReturn(0);
99320282da2SJoe Wallwork }
99420282da2SJoe Wallwork 
995cb7bfe8cSJoe Wallwork /*@
99620282da2SJoe Wallwork   DMPlexMetricCreate - Create a Riemannian metric field
99720282da2SJoe Wallwork 
99820282da2SJoe Wallwork   Input parameters:
99920282da2SJoe Wallwork + dm     - The DM
100020282da2SJoe Wallwork - f      - The field number to use
100120282da2SJoe Wallwork 
100220282da2SJoe Wallwork   Output parameter:
100320282da2SJoe Wallwork . metric - The metric
100420282da2SJoe Wallwork 
100520282da2SJoe Wallwork   Level: beginner
100620282da2SJoe Wallwork 
100731b70465SJoe Wallwork   Notes:
100831b70465SJoe Wallwork 
100931b70465SJoe Wallwork   It is assumed that the DM is comprised of simplices.
101031b70465SJoe Wallwork 
101131b70465SJoe Wallwork   Command line options for Riemannian metrics:
101231b70465SJoe Wallwork 
1013cb7bfe8cSJoe Wallwork + -dm_plex_metric_isotropic                 - Is the metric isotropic?
101493520041SJoe Wallwork . -dm_plex_metric_uniform                   - Is the metric uniform?
1015cb7bfe8cSJoe Wallwork . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization?
1016cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_min                     - Minimum tolerated metric magnitude
1017cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max                     - Maximum tolerated metric magnitude
1018cb7bfe8cSJoe Wallwork . -dm_plex_metric_a_max                     - Maximum tolerated anisotropy
1019cb7bfe8cSJoe Wallwork . -dm_plex_metric_p                         - L-p normalization order
102067b8a455SSatish Balay - -dm_plex_metric_target_complexity         - Target metric complexity
1021cb7bfe8cSJoe Wallwork 
1022cb7bfe8cSJoe Wallwork   Switching between remeshers can be achieved using
1023cb7bfe8cSJoe Wallwork 
102467b8a455SSatish Balay . -dm_adaptor <pragmatic/mmg/parmmg>        - specify dm adaptor to use
1025cb7bfe8cSJoe Wallwork 
1026cb7bfe8cSJoe Wallwork   Further options that are only relevant to Mmg and ParMmg:
1027cb7bfe8cSJoe Wallwork 
1028cb7bfe8cSJoe Wallwork + -dm_plex_metric_gradation_factor          - Maximum ratio by which edge lengths may grow during gradation
1029cb7bfe8cSJoe Wallwork . -dm_plex_metric_num_iterations            - Number of parallel mesh adaptation iterations for ParMmg
1030cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_insert                 - Should node insertion/deletion be turned off?
1031cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_swap                   - Should facet swapping be turned off?
1032cb7bfe8cSJoe Wallwork . -dm_plex_metric_no_move                   - Should node movement be turned off?
1033cb7bfe8cSJoe Wallwork - -dm_plex_metric_verbosity                 - Choose a verbosity level from -1 (silent) to 10 (maximum).
103420282da2SJoe Wallwork 
103520282da2SJoe Wallwork .seealso: DMPlexMetricCreateUniform(), DMPlexMetricCreateIsotropic()
1036cb7bfe8cSJoe Wallwork @*/
103720282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric)
103820282da2SJoe Wallwork {
103931b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
104093520041SJoe Wallwork   PetscBool      isotropic, uniform;
104120282da2SJoe Wallwork   PetscErrorCode ierr;
104220282da2SJoe Wallwork   PetscInt       coordDim, Nd;
104320282da2SJoe Wallwork 
104420282da2SJoe Wallwork   PetscFunctionBegin;
104531b70465SJoe Wallwork   if (!plex->metricCtx) {
104631b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
104731b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
104831b70465SJoe Wallwork   }
104920282da2SJoe Wallwork   ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr);
105020282da2SJoe Wallwork   Nd = coordDim*coordDim;
105193520041SJoe Wallwork   ierr = DMPlexMetricIsUniform(dm, &uniform);CHKERRQ(ierr);
105293520041SJoe Wallwork   ierr = DMPlexMetricIsIsotropic(dm, &isotropic);CHKERRQ(ierr);
105393520041SJoe Wallwork   if (uniform) {
105493520041SJoe Wallwork     MPI_Comm comm;
105593520041SJoe Wallwork 
105693520041SJoe Wallwork     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
10572c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!isotropic,comm, PETSC_ERR_ARG_WRONG, "Uniform anisotropic metrics not supported");
105893520041SJoe Wallwork     ierr = VecCreate(comm, metric);CHKERRQ(ierr);
105993520041SJoe Wallwork     ierr = VecSetSizes(*metric, 1, PETSC_DECIDE);CHKERRQ(ierr);
106093520041SJoe Wallwork     ierr = VecSetFromOptions(*metric);CHKERRQ(ierr);
106193520041SJoe Wallwork   } else if (isotropic) {
106293520041SJoe Wallwork     ierr = DMPlexP1FieldCreate_Private(dm, f, 1, metric);CHKERRQ(ierr);
106393520041SJoe Wallwork   } else {
106420282da2SJoe Wallwork     ierr = DMPlexP1FieldCreate_Private(dm, f, Nd, metric);CHKERRQ(ierr);
106593520041SJoe Wallwork   }
106620282da2SJoe Wallwork   PetscFunctionReturn(0);
106720282da2SJoe Wallwork }
106820282da2SJoe Wallwork 
1069cb7bfe8cSJoe Wallwork /*@
107020282da2SJoe Wallwork   DMPlexMetricCreateUniform - Construct a uniform isotropic metric
107120282da2SJoe Wallwork 
107220282da2SJoe Wallwork   Input parameters:
107320282da2SJoe Wallwork + dm     - The DM
107420282da2SJoe Wallwork . f      - The field number to use
107520282da2SJoe Wallwork - alpha  - Scaling parameter for the diagonal
107620282da2SJoe Wallwork 
107720282da2SJoe Wallwork   Output parameter:
107820282da2SJoe Wallwork . metric - The uniform metric
107920282da2SJoe Wallwork 
108020282da2SJoe Wallwork   Level: beginner
108120282da2SJoe Wallwork 
108293520041SJoe Wallwork   Note: In this case, the metric is constant in space and so is only specified for a single vertex.
108320282da2SJoe Wallwork 
108420282da2SJoe Wallwork .seealso: DMPlexMetricCreate(), DMPlexMetricCreateIsotropic()
1085cb7bfe8cSJoe Wallwork @*/
108620282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric)
108720282da2SJoe Wallwork {
108820282da2SJoe Wallwork   PetscErrorCode ierr;
108920282da2SJoe Wallwork 
109020282da2SJoe Wallwork   PetscFunctionBegin;
109193520041SJoe Wallwork   ierr = DMPlexMetricSetUniform(dm, PETSC_TRUE);CHKERRQ(ierr);
109220282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr);
10932c71b3e2SJacob Faibussowitsch   PetscCheck(alpha,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined");
10942c71b3e2SJacob Faibussowitsch   PetscCheck(alpha >= 1.0e-30,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling %e should be positive", alpha);
109593520041SJoe Wallwork   ierr = VecSet(*metric, alpha);CHKERRQ(ierr);
109693520041SJoe Wallwork   ierr = VecAssemblyBegin(*metric);CHKERRQ(ierr);
109793520041SJoe Wallwork   ierr = VecAssemblyEnd(*metric);CHKERRQ(ierr);
109820282da2SJoe Wallwork   PetscFunctionReturn(0);
109920282da2SJoe Wallwork }
110020282da2SJoe Wallwork 
110193520041SJoe Wallwork static void identity(PetscInt dim, PetscInt Nf, PetscInt NfAux,
110293520041SJoe Wallwork                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
110393520041SJoe Wallwork                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
110493520041SJoe Wallwork                      PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
110593520041SJoe Wallwork {
110693520041SJoe Wallwork   f0[0] = u[0];
110793520041SJoe Wallwork }
110893520041SJoe Wallwork 
1109cb7bfe8cSJoe Wallwork /*@
111020282da2SJoe Wallwork   DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator
111120282da2SJoe Wallwork 
111220282da2SJoe Wallwork   Input parameters:
111320282da2SJoe Wallwork + dm        - The DM
111420282da2SJoe Wallwork . f         - The field number to use
111520282da2SJoe Wallwork - indicator - The error indicator
111620282da2SJoe Wallwork 
111720282da2SJoe Wallwork   Output parameter:
111820282da2SJoe Wallwork . metric    - The isotropic metric
111920282da2SJoe Wallwork 
112020282da2SJoe Wallwork   Level: beginner
112120282da2SJoe Wallwork 
112220282da2SJoe Wallwork   Notes:
112320282da2SJoe Wallwork 
112420282da2SJoe Wallwork   It is assumed that the DM is comprised of simplices.
112520282da2SJoe Wallwork 
112693520041SJoe Wallwork   The indicator needs to be a scalar field. If it is not defined vertex-wise, then it is projected appropriately.
112720282da2SJoe Wallwork 
112820282da2SJoe Wallwork .seealso: DMPlexMetricCreate(), DMPlexMetricCreateUniform()
1129cb7bfe8cSJoe Wallwork @*/
113020282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric)
113120282da2SJoe Wallwork {
113220282da2SJoe Wallwork   PetscErrorCode ierr;
113393520041SJoe Wallwork   PetscInt       m, n;
113420282da2SJoe Wallwork 
113520282da2SJoe Wallwork   PetscFunctionBegin;
113693520041SJoe Wallwork   ierr = DMPlexMetricSetIsotropic(dm, PETSC_TRUE);CHKERRQ(ierr);
113720282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr);
113893520041SJoe Wallwork   ierr = VecGetSize(indicator, &m);CHKERRQ(ierr);
113993520041SJoe Wallwork   ierr = VecGetSize(*metric, &n);CHKERRQ(ierr);
114093520041SJoe Wallwork   if (m == n) { ierr = VecCopy(indicator, *metric);CHKERRQ(ierr); }
114193520041SJoe Wallwork   else {
114293520041SJoe Wallwork     DM     dmIndi;
114393520041SJoe Wallwork     void (*funcs[1])(PetscInt, PetscInt, PetscInt,
114493520041SJoe Wallwork                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
114593520041SJoe Wallwork                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
114693520041SJoe Wallwork                      PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
114793520041SJoe Wallwork 
114820282da2SJoe Wallwork     ierr = VecGetDM(indicator, &dmIndi);CHKERRQ(ierr);
114993520041SJoe Wallwork     funcs[0] = identity;
115093520041SJoe Wallwork     ierr = DMProjectFieldLocal(dmIndi, 0.0, indicator, funcs, INSERT_VALUES, *metric);CHKERRQ(ierr);
115120282da2SJoe Wallwork   }
115220282da2SJoe Wallwork   PetscFunctionReturn(0);
115320282da2SJoe Wallwork }
115420282da2SJoe Wallwork 
115582490253SJoe Wallwork static PetscErrorCode LAPACKsyevFail(PetscInt dim, PetscScalar Mpos[])
115682490253SJoe Wallwork {
115782490253SJoe Wallwork   PetscInt i, j;
115882490253SJoe Wallwork 
115982490253SJoe Wallwork   PetscFunctionBegin;
116082490253SJoe Wallwork   PetscPrintf(PETSC_COMM_SELF, "Failed to apply LAPACKsyev to the matrix\n");
116182490253SJoe Wallwork   for (i = 0; i < dim; ++i) {
116282490253SJoe Wallwork     if (i == 0) PetscPrintf(PETSC_COMM_SELF, "    [[");
116382490253SJoe Wallwork     else        PetscPrintf(PETSC_COMM_SELF, "     [");
116482490253SJoe Wallwork     for (j = 0; j < dim; ++j) {
116582490253SJoe Wallwork       if (j < dim-1) PetscPrintf(PETSC_COMM_SELF, "%15.8e, ", Mpos[i*dim+j]);
116682490253SJoe Wallwork       else           PetscPrintf(PETSC_COMM_SELF, "%15.8e", Mpos[i*dim+j]);
116782490253SJoe Wallwork     }
116882490253SJoe Wallwork     if (i < dim-1) PetscPrintf(PETSC_COMM_SELF, "]\n");
116982490253SJoe Wallwork     else           PetscPrintf(PETSC_COMM_SELF, "]]\n");
117082490253SJoe Wallwork   }
117182490253SJoe Wallwork   PetscFunctionReturn(0);
117282490253SJoe Wallwork }
117382490253SJoe Wallwork 
11743f07679eSJoe Wallwork static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[], PetscScalar *detMp)
117520282da2SJoe Wallwork {
117620282da2SJoe Wallwork   PetscErrorCode ierr;
117720282da2SJoe Wallwork   PetscInt       i, j, k;
117820282da2SJoe 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);
117920282da2SJoe Wallwork   PetscScalar   *Mpos;
118020282da2SJoe Wallwork 
118120282da2SJoe Wallwork   PetscFunctionBegin;
118220282da2SJoe Wallwork   ierr = PetscMalloc2(dim*dim, &Mpos, dim, &eigs);CHKERRQ(ierr);
118320282da2SJoe Wallwork 
118420282da2SJoe Wallwork   /* Symmetrize */
118520282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
118620282da2SJoe Wallwork     Mpos[i*dim+i] = Mp[i*dim+i];
118720282da2SJoe Wallwork     for (j = i+1; j < dim; ++j) {
118820282da2SJoe Wallwork       Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]);
118920282da2SJoe Wallwork       Mpos[j*dim+i] = Mpos[i*dim+j];
119020282da2SJoe Wallwork     }
119120282da2SJoe Wallwork   }
119220282da2SJoe Wallwork 
119320282da2SJoe Wallwork   /* Compute eigendecomposition */
119493520041SJoe Wallwork   if (dim == 1) {
119593520041SJoe Wallwork 
119693520041SJoe Wallwork     /* Isotropic case */
119793520041SJoe Wallwork     eigs[0] = PetscRealPart(Mpos[0]);
119893520041SJoe Wallwork     Mpos[0] = 1.0;
119993520041SJoe Wallwork   } else {
120093520041SJoe Wallwork 
120193520041SJoe Wallwork     /* Anisotropic case */
120220282da2SJoe Wallwork     PetscScalar  *work;
120320282da2SJoe Wallwork     PetscBLASInt lwork;
120420282da2SJoe Wallwork 
120520282da2SJoe Wallwork     lwork = 5*dim;
120620282da2SJoe Wallwork     ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr);
120720282da2SJoe Wallwork     {
120820282da2SJoe Wallwork       PetscBLASInt lierr;
120920282da2SJoe Wallwork       PetscBLASInt nb;
121020282da2SJoe Wallwork 
121120282da2SJoe Wallwork       ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr);
121220282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
121320282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
121420282da2SJoe Wallwork       {
121520282da2SJoe Wallwork         PetscReal *rwork;
121620282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
121720282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr));
121820282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
121920282da2SJoe Wallwork       }
122020282da2SJoe Wallwork #else
122120282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr));
122220282da2SJoe Wallwork #endif
122382490253SJoe Wallwork       if (lierr) {
122482490253SJoe Wallwork         for (i = 0; i < dim; ++i) {
122582490253SJoe Wallwork           Mpos[i*dim+i] = Mp[i*dim+i];
122682490253SJoe Wallwork           for (j = i+1; j < dim; ++j) {
122782490253SJoe Wallwork             Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]);
122882490253SJoe Wallwork             Mpos[j*dim+i] = Mpos[i*dim+j];
122982490253SJoe Wallwork           }
123082490253SJoe Wallwork         }
123182490253SJoe Wallwork         LAPACKsyevFail(dim, Mpos);
123298921bdaSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
123382490253SJoe Wallwork       }
123420282da2SJoe Wallwork       ierr = PetscFPTrapPop();CHKERRQ(ierr);
123520282da2SJoe Wallwork     }
123620282da2SJoe Wallwork     ierr = PetscFree(work);CHKERRQ(ierr);
123720282da2SJoe Wallwork   }
123820282da2SJoe Wallwork 
123920282da2SJoe Wallwork   /* Reflect to positive orthant and enforce maximum and minimum size */
124020282da2SJoe Wallwork   max_eig = 0.0;
124120282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
124220282da2SJoe Wallwork     eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i])));
124320282da2SJoe Wallwork     max_eig = PetscMax(eigs[i], max_eig);
124420282da2SJoe Wallwork   }
124520282da2SJoe Wallwork 
12463f07679eSJoe Wallwork   /* Enforce maximum anisotropy and compute determinant */
12473f07679eSJoe Wallwork   *detMp = 1.0;
124820282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
124920282da2SJoe Wallwork     if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min);
12503f07679eSJoe Wallwork     *detMp *= eigs[i];
125120282da2SJoe Wallwork   }
125220282da2SJoe Wallwork 
125320282da2SJoe Wallwork   /* Reconstruct Hessian */
125420282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
125520282da2SJoe Wallwork     for (j = 0; j < dim; ++j) {
125620282da2SJoe Wallwork       Mp[i*dim+j] = 0.0;
125720282da2SJoe Wallwork       for (k = 0; k < dim; ++k) {
125820282da2SJoe Wallwork         Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j];
125920282da2SJoe Wallwork       }
126020282da2SJoe Wallwork     }
126120282da2SJoe Wallwork   }
126220282da2SJoe Wallwork   ierr = PetscFree2(Mpos, eigs);CHKERRQ(ierr);
126320282da2SJoe Wallwork 
126420282da2SJoe Wallwork   PetscFunctionReturn(0);
126520282da2SJoe Wallwork }
126620282da2SJoe Wallwork 
1267cb7bfe8cSJoe Wallwork /*@
126820282da2SJoe Wallwork   DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric
126920282da2SJoe Wallwork 
127020282da2SJoe Wallwork   Input parameters:
127120282da2SJoe Wallwork + dm                 - The DM
12723f07679eSJoe Wallwork . metricIn           - The metric
127399abec2bSJoe Wallwork . restrictSizes      - Should maximum/minimum metric magnitudes be enforced?
12743f07679eSJoe Wallwork - restrictAnisotropy - Should maximum anisotropy be enforced?
127520282da2SJoe Wallwork 
127620282da2SJoe Wallwork   Output parameter:
12773f07679eSJoe Wallwork + metricOut          - The metric
12783f07679eSJoe Wallwork - determinant        - Its determinant
127920282da2SJoe Wallwork 
128020282da2SJoe Wallwork   Level: beginner
128120282da2SJoe Wallwork 
1282cb7bfe8cSJoe Wallwork   Notes:
1283cb7bfe8cSJoe Wallwork 
1284cb7bfe8cSJoe Wallwork   Relevant command line options:
1285cb7bfe8cSJoe Wallwork 
128693520041SJoe Wallwork + -dm_plex_metric_isotropic - Is the metric isotropic?
128793520041SJoe Wallwork . -dm_plex_metric_uniform   - Is the metric uniform?
128893520041SJoe Wallwork . -dm_plex_metric_h_min     - Minimum tolerated metric magnitude
1289cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max     - Maximum tolerated metric magnitude
1290cb7bfe8cSJoe Wallwork - -dm_plex_metric_a_max     - Maximum tolerated anisotropy
1291cb7bfe8cSJoe Wallwork 
129220282da2SJoe Wallwork .seealso: DMPlexMetricNormalize(), DMPlexMetricIntersection()
1293cb7bfe8cSJoe Wallwork @*/
12943f07679eSJoe Wallwork PetscErrorCode DMPlexMetricEnforceSPD(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut, Vec *determinant)
129520282da2SJoe Wallwork {
12963f07679eSJoe Wallwork   DM             dmDet;
129793520041SJoe Wallwork   PetscBool      isotropic, uniform;
129820282da2SJoe Wallwork   PetscErrorCode ierr;
129920282da2SJoe Wallwork   PetscInt       dim, vStart, vEnd, v;
13003f07679eSJoe Wallwork   PetscScalar   *met, *det;
130120282da2SJoe Wallwork   PetscReal      h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0;
130220282da2SJoe Wallwork 
130320282da2SJoe Wallwork   PetscFunctionBegin;
1304fe902aceSJoe Wallwork   ierr = PetscLogEventBegin(DMPLEX_MetricEnforceSPD,0,0,0,0);CHKERRQ(ierr);
130520282da2SJoe Wallwork 
130620282da2SJoe Wallwork   /* Extract metadata from dm */
130720282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
130820282da2SJoe Wallwork   if (restrictSizes) {
130999abec2bSJoe Wallwork     ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr);
131099abec2bSJoe Wallwork     ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr);
131199abec2bSJoe Wallwork     h_min = PetscMax(h_min, 1.0e-30);
131299abec2bSJoe Wallwork     h_max = PetscMin(h_max, 1.0e+30);
131354c59aa7SJacob Faibussowitsch     PetscCheck(h_min < h_max,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max);
131499abec2bSJoe Wallwork   }
131599abec2bSJoe Wallwork   if (restrictAnisotropy) {
131699abec2bSJoe Wallwork     ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr);
131799abec2bSJoe Wallwork     a_max = PetscMin(a_max, 1.0e+30);
131820282da2SJoe Wallwork   }
131920282da2SJoe Wallwork 
132093520041SJoe Wallwork   /* Setup output metric */
13213f07679eSJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr);
13223f07679eSJoe Wallwork   ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr);
132393520041SJoe Wallwork 
132493520041SJoe Wallwork   /* Enforce SPD and extract determinant */
132593520041SJoe Wallwork   ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr);
132693520041SJoe Wallwork   ierr = DMPlexMetricIsUniform(dm, &uniform);CHKERRQ(ierr);
132793520041SJoe Wallwork   ierr = DMPlexMetricIsIsotropic(dm, &isotropic);CHKERRQ(ierr);
132893520041SJoe Wallwork   if (uniform) {
1329d1a5b989SMatthew G. Knepley     PetscCheck(isotropic, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform anisotropic metrics cannot exist");
133093520041SJoe Wallwork 
133193520041SJoe Wallwork     /* Uniform case */
133293520041SJoe Wallwork     ierr = VecDuplicate(metricIn, determinant);CHKERRQ(ierr);
133393520041SJoe Wallwork     ierr = VecGetArray(*determinant, &det);CHKERRQ(ierr);
133493520041SJoe Wallwork     ierr = DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det);CHKERRQ(ierr);
133593520041SJoe Wallwork     ierr = VecRestoreArray(*determinant, &det);CHKERRQ(ierr);
133693520041SJoe Wallwork   } else {
133793520041SJoe Wallwork 
133893520041SJoe Wallwork     /* Spatially varying case */
133993520041SJoe Wallwork     PetscInt nrow;
134093520041SJoe Wallwork 
134193520041SJoe Wallwork     if (isotropic) nrow = 1;
134293520041SJoe Wallwork     else nrow = dim;
13433f07679eSJoe Wallwork     ierr = DMClone(dm, &dmDet);CHKERRQ(ierr);
13443f07679eSJoe Wallwork     ierr = DMPlexP1FieldCreate_Private(dmDet, 0, 1, determinant);CHKERRQ(ierr);
134520282da2SJoe Wallwork     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
13463f07679eSJoe Wallwork     ierr = VecGetArray(*determinant, &det);CHKERRQ(ierr);
134720282da2SJoe Wallwork     for (v = vStart; v < vEnd; ++v) {
13483f07679eSJoe Wallwork       PetscScalar *vmet, *vdet;
134920282da2SJoe Wallwork       ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr);
13503f07679eSJoe Wallwork       ierr = DMPlexPointLocalRef(dmDet, v, det, &vdet);CHKERRQ(ierr);
135193520041SJoe Wallwork       ierr = DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, vmet, vdet);CHKERRQ(ierr);
135220282da2SJoe Wallwork     }
13533f07679eSJoe Wallwork     ierr = VecRestoreArray(*determinant, &det);CHKERRQ(ierr);
135493520041SJoe Wallwork   }
13553f07679eSJoe Wallwork   ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr);
1356fe902aceSJoe Wallwork 
1357fe902aceSJoe Wallwork   ierr = PetscLogEventEnd(DMPLEX_MetricEnforceSPD,0,0,0,0);CHKERRQ(ierr);
135820282da2SJoe Wallwork   PetscFunctionReturn(0);
135920282da2SJoe Wallwork }
136020282da2SJoe Wallwork 
136120282da2SJoe Wallwork static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
136220282da2SJoe Wallwork                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
136320282da2SJoe Wallwork                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
136420282da2SJoe Wallwork                      PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
136520282da2SJoe Wallwork {
136620282da2SJoe Wallwork   const PetscScalar p = constants[0];
136720282da2SJoe Wallwork 
13683f07679eSJoe Wallwork   f0[0] = PetscPowReal(u[0], p/(2.0*p + dim));
136920282da2SJoe Wallwork }
137020282da2SJoe Wallwork 
1371cb7bfe8cSJoe Wallwork /*@
137220282da2SJoe Wallwork   DMPlexMetricNormalize - Apply L-p normalization to a metric
137320282da2SJoe Wallwork 
137420282da2SJoe Wallwork   Input parameters:
137520282da2SJoe Wallwork + dm                 - The DM
137620282da2SJoe Wallwork . metricIn           - The unnormalized metric
137716522936SJoe Wallwork . restrictSizes      - Should maximum/minimum metric magnitudes be enforced?
137816522936SJoe Wallwork - restrictAnisotropy - Should maximum metric anisotropy be enforced?
137920282da2SJoe Wallwork 
138020282da2SJoe Wallwork   Output parameter:
138120282da2SJoe Wallwork . metricOut          - The normalized metric
138220282da2SJoe Wallwork 
138320282da2SJoe Wallwork   Level: beginner
138420282da2SJoe Wallwork 
1385cb7bfe8cSJoe Wallwork   Notes:
1386cb7bfe8cSJoe Wallwork 
1387cb7bfe8cSJoe Wallwork   Relevant command line options:
1388cb7bfe8cSJoe Wallwork 
138993520041SJoe Wallwork + -dm_plex_metric_isotropic                 - Is the metric isotropic?
139093520041SJoe Wallwork . -dm_plex_metric_uniform                   - Is the metric uniform?
139193520041SJoe Wallwork . -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization?
1392cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_min                     - Minimum tolerated metric magnitude
1393cb7bfe8cSJoe Wallwork . -dm_plex_metric_h_max                     - Maximum tolerated metric magnitude
1394cb7bfe8cSJoe Wallwork . -dm_plex_metric_a_max                     - Maximum tolerated anisotropy
1395cb7bfe8cSJoe Wallwork . -dm_plex_metric_p                         - L-p normalization order
1396cb7bfe8cSJoe Wallwork - -dm_plex_metric_target_complexity         - Target metric complexity
1397cb7bfe8cSJoe Wallwork 
139820282da2SJoe Wallwork .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection()
1399cb7bfe8cSJoe Wallwork @*/
140016522936SJoe Wallwork PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut)
140120282da2SJoe Wallwork {
14023f07679eSJoe Wallwork   DM               dmDet;
140320282da2SJoe Wallwork   MPI_Comm         comm;
140493520041SJoe Wallwork   PetscBool        restrictAnisotropyFirst, isotropic, uniform;
140520282da2SJoe Wallwork   PetscDS          ds;
140620282da2SJoe Wallwork   PetscErrorCode   ierr;
140720282da2SJoe Wallwork   PetscInt         dim, Nd, vStart, vEnd, v, i;
14083f07679eSJoe Wallwork   PetscScalar     *met, *det, integral, constants[1];
140993520041SJoe Wallwork   PetscReal        p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, fact, target, realIntegral;
14103f07679eSJoe Wallwork   Vec              determinant;
141120282da2SJoe Wallwork 
141220282da2SJoe Wallwork   PetscFunctionBegin;
1413fe902aceSJoe Wallwork   ierr = PetscLogEventBegin(DMPLEX_MetricNormalize,0,0,0,0);CHKERRQ(ierr);
141420282da2SJoe Wallwork 
141520282da2SJoe Wallwork   /* Extract metadata from dm */
141620282da2SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
141720282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
141893520041SJoe Wallwork   ierr = DMPlexMetricIsUniform(dm, &uniform);CHKERRQ(ierr);
141993520041SJoe Wallwork   ierr = DMPlexMetricIsIsotropic(dm, &isotropic);CHKERRQ(ierr);
142093520041SJoe Wallwork   if (isotropic) Nd = 1;
142193520041SJoe Wallwork   else Nd = dim*dim;
142220282da2SJoe Wallwork 
142320282da2SJoe Wallwork   /* Set up metric and ensure it is SPD */
142416522936SJoe Wallwork   ierr = DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst);CHKERRQ(ierr);
14253f07679eSJoe Wallwork   ierr = DMPlexMetricEnforceSPD(dm, metricIn, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), metricOut, &determinant);CHKERRQ(ierr);
142620282da2SJoe Wallwork 
142720282da2SJoe Wallwork   /* Compute global normalization factor */
142816522936SJoe Wallwork   ierr = DMPlexMetricGetTargetComplexity(dm, &target);CHKERRQ(ierr);
142916522936SJoe Wallwork   ierr = DMPlexMetricGetNormalizationOrder(dm, &p);CHKERRQ(ierr);
143016522936SJoe Wallwork   constants[0] = p;
143193520041SJoe Wallwork   if (uniform) {
14322c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!isotropic,comm, PETSC_ERR_ARG_WRONG, "Uniform anisotropic metrics not supported");
143393520041SJoe Wallwork     DM  dmTmp;
143493520041SJoe Wallwork     Vec tmp;
143593520041SJoe Wallwork 
143693520041SJoe Wallwork     ierr = DMClone(dm, &dmTmp);CHKERRQ(ierr);
143793520041SJoe Wallwork     ierr = DMPlexP1FieldCreate_Private(dmTmp, 0, 1, &tmp);CHKERRQ(ierr);
143893520041SJoe Wallwork     ierr = VecGetArray(determinant, &det);CHKERRQ(ierr);
143993520041SJoe Wallwork     ierr = VecSet(tmp, det[0]);CHKERRQ(ierr);
144093520041SJoe Wallwork     ierr = VecRestoreArray(determinant, &det);CHKERRQ(ierr);
144193520041SJoe Wallwork     ierr = DMGetDS(dmTmp, &ds);CHKERRQ(ierr);
144293520041SJoe Wallwork     ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr);
144393520041SJoe Wallwork     ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr);
144493520041SJoe Wallwork     ierr = DMPlexComputeIntegralFEM(dmTmp, tmp, &integral, NULL);CHKERRQ(ierr);
144593520041SJoe Wallwork     ierr = VecDestroy(&tmp);CHKERRQ(ierr);
144693520041SJoe Wallwork     ierr = DMDestroy(&dmTmp);CHKERRQ(ierr);
144793520041SJoe Wallwork   } else {
14483f07679eSJoe Wallwork     ierr = VecGetDM(determinant, &dmDet);CHKERRQ(ierr);
14493f07679eSJoe Wallwork     ierr = DMGetDS(dmDet, &ds);CHKERRQ(ierr);
145020282da2SJoe Wallwork     ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr);
145120282da2SJoe Wallwork     ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr);
14523f07679eSJoe Wallwork     ierr = DMPlexComputeIntegralFEM(dmDet, determinant, &integral, NULL);CHKERRQ(ierr);
145393520041SJoe Wallwork   }
14543f07679eSJoe Wallwork   realIntegral = PetscRealPart(integral);
14552c71b3e2SJacob Faibussowitsch   PetscCheckFalse(realIntegral < 1.0e-30,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global metric normalization factor should be strictly positive, not %.4e Is the input metric positive-definite?", realIntegral);
14563f07679eSJoe Wallwork   factGlob = PetscPowReal(target/realIntegral, 2.0/dim);
145720282da2SJoe Wallwork 
145820282da2SJoe Wallwork   /* Apply local scaling */
145920282da2SJoe Wallwork   if (restrictSizes) {
146016522936SJoe Wallwork     ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr);
146116522936SJoe Wallwork     ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr);
146216522936SJoe Wallwork     h_min = PetscMax(h_min, 1.0e-30);
146316522936SJoe Wallwork     h_max = PetscMin(h_max, 1.0e+30);
14642c71b3e2SJacob Faibussowitsch     PetscCheckFalse(h_min >= h_max,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max);
146516522936SJoe Wallwork   }
146616522936SJoe Wallwork   if (restrictAnisotropy && !restrictAnisotropyFirst) {
146716522936SJoe Wallwork     ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr);
146816522936SJoe Wallwork     a_max = PetscMin(a_max, 1.0e+30);
146920282da2SJoe Wallwork   }
147020282da2SJoe Wallwork   ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr);
14713f07679eSJoe Wallwork   ierr = VecGetArray(determinant, &det);CHKERRQ(ierr);
147293520041SJoe Wallwork   if (uniform) {
147393520041SJoe Wallwork 
147493520041SJoe Wallwork     /* Uniform case */
147593520041SJoe Wallwork     met[0] *= factGlob * PetscPowReal(PetscAbsScalar(det[0]), -1.0/(2*p+dim));
147693520041SJoe Wallwork     if (restrictSizes) { ierr = DMPlexMetricModify_Private(1, h_min, h_max, a_max, met, det);CHKERRQ(ierr); }
147793520041SJoe Wallwork   } else {
147893520041SJoe Wallwork 
147993520041SJoe Wallwork     /* Spatially varying case */
148093520041SJoe Wallwork     PetscInt nrow;
148193520041SJoe Wallwork 
148293520041SJoe Wallwork     if (isotropic) nrow = 1;
148393520041SJoe Wallwork     else nrow = dim;
148416522936SJoe Wallwork     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
148520282da2SJoe Wallwork     for (v = vStart; v < vEnd; ++v) {
14863f07679eSJoe Wallwork       PetscScalar *Mp, *detM;
148720282da2SJoe Wallwork 
148820282da2SJoe Wallwork       ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr);
14893f07679eSJoe Wallwork       ierr = DMPlexPointLocalRef(dmDet, v, det, &detM);CHKERRQ(ierr);
14903f07679eSJoe Wallwork       fact = factGlob * PetscPowReal(PetscAbsScalar(detM[0]), -1.0/(2*p+dim));
149120282da2SJoe Wallwork       for (i = 0; i < Nd; ++i) Mp[i] *= fact;
149293520041SJoe Wallwork       if (restrictSizes) { ierr = DMPlexMetricModify_Private(nrow, h_min, h_max, a_max, Mp, detM);CHKERRQ(ierr); }
149393520041SJoe Wallwork     }
149420282da2SJoe Wallwork   }
14953f07679eSJoe Wallwork   ierr = VecRestoreArray(determinant, &det);CHKERRQ(ierr);
149620282da2SJoe Wallwork   ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr);
14973f07679eSJoe Wallwork   ierr = VecDestroy(&determinant);CHKERRQ(ierr);
149893520041SJoe Wallwork   if (!uniform) { ierr = DMDestroy(&dmDet);CHKERRQ(ierr); }
149920282da2SJoe Wallwork 
1500fe902aceSJoe Wallwork   ierr = PetscLogEventEnd(DMPLEX_MetricNormalize,0,0,0,0);CHKERRQ(ierr);
150120282da2SJoe Wallwork   PetscFunctionReturn(0);
150220282da2SJoe Wallwork }
150320282da2SJoe Wallwork 
1504cb7bfe8cSJoe Wallwork /*@
150520282da2SJoe Wallwork   DMPlexMetricAverage - Compute the average of a list of metrics
150620282da2SJoe Wallwork 
1507f1a722f8SMatthew G. Knepley   Input Parameters:
150820282da2SJoe Wallwork + dm         - The DM
150920282da2SJoe Wallwork . numMetrics - The number of metrics to be averaged
151020282da2SJoe Wallwork . weights    - Weights for the average
151120282da2SJoe Wallwork - metrics    - The metrics to be averaged
151220282da2SJoe Wallwork 
151320282da2SJoe Wallwork   Output Parameter:
151420282da2SJoe Wallwork . metricAvg  - The averaged metric
151520282da2SJoe Wallwork 
151620282da2SJoe Wallwork   Level: beginner
151720282da2SJoe Wallwork 
151820282da2SJoe Wallwork   Notes:
151920282da2SJoe Wallwork   The weights should sum to unity.
152020282da2SJoe Wallwork 
152120282da2SJoe Wallwork   If weights are not provided then an unweighted average is used.
152220282da2SJoe Wallwork 
152320282da2SJoe Wallwork .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection()
1524cb7bfe8cSJoe Wallwork @*/
152520282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg)
152620282da2SJoe Wallwork {
152720282da2SJoe Wallwork   PetscBool      haveWeights = PETSC_TRUE;
152820282da2SJoe Wallwork   PetscErrorCode ierr;
152993520041SJoe Wallwork   PetscInt       i, m, n;
153020282da2SJoe Wallwork   PetscReal      sum = 0.0, tol = 1.0e-10;
153120282da2SJoe Wallwork 
153220282da2SJoe Wallwork   PetscFunctionBegin;
1533fe902aceSJoe Wallwork   ierr = PetscLogEventBegin(DMPLEX_MetricAverage,0,0,0,0);CHKERRQ(ierr);
15342c71b3e2SJacob Faibussowitsch   PetscCheck(numMetrics >= 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics);
153520282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr);
153620282da2SJoe Wallwork   ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr);
153793520041SJoe Wallwork   ierr = VecGetSize(*metricAvg, &m);CHKERRQ(ierr);
153893520041SJoe Wallwork   for (i = 0; i < numMetrics; ++i) {
153993520041SJoe Wallwork     ierr = VecGetSize(metrics[i], &n);CHKERRQ(ierr);
15402c71b3e2SJacob Faibussowitsch     PetscCheckFalse(m != n,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Averaging different metric types not implemented");
154193520041SJoe Wallwork   }
154220282da2SJoe Wallwork 
154320282da2SJoe Wallwork   /* Default to the unweighted case */
154420282da2SJoe Wallwork   if (!weights) {
154520282da2SJoe Wallwork     ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr);
154620282da2SJoe Wallwork     haveWeights = PETSC_FALSE;
154720282da2SJoe Wallwork     for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; }
154820282da2SJoe Wallwork   }
154920282da2SJoe Wallwork 
155020282da2SJoe Wallwork   /* Check weights sum to unity */
155193520041SJoe Wallwork   for (i = 0; i < numMetrics; ++i) sum += weights[i];
15522c71b3e2SJacob Faibussowitsch   PetscCheckFalse(PetscAbsReal(sum - 1) > tol,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity");
155320282da2SJoe Wallwork 
155420282da2SJoe Wallwork   /* Compute metric average */
155520282da2SJoe Wallwork   for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); }
155620282da2SJoe Wallwork   if (!haveWeights) { ierr = PetscFree(weights); }
1557fe902aceSJoe Wallwork 
1558fe902aceSJoe Wallwork   ierr = PetscLogEventEnd(DMPLEX_MetricAverage,0,0,0,0);CHKERRQ(ierr);
155920282da2SJoe Wallwork   PetscFunctionReturn(0);
156020282da2SJoe Wallwork }
156120282da2SJoe Wallwork 
1562cb7bfe8cSJoe Wallwork /*@
156320282da2SJoe Wallwork   DMPlexMetricAverage2 - Compute the unweighted average of two metrics
156420282da2SJoe Wallwork 
1565f1a722f8SMatthew G. Knepley   Input Parameters:
156620282da2SJoe Wallwork + dm         - The DM
156720282da2SJoe Wallwork . metric1    - The first metric to be averaged
156820282da2SJoe Wallwork - metric2    - The second metric to be averaged
156920282da2SJoe Wallwork 
157020282da2SJoe Wallwork   Output Parameter:
157120282da2SJoe Wallwork . metricAvg  - The averaged metric
157220282da2SJoe Wallwork 
157320282da2SJoe Wallwork   Level: beginner
157420282da2SJoe Wallwork 
157520282da2SJoe Wallwork .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3()
1576cb7bfe8cSJoe Wallwork @*/
157720282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg)
157820282da2SJoe Wallwork {
157920282da2SJoe Wallwork   PetscErrorCode ierr;
158020282da2SJoe Wallwork   PetscReal      weights[2] = {0.5, 0.5};
158120282da2SJoe Wallwork   Vec            metrics[2] = {metric1, metric2};
158220282da2SJoe Wallwork 
158320282da2SJoe Wallwork   PetscFunctionBegin;
158420282da2SJoe Wallwork   ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr);
158520282da2SJoe Wallwork   PetscFunctionReturn(0);
158620282da2SJoe Wallwork }
158720282da2SJoe Wallwork 
1588cb7bfe8cSJoe Wallwork /*@
158920282da2SJoe Wallwork   DMPlexMetricAverage3 - Compute the unweighted average of three metrics
159020282da2SJoe Wallwork 
1591f1a722f8SMatthew G. Knepley   Input Parameters:
159220282da2SJoe Wallwork + dm         - The DM
159320282da2SJoe Wallwork . metric1    - The first metric to be averaged
159420282da2SJoe Wallwork . metric2    - The second metric to be averaged
159520282da2SJoe Wallwork - metric3    - The third metric to be averaged
159620282da2SJoe Wallwork 
159720282da2SJoe Wallwork   Output Parameter:
159820282da2SJoe Wallwork . metricAvg  - The averaged metric
159920282da2SJoe Wallwork 
160020282da2SJoe Wallwork   Level: beginner
160120282da2SJoe Wallwork 
160220282da2SJoe Wallwork .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2()
1603cb7bfe8cSJoe Wallwork @*/
160420282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg)
160520282da2SJoe Wallwork {
160620282da2SJoe Wallwork   PetscErrorCode ierr;
160720282da2SJoe Wallwork   PetscReal      weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0};
160820282da2SJoe Wallwork   Vec            metrics[3] = {metric1, metric2, metric3};
160920282da2SJoe Wallwork 
161020282da2SJoe Wallwork   PetscFunctionBegin;
161120282da2SJoe Wallwork   ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr);
161220282da2SJoe Wallwork   PetscFunctionReturn(0);
161320282da2SJoe Wallwork }
161420282da2SJoe Wallwork 
161520282da2SJoe Wallwork static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[])
161620282da2SJoe Wallwork {
161720282da2SJoe Wallwork   PetscErrorCode ierr;
161820282da2SJoe Wallwork   PetscInt       i, j, k, l, m;
161920282da2SJoe Wallwork   PetscReal     *evals, *evals1;
162020282da2SJoe Wallwork   PetscScalar   *evecs, *sqrtM1, *isqrtM1;
162120282da2SJoe Wallwork 
162220282da2SJoe Wallwork   PetscFunctionBegin;
162393520041SJoe Wallwork 
162493520041SJoe Wallwork   /* Isotropic case */
162593520041SJoe Wallwork   if (dim == 1) {
162693520041SJoe Wallwork     M2[0] = (PetscScalar)PetscMin(PetscRealPart(M1[0]), PetscRealPart(M2[0]));
162793520041SJoe Wallwork     PetscFunctionReturn(0);
162893520041SJoe Wallwork   }
162993520041SJoe Wallwork 
163093520041SJoe Wallwork   /* Anisotropic case */
163120282da2SJoe Wallwork   ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr);
163220282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
163320282da2SJoe Wallwork     for (j = 0; j < dim; ++j) {
163420282da2SJoe Wallwork       evecs[i*dim+j] = M1[i*dim+j];
163520282da2SJoe Wallwork     }
163620282da2SJoe Wallwork   }
163720282da2SJoe Wallwork   {
163820282da2SJoe Wallwork     PetscScalar *work;
163920282da2SJoe Wallwork     PetscBLASInt lwork;
164020282da2SJoe Wallwork 
164120282da2SJoe Wallwork     lwork = 5*dim;
164220282da2SJoe Wallwork     ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr);
164320282da2SJoe Wallwork     {
164420282da2SJoe Wallwork       PetscBLASInt lierr, nb;
164520282da2SJoe Wallwork       PetscReal    sqrtk;
164620282da2SJoe Wallwork 
164720282da2SJoe Wallwork       /* Compute eigendecomposition of M1 */
164820282da2SJoe Wallwork       ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr);
164920282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
165020282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
165120282da2SJoe Wallwork       {
165220282da2SJoe Wallwork         PetscReal *rwork;
165320282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
165420282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr));
165520282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
165620282da2SJoe Wallwork       }
165720282da2SJoe Wallwork #else
165820282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr));
165920282da2SJoe Wallwork #endif
166082490253SJoe Wallwork       if (lierr) {
166182490253SJoe Wallwork         LAPACKsyevFail(dim, M1);
166298921bdaSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
166382490253SJoe Wallwork       }
166420282da2SJoe Wallwork       ierr = PetscFPTrapPop();
166520282da2SJoe Wallwork 
166620282da2SJoe Wallwork       /* Compute square root and reciprocal */
166720282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
166820282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
166920282da2SJoe Wallwork           sqrtM1[i*dim+j] = 0.0;
167020282da2SJoe Wallwork           isqrtM1[i*dim+j] = 0.0;
167120282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
167220282da2SJoe Wallwork             sqrtk = PetscSqrtReal(evals1[k]);
167320282da2SJoe Wallwork             sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j];
167420282da2SJoe Wallwork             isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j];
167520282da2SJoe Wallwork           }
167620282da2SJoe Wallwork         }
167720282da2SJoe Wallwork       }
167820282da2SJoe Wallwork 
167920282da2SJoe Wallwork       /* Map into the space spanned by the eigenvectors of M1 */
168020282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
168120282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
168220282da2SJoe Wallwork           evecs[i*dim+j] = 0.0;
168320282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
168420282da2SJoe Wallwork             for (l = 0; l < dim; ++l) {
168520282da2SJoe Wallwork               evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l];
168620282da2SJoe Wallwork             }
168720282da2SJoe Wallwork           }
168820282da2SJoe Wallwork         }
168920282da2SJoe Wallwork       }
169020282da2SJoe Wallwork 
169120282da2SJoe Wallwork       /* Compute eigendecomposition */
169220282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
169320282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
169420282da2SJoe Wallwork       {
169520282da2SJoe Wallwork         PetscReal *rwork;
169620282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
169720282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr));
169820282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
169920282da2SJoe Wallwork       }
170020282da2SJoe Wallwork #else
170120282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr));
170220282da2SJoe Wallwork #endif
170382490253SJoe Wallwork       if (lierr) {
170482490253SJoe Wallwork         for (i = 0; i < dim; ++i) {
170582490253SJoe Wallwork           for (j = 0; j < dim; ++j) {
170682490253SJoe Wallwork             evecs[i*dim+j] = 0.0;
170782490253SJoe Wallwork             for (k = 0; k < dim; ++k) {
170882490253SJoe Wallwork               for (l = 0; l < dim; ++l) {
170982490253SJoe Wallwork                 evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l];
171082490253SJoe Wallwork               }
171182490253SJoe Wallwork             }
171282490253SJoe Wallwork           }
171382490253SJoe Wallwork         }
171482490253SJoe Wallwork         LAPACKsyevFail(dim, evecs);
171598921bdaSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
171682490253SJoe Wallwork       }
171720282da2SJoe Wallwork       ierr = PetscFPTrapPop();
171820282da2SJoe Wallwork 
171920282da2SJoe Wallwork       /* Modify eigenvalues */
172020282da2SJoe Wallwork       for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]);
172120282da2SJoe Wallwork 
172220282da2SJoe Wallwork       /* Map back to get the intersection */
172320282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
172420282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
172520282da2SJoe Wallwork           M2[i*dim+j] = 0.0;
172620282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
172720282da2SJoe Wallwork             for (l = 0; l < dim; ++l) {
172820282da2SJoe Wallwork               for (m = 0; m < dim; ++m) {
172920282da2SJoe Wallwork                 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m];
173020282da2SJoe Wallwork               }
173120282da2SJoe Wallwork             }
173220282da2SJoe Wallwork           }
173320282da2SJoe Wallwork         }
173420282da2SJoe Wallwork       }
173520282da2SJoe Wallwork     }
173620282da2SJoe Wallwork     ierr = PetscFree(work);CHKERRQ(ierr);
173720282da2SJoe Wallwork   }
173820282da2SJoe Wallwork   ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr);
173920282da2SJoe Wallwork   PetscFunctionReturn(0);
174020282da2SJoe Wallwork }
174120282da2SJoe Wallwork 
1742cb7bfe8cSJoe Wallwork /*@
174320282da2SJoe Wallwork   DMPlexMetricIntersection - Compute the intersection of a list of metrics
174420282da2SJoe Wallwork 
1745f1a722f8SMatthew G. Knepley   Input Parameters:
174620282da2SJoe Wallwork + dm         - The DM
174720282da2SJoe Wallwork . numMetrics - The number of metrics to be intersected
174820282da2SJoe Wallwork - metrics    - The metrics to be intersected
174920282da2SJoe Wallwork 
175020282da2SJoe Wallwork   Output Parameter:
175120282da2SJoe Wallwork . metricInt  - The intersected metric
175220282da2SJoe Wallwork 
175320282da2SJoe Wallwork   Level: beginner
175420282da2SJoe Wallwork 
175520282da2SJoe Wallwork   Notes:
175620282da2SJoe Wallwork 
175720282da2SJoe Wallwork   The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics.
175820282da2SJoe Wallwork 
175920282da2SJoe Wallwork   The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2.
176020282da2SJoe Wallwork 
176120282da2SJoe Wallwork .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage()
1762cb7bfe8cSJoe Wallwork @*/
176320282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt)
176420282da2SJoe Wallwork {
176593520041SJoe Wallwork   PetscBool      isotropic, uniform;
176620282da2SJoe Wallwork   PetscErrorCode ierr;
176793520041SJoe Wallwork   PetscInt       v, i, m, n;
176893520041SJoe Wallwork   PetscScalar   *met, *meti;
176920282da2SJoe Wallwork 
177020282da2SJoe Wallwork   PetscFunctionBegin;
1771fe902aceSJoe Wallwork   ierr = PetscLogEventBegin(DMPLEX_MetricIntersection,0,0,0,0);CHKERRQ(ierr);
17722c71b3e2SJacob Faibussowitsch   PetscCheck(numMetrics >= 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics);
177320282da2SJoe Wallwork 
177420282da2SJoe Wallwork   /* Copy over the first metric */
177593520041SJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr);
177620282da2SJoe Wallwork   ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr);
177793520041SJoe Wallwork   if (numMetrics == 1) PetscFunctionReturn(0);
177893520041SJoe Wallwork   ierr = VecGetSize(*metricInt, &m);CHKERRQ(ierr);
177993520041SJoe Wallwork   for (i = 0; i < numMetrics; ++i) {
178093520041SJoe Wallwork     ierr = VecGetSize(metrics[i], &n);CHKERRQ(ierr);
17812c71b3e2SJacob Faibussowitsch     PetscCheckFalse(m != n,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Intersecting different metric types not implemented");
178293520041SJoe Wallwork   }
178320282da2SJoe Wallwork 
178420282da2SJoe Wallwork   /* Intersect subsequent metrics in turn */
178593520041SJoe Wallwork   ierr = DMPlexMetricIsUniform(dm, &uniform);CHKERRQ(ierr);
178693520041SJoe Wallwork   ierr = DMPlexMetricIsIsotropic(dm, &isotropic);CHKERRQ(ierr);
178793520041SJoe Wallwork   if (uniform) {
178893520041SJoe Wallwork 
178993520041SJoe Wallwork     /* Uniform case */
179093520041SJoe Wallwork     ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr);
179193520041SJoe Wallwork     for (i = 1; i < numMetrics; ++i) {
179293520041SJoe Wallwork       ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr);
179393520041SJoe Wallwork       ierr = DMPlexMetricIntersection_Private(1, meti, met);CHKERRQ(ierr);
179493520041SJoe Wallwork       ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr);
179593520041SJoe Wallwork     }
179693520041SJoe Wallwork     ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr);
179793520041SJoe Wallwork   } else {
179893520041SJoe Wallwork 
179993520041SJoe Wallwork     /* Spatially varying case */
180093520041SJoe Wallwork     PetscInt     dim, vStart, vEnd, nrow;
180193520041SJoe Wallwork     PetscScalar *M, *Mi;
180293520041SJoe Wallwork 
180393520041SJoe Wallwork     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
180493520041SJoe Wallwork     if (isotropic) nrow = 1;
180593520041SJoe Wallwork     else nrow = dim;
180693520041SJoe Wallwork     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
180720282da2SJoe Wallwork     ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr);
180820282da2SJoe Wallwork     for (i = 1; i < numMetrics; ++i) {
180920282da2SJoe Wallwork       ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr);
181020282da2SJoe Wallwork       for (v = vStart; v < vEnd; ++v) {
181120282da2SJoe Wallwork         ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr);
181220282da2SJoe Wallwork         ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr);
181393520041SJoe Wallwork         ierr = DMPlexMetricIntersection_Private(nrow, Mi, M);CHKERRQ(ierr);
181420282da2SJoe Wallwork       }
181520282da2SJoe Wallwork       ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr);
181620282da2SJoe Wallwork     }
181720282da2SJoe Wallwork     ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr);
181820282da2SJoe Wallwork   }
1819fe902aceSJoe Wallwork 
1820fe902aceSJoe Wallwork   ierr = PetscLogEventEnd(DMPLEX_MetricIntersection,0,0,0,0);CHKERRQ(ierr);
182120282da2SJoe Wallwork   PetscFunctionReturn(0);
182220282da2SJoe Wallwork }
182320282da2SJoe Wallwork 
1824cb7bfe8cSJoe Wallwork /*@
182520282da2SJoe Wallwork   DMPlexMetricIntersection2 - Compute the intersection of two metrics
182620282da2SJoe Wallwork 
1827f1a722f8SMatthew G. Knepley   Input Parameters:
182820282da2SJoe Wallwork + dm        - The DM
182920282da2SJoe Wallwork . metric1   - The first metric to be intersected
183020282da2SJoe Wallwork - metric2   - The second metric to be intersected
183120282da2SJoe Wallwork 
183220282da2SJoe Wallwork   Output Parameter:
183320282da2SJoe Wallwork . metricInt - The intersected metric
183420282da2SJoe Wallwork 
183520282da2SJoe Wallwork   Level: beginner
183620282da2SJoe Wallwork 
183720282da2SJoe Wallwork .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3()
1838cb7bfe8cSJoe Wallwork @*/
183920282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt)
184020282da2SJoe Wallwork {
184120282da2SJoe Wallwork   PetscErrorCode ierr;
184220282da2SJoe Wallwork   Vec            metrics[2] = {metric1, metric2};
184320282da2SJoe Wallwork 
184420282da2SJoe Wallwork   PetscFunctionBegin;
184520282da2SJoe Wallwork   ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr);
184620282da2SJoe Wallwork   PetscFunctionReturn(0);
184720282da2SJoe Wallwork }
184820282da2SJoe Wallwork 
1849cb7bfe8cSJoe Wallwork /*@
185020282da2SJoe Wallwork   DMPlexMetricIntersection3 - Compute the intersection of three metrics
185120282da2SJoe Wallwork 
1852f1a722f8SMatthew G. Knepley   Input Parameters:
185320282da2SJoe Wallwork + dm        - The DM
185420282da2SJoe Wallwork . metric1   - The first metric to be intersected
185520282da2SJoe Wallwork . metric2   - The second metric to be intersected
185620282da2SJoe Wallwork - metric3   - The third metric to be intersected
185720282da2SJoe Wallwork 
185820282da2SJoe Wallwork   Output Parameter:
185920282da2SJoe Wallwork . metricInt - The intersected metric
186020282da2SJoe Wallwork 
186120282da2SJoe Wallwork   Level: beginner
186220282da2SJoe Wallwork 
186320282da2SJoe Wallwork .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2()
1864cb7bfe8cSJoe Wallwork @*/
186520282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt)
186620282da2SJoe Wallwork {
186720282da2SJoe Wallwork   PetscErrorCode ierr;
186820282da2SJoe Wallwork   Vec            metrics[3] = {metric1, metric2, metric3};
186920282da2SJoe Wallwork 
187020282da2SJoe Wallwork   PetscFunctionBegin;
187120282da2SJoe Wallwork   ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr);
187220282da2SJoe Wallwork   PetscFunctionReturn(0);
187320282da2SJoe Wallwork }
1874