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