xref: /petsc/src/dm/impls/plex/plexmetric.c (revision cc2eee551e05fb75136b6c9fcd8fc2bcfdb44367)
120282da2SJoe Wallwork #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
220282da2SJoe Wallwork #include <petscblaslapack.h>
320282da2SJoe Wallwork 
431b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetFromOptions(DM dm)
531b70465SJoe Wallwork {
631b70465SJoe Wallwork   MPI_Comm       comm;
731b70465SJoe Wallwork   PetscBool      isotropic = PETSC_FALSE, restrictAnisotropyFirst = PETSC_FALSE;
8*cc2eee55SJoe Wallwork   PetscBool      noInsert = PETSC_FALSE, noSwap = PETSC_FALSE, noMove = PETSC_FALSE;
931b70465SJoe Wallwork   PetscErrorCode ierr;
10*cc2eee55SJoe Wallwork   PetscInt       verbosity = -1, numIter = 3;
11*cc2eee55SJoe 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;
1231b70465SJoe Wallwork 
1331b70465SJoe Wallwork   PetscFunctionBegin;
1431b70465SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1531b70465SJoe Wallwork   ierr = PetscOptionsBegin(comm, "", "Riemannian metric options", "DMPlexMetric");CHKERRQ(ierr);
1631b70465SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_isotropic", "Is the metric isotropic?", "DMPlexMetricCreateIsotropic", isotropic, &isotropic, NULL);CHKERRQ(ierr);
17*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetIsotropic(dm, isotropic);CHKERRQ(ierr);
1831b70465SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_restrict_anisotropy_first", "Should anisotropy be restricted before normalization?", "DMPlexNormalize", restrictAnisotropyFirst, &restrictAnisotropyFirst, NULL);CHKERRQ(ierr);
19*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetRestrictAnisotropyFirst(dm, restrictAnisotropyFirst);CHKERRQ(ierr);
20*cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_insert", "Turn off node insertion and deletion", "DMAdaptMetric", noInsert, &noInsert, NULL);CHKERRQ(ierr);
21*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoInsertion(dm, noInsert);CHKERRQ(ierr);
22*cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_swap", "Turn off facet swapping", "DMAdaptMetric", noSwap, &noSwap, NULL);CHKERRQ(ierr);
23*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoSwapping(dm, noSwap);CHKERRQ(ierr);
24*cc2eee55SJoe Wallwork   ierr = PetscOptionsBool("-dm_plex_metric_no_move", "Turn off facet node movement", "DMAdaptMetric", noMove, &noMove, NULL);CHKERRQ(ierr);
25*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNoMovement(dm, noMove);CHKERRQ(ierr);
26*cc2eee55SJoe Wallwork   ierr = PetscOptionsBoundedInt("-dm_plex_metric_num_iterations", "Number of ParMmg adaptation iterations", "DMAdaptMetric", numIter, &numIter, NULL, 0);CHKERRQ(ierr);
27*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetNumIterations(dm, numIter);CHKERRQ(ierr);
28*cc2eee55SJoe Wallwork   ierr = PetscOptionsRangeInt("-dm_plex_metric_verbosity", "Verbosity of metric-based mesh adaptation package (-1 = silent, 10 = maximum)", "DMAdaptMetric", verbosity, &verbosity, NULL, -1, 10);CHKERRQ(ierr);
29*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetVerbosity(dm, verbosity);CHKERRQ(ierr);
3031b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_h_min", "Minimum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_min, &h_min, NULL);CHKERRQ(ierr);
3131b70465SJoe Wallwork   ierr = DMPlexMetricSetMinimumMagnitude(dm, h_min);CHKERRQ(ierr);
3231b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_h_max", "Maximum tolerated metric magnitude", "DMPlexMetricEnforceSPD", h_max, &h_max, NULL);CHKERRQ(ierr);
3331b70465SJoe Wallwork   ierr = DMPlexMetricSetMaximumMagnitude(dm, h_max);CHKERRQ(ierr);
3431b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_a_max", "Maximum tolerated anisotropy", "DMPlexMetricEnforceSPD", a_max, &a_max, NULL);CHKERRQ(ierr);
3531b70465SJoe Wallwork   ierr = DMPlexMetricSetMaximumAnisotropy(dm, a_max);CHKERRQ(ierr);
3631b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_p", "L-p normalization order", "DMPlexMetricNormalize", p, &p, NULL);CHKERRQ(ierr);
3731b70465SJoe Wallwork   ierr = DMPlexMetricSetNormalizationOrder(dm, p);CHKERRQ(ierr);
3831b70465SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_target_complexity", "Target metric complexity", "DMPlexMetricNormalize", target, &target, NULL);CHKERRQ(ierr);
3931b70465SJoe Wallwork   ierr = DMPlexMetricSetTargetComplexity(dm, target);CHKERRQ(ierr);
40*cc2eee55SJoe Wallwork   ierr = PetscOptionsReal("-dm_plex_metric_gradation_factor", "Metric gradation factor", "DMAdaptMetric", beta, &beta, NULL);CHKERRQ(ierr);
41*cc2eee55SJoe Wallwork   ierr = DMPlexMetricSetGradationFactor(dm, beta);CHKERRQ(ierr);
4231b70465SJoe Wallwork   ierr = PetscOptionsEnd();CHKERRQ(ierr);
4331b70465SJoe Wallwork   PetscFunctionReturn(0);
4431b70465SJoe Wallwork }
4531b70465SJoe Wallwork 
4631b70465SJoe Wallwork /*
4731b70465SJoe Wallwork   DMPlexMetricSetIsotropic - Record whether a metric is isotropic
4831b70465SJoe Wallwork 
4931b70465SJoe Wallwork   Input parameters:
5031b70465SJoe Wallwork + dm        - The DM
5131b70465SJoe Wallwork - isotropic - Is the metric isotropic?
5231b70465SJoe Wallwork 
5331b70465SJoe Wallwork   Level: beginner
5431b70465SJoe Wallwork 
5531b70465SJoe Wallwork .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst()
5631b70465SJoe Wallwork */
5731b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetIsotropic(DM dm, PetscBool isotropic)
5831b70465SJoe Wallwork {
5931b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
6031b70465SJoe Wallwork   PetscErrorCode ierr;
6131b70465SJoe Wallwork 
6231b70465SJoe Wallwork   PetscFunctionBegin;
6331b70465SJoe Wallwork   if (!plex->metricCtx) {
6431b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
6531b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
6631b70465SJoe Wallwork   }
6731b70465SJoe Wallwork   plex->metricCtx->isotropic = isotropic;
6831b70465SJoe Wallwork   PetscFunctionReturn(0);
6931b70465SJoe Wallwork }
7031b70465SJoe Wallwork 
7131b70465SJoe Wallwork /*
7231b70465SJoe Wallwork   DMPlexMetricIsIsotropic - Is a metric is isotropic?
7331b70465SJoe Wallwork 
7431b70465SJoe Wallwork   Input parameters:
7531b70465SJoe Wallwork . dm        - The DM
7631b70465SJoe Wallwork 
7731b70465SJoe Wallwork   Output parameters:
7831b70465SJoe Wallwork . isotropic - Is the metric isotropic?
7931b70465SJoe Wallwork 
8031b70465SJoe Wallwork   Level: beginner
8131b70465SJoe Wallwork 
8231b70465SJoe Wallwork .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst()
8331b70465SJoe Wallwork */
8431b70465SJoe Wallwork PetscErrorCode DMPlexMetricIsIsotropic(DM dm, PetscBool *isotropic)
8531b70465SJoe Wallwork {
8631b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
8731b70465SJoe Wallwork   PetscErrorCode ierr;
8831b70465SJoe Wallwork 
8931b70465SJoe Wallwork   PetscFunctionBegin;
9031b70465SJoe Wallwork   if (!plex->metricCtx) {
9131b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
9231b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
9331b70465SJoe Wallwork   }
9431b70465SJoe Wallwork   *isotropic = plex->metricCtx->isotropic;
9531b70465SJoe Wallwork   PetscFunctionReturn(0);
9631b70465SJoe Wallwork }
9731b70465SJoe Wallwork 
9831b70465SJoe Wallwork /*
9931b70465SJoe Wallwork   DMPlexMetricSetRestrictAnisotropyFirst - Record whether anisotropy should be restricted before normalization
10031b70465SJoe Wallwork 
10131b70465SJoe Wallwork   Input parameters:
10231b70465SJoe Wallwork + dm                      - The DM
10331b70465SJoe Wallwork - restrictAnisotropyFirst - Should anisotropy be normalized first?
10431b70465SJoe Wallwork 
10531b70465SJoe Wallwork   Level: beginner
10631b70465SJoe Wallwork 
10731b70465SJoe Wallwork .seealso: DMPlexMetricSetIsotropic(), DMPlexMetricRestrictAnisotropyFirst()
10831b70465SJoe Wallwork */
10931b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetRestrictAnisotropyFirst(DM dm, PetscBool restrictAnisotropyFirst)
11031b70465SJoe Wallwork {
11131b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
11231b70465SJoe Wallwork   PetscErrorCode ierr;
11331b70465SJoe Wallwork 
11431b70465SJoe Wallwork   PetscFunctionBegin;
11531b70465SJoe Wallwork   if (!plex->metricCtx) {
11631b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
11731b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
11831b70465SJoe Wallwork   }
11931b70465SJoe Wallwork   plex->metricCtx->restrictAnisotropyFirst = restrictAnisotropyFirst;
12031b70465SJoe Wallwork   PetscFunctionReturn(0);
12131b70465SJoe Wallwork }
12231b70465SJoe Wallwork 
12331b70465SJoe Wallwork /*
12431b70465SJoe Wallwork   DMPlexMetricRestrictAnisotropyFirst - Is anisotropy restricted before normalization or after?
12531b70465SJoe Wallwork 
12631b70465SJoe Wallwork   Input parameters:
12731b70465SJoe Wallwork . dm                      - The DM
12831b70465SJoe Wallwork 
12931b70465SJoe Wallwork   Output parameters:
13031b70465SJoe Wallwork . restrictAnisotropyFirst - Is anisotropy be normalized first?
13131b70465SJoe Wallwork 
13231b70465SJoe Wallwork   Level: beginner
13331b70465SJoe Wallwork 
13431b70465SJoe Wallwork .seealso: DMPlexMetricIsIsotropic(), DMPlexMetricSetRestrictAnisotropyFirst()
13531b70465SJoe Wallwork */
13631b70465SJoe Wallwork PetscErrorCode DMPlexMetricRestrictAnisotropyFirst(DM dm, PetscBool *restrictAnisotropyFirst)
13731b70465SJoe Wallwork {
13831b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
13931b70465SJoe Wallwork   PetscErrorCode ierr;
14031b70465SJoe Wallwork 
14131b70465SJoe Wallwork   PetscFunctionBegin;
14231b70465SJoe Wallwork   if (!plex->metricCtx) {
14331b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
14431b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
14531b70465SJoe Wallwork   }
14631b70465SJoe Wallwork   *restrictAnisotropyFirst = plex->metricCtx->restrictAnisotropyFirst;
14731b70465SJoe Wallwork   PetscFunctionReturn(0);
14831b70465SJoe Wallwork }
14931b70465SJoe Wallwork 
15031b70465SJoe Wallwork /*
151*cc2eee55SJoe Wallwork   DMPlexMetricSetNoInsertion - Should node insertion and deletion be turned off?
152*cc2eee55SJoe Wallwork 
153*cc2eee55SJoe Wallwork   Input parameters:
154*cc2eee55SJoe Wallwork + dm       - The DM
155*cc2eee55SJoe Wallwork - noInsert - Should node insertion and deletion be turned off?
156*cc2eee55SJoe Wallwork 
157*cc2eee55SJoe Wallwork   Level: beginner
158*cc2eee55SJoe Wallwork 
159*cc2eee55SJoe Wallwork .seealso: DMPlexMetricNoInsertion(), DMPlexMetricSetNoSwapping(), DMPlexMetricSetNoMovement()
160*cc2eee55SJoe Wallwork */
161*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoInsertion(DM dm, PetscBool noInsert)
162*cc2eee55SJoe Wallwork {
163*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
164*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
165*cc2eee55SJoe Wallwork 
166*cc2eee55SJoe Wallwork   PetscFunctionBegin;
167*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
168*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
169*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
170*cc2eee55SJoe Wallwork   }
171*cc2eee55SJoe Wallwork   plex->metricCtx->noInsert = noInsert;
172*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
173*cc2eee55SJoe Wallwork }
174*cc2eee55SJoe Wallwork 
175*cc2eee55SJoe Wallwork /*
176*cc2eee55SJoe Wallwork   DMPlexMetricNoInsertion - Are node insertion and deletion turned off?
177*cc2eee55SJoe Wallwork 
178*cc2eee55SJoe Wallwork   Input parameters:
179*cc2eee55SJoe Wallwork . dm       - The DM
180*cc2eee55SJoe Wallwork 
181*cc2eee55SJoe Wallwork   Output parameters:
182*cc2eee55SJoe Wallwork . noInsert - Are node insertion and deletion turned off?
183*cc2eee55SJoe Wallwork 
184*cc2eee55SJoe Wallwork   Level: beginner
185*cc2eee55SJoe Wallwork 
186*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetNoInsertion(), DMPlexMetricNoSwapping(), DMPlexMetricNoMovement()
187*cc2eee55SJoe Wallwork */
188*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoInsertion(DM dm, PetscBool *noInsert)
189*cc2eee55SJoe Wallwork {
190*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
191*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
192*cc2eee55SJoe Wallwork 
193*cc2eee55SJoe Wallwork   PetscFunctionBegin;
194*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
195*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
196*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
197*cc2eee55SJoe Wallwork   }
198*cc2eee55SJoe Wallwork   *noInsert = plex->metricCtx->noInsert;
199*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
200*cc2eee55SJoe Wallwork }
201*cc2eee55SJoe Wallwork 
202*cc2eee55SJoe Wallwork /*
203*cc2eee55SJoe Wallwork   DMPlexMetricSetNoSwapping - Should facet swapping be turned off?
204*cc2eee55SJoe Wallwork 
205*cc2eee55SJoe Wallwork   Input parameters:
206*cc2eee55SJoe Wallwork + dm     - The DM
207*cc2eee55SJoe Wallwork - noSwap - Should facet swapping be turned off?
208*cc2eee55SJoe Wallwork 
209*cc2eee55SJoe Wallwork   Level: beginner
210*cc2eee55SJoe Wallwork 
211*cc2eee55SJoe Wallwork .seealso: DMPlexMetricNoSwapping(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoMovement()
212*cc2eee55SJoe Wallwork */
213*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoSwapping(DM dm, PetscBool noSwap)
214*cc2eee55SJoe Wallwork {
215*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
216*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
217*cc2eee55SJoe Wallwork 
218*cc2eee55SJoe Wallwork   PetscFunctionBegin;
219*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
220*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
221*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
222*cc2eee55SJoe Wallwork   }
223*cc2eee55SJoe Wallwork   plex->metricCtx->noSwap = noSwap;
224*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
225*cc2eee55SJoe Wallwork }
226*cc2eee55SJoe Wallwork 
227*cc2eee55SJoe Wallwork /*
228*cc2eee55SJoe Wallwork   DMPlexMetricNoSwapping - Is facet swapping turned off?
229*cc2eee55SJoe Wallwork 
230*cc2eee55SJoe Wallwork   Input parameters:
231*cc2eee55SJoe Wallwork . dm     - The DM
232*cc2eee55SJoe Wallwork 
233*cc2eee55SJoe Wallwork   Output parameters:
234*cc2eee55SJoe Wallwork . noSwap - Is facet swapping turned off?
235*cc2eee55SJoe Wallwork 
236*cc2eee55SJoe Wallwork   Level: beginner
237*cc2eee55SJoe Wallwork 
238*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetNoSwapping(), DMPlexMetricNoInsertion(), DMPlexMetricNoMovement()
239*cc2eee55SJoe Wallwork */
240*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoSwapping(DM dm, PetscBool *noSwap)
241*cc2eee55SJoe Wallwork {
242*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
243*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
244*cc2eee55SJoe Wallwork 
245*cc2eee55SJoe Wallwork   PetscFunctionBegin;
246*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
247*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
248*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
249*cc2eee55SJoe Wallwork   }
250*cc2eee55SJoe Wallwork   *noSwap = plex->metricCtx->noSwap;
251*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
252*cc2eee55SJoe Wallwork }
253*cc2eee55SJoe Wallwork 
254*cc2eee55SJoe Wallwork /*
255*cc2eee55SJoe Wallwork   DMPlexMetricSetNoMovement - Should node movement be turned off?
256*cc2eee55SJoe Wallwork 
257*cc2eee55SJoe Wallwork   Input parameters:
258*cc2eee55SJoe Wallwork + dm     - The DM
259*cc2eee55SJoe Wallwork - noMove - Should node movement be turned off?
260*cc2eee55SJoe Wallwork 
261*cc2eee55SJoe Wallwork   Level: beginner
262*cc2eee55SJoe Wallwork 
263*cc2eee55SJoe Wallwork .seealso: DMPlexMetricNoMovement(), DMPlexMetricSetNoInsertion(), DMPlexMetricSetNoSwapping()
264*cc2eee55SJoe Wallwork */
265*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNoMovement(DM dm, PetscBool noMove)
266*cc2eee55SJoe Wallwork {
267*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
268*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
269*cc2eee55SJoe Wallwork 
270*cc2eee55SJoe Wallwork   PetscFunctionBegin;
271*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
272*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
273*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
274*cc2eee55SJoe Wallwork   }
275*cc2eee55SJoe Wallwork   plex->metricCtx->noMove = noMove;
276*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
277*cc2eee55SJoe Wallwork }
278*cc2eee55SJoe Wallwork 
279*cc2eee55SJoe Wallwork /*
280*cc2eee55SJoe Wallwork   DMPlexMetricNoMovement - Is node movement turned off?
281*cc2eee55SJoe Wallwork 
282*cc2eee55SJoe Wallwork   Input parameters:
283*cc2eee55SJoe Wallwork . dm     - The DM
284*cc2eee55SJoe Wallwork 
285*cc2eee55SJoe Wallwork   Output parameters:
286*cc2eee55SJoe Wallwork . noMove - Is node movement turned off?
287*cc2eee55SJoe Wallwork 
288*cc2eee55SJoe Wallwork   Level: beginner
289*cc2eee55SJoe Wallwork 
290*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetNoMovement(), DMPlexMetricNoInsertion(), DMPlexMetricNoSwapping()
291*cc2eee55SJoe Wallwork */
292*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricNoMovement(DM dm, PetscBool *noMove)
293*cc2eee55SJoe Wallwork {
294*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
295*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
296*cc2eee55SJoe Wallwork 
297*cc2eee55SJoe Wallwork   PetscFunctionBegin;
298*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
299*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
300*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
301*cc2eee55SJoe Wallwork   }
302*cc2eee55SJoe Wallwork   *noMove = plex->metricCtx->noMove;
303*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
304*cc2eee55SJoe Wallwork }
305*cc2eee55SJoe Wallwork 
306*cc2eee55SJoe Wallwork /*
30731b70465SJoe Wallwork   DMPlexMetricSetMinimumMagnitude - Set the minimum tolerated metric magnitude
30831b70465SJoe Wallwork 
30931b70465SJoe Wallwork   Input parameters:
31031b70465SJoe Wallwork + dm    - The DM
31131b70465SJoe Wallwork - h_min - The minimum tolerated metric magnitude
31231b70465SJoe Wallwork 
31331b70465SJoe Wallwork   Level: beginner
31431b70465SJoe Wallwork 
31531b70465SJoe Wallwork .seealso: DMPlexMetricGetMinimumMagnitude(), DMPlexMetricSetMaximumMagnitude()
31631b70465SJoe Wallwork */
31731b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMinimumMagnitude(DM dm, PetscReal h_min)
31831b70465SJoe Wallwork {
31931b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
32031b70465SJoe Wallwork   PetscErrorCode ierr;
32131b70465SJoe Wallwork 
32231b70465SJoe Wallwork   PetscFunctionBegin;
32331b70465SJoe Wallwork   if (!plex->metricCtx) {
32431b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
32531b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
32631b70465SJoe Wallwork   }
32731b70465SJoe Wallwork   if (h_min <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_min);
32831b70465SJoe Wallwork   plex->metricCtx->h_min = h_min;
32931b70465SJoe Wallwork   PetscFunctionReturn(0);
33031b70465SJoe Wallwork }
33131b70465SJoe Wallwork 
33231b70465SJoe Wallwork /*
33331b70465SJoe Wallwork   DMPlexMetricGetMinimumMagnitude - Get the minimum tolerated metric magnitude
33431b70465SJoe Wallwork 
33531b70465SJoe Wallwork   Input parameters:
33631b70465SJoe Wallwork . dm    - The DM
33731b70465SJoe Wallwork 
338*cc2eee55SJoe Wallwork   Output parameters:
33931b70465SJoe Wallwork . h_min - The minimum tolerated metric magnitude
34031b70465SJoe Wallwork 
34131b70465SJoe Wallwork   Level: beginner
34231b70465SJoe Wallwork 
34331b70465SJoe Wallwork .seealso: DMPlexMetricSetMinimumMagnitude(), DMPlexMetricGetMaximumMagnitude()
34431b70465SJoe Wallwork */
34531b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMinimumMagnitude(DM dm, PetscReal *h_min)
34631b70465SJoe Wallwork {
34731b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
34831b70465SJoe Wallwork   PetscErrorCode ierr;
34931b70465SJoe Wallwork 
35031b70465SJoe Wallwork   PetscFunctionBegin;
35131b70465SJoe Wallwork   if (!plex->metricCtx) {
35231b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
35331b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
35431b70465SJoe Wallwork   }
35531b70465SJoe Wallwork   *h_min = plex->metricCtx->h_min;
35631b70465SJoe Wallwork   PetscFunctionReturn(0);
35731b70465SJoe Wallwork }
35831b70465SJoe Wallwork 
35931b70465SJoe Wallwork /*
36031b70465SJoe Wallwork   DMPlexMetricSetMaximumMagnitude - Set the maximum tolerated metric magnitude
36131b70465SJoe Wallwork 
36231b70465SJoe Wallwork   Input parameters:
36331b70465SJoe Wallwork + dm    - The DM
36431b70465SJoe Wallwork - h_max - The maximum tolerated metric magnitude
36531b70465SJoe Wallwork 
36631b70465SJoe Wallwork   Level: beginner
36731b70465SJoe Wallwork 
36831b70465SJoe Wallwork .seealso: DMPlexMetricGetMaximumMagnitude(), DMPlexMetricSetMinimumMagnitude()
36931b70465SJoe Wallwork */
37031b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumMagnitude(DM dm, PetscReal h_max)
37131b70465SJoe Wallwork {
37231b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
37331b70465SJoe Wallwork   PetscErrorCode ierr;
37431b70465SJoe Wallwork 
37531b70465SJoe Wallwork   PetscFunctionBegin;
37631b70465SJoe Wallwork   if (!plex->metricCtx) {
37731b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
37831b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
37931b70465SJoe Wallwork   }
38031b70465SJoe Wallwork   if (h_max <= 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric magnitudes must be positive, not %.4e", h_max);
38131b70465SJoe Wallwork   plex->metricCtx->h_max = h_max;
38231b70465SJoe Wallwork   PetscFunctionReturn(0);
38331b70465SJoe Wallwork }
38431b70465SJoe Wallwork 
38531b70465SJoe Wallwork /*
38631b70465SJoe Wallwork   DMPlexMetricGetMaximumMagnitude - Get the maximum tolerated metric magnitude
38731b70465SJoe Wallwork 
38831b70465SJoe Wallwork   Input parameters:
38931b70465SJoe Wallwork . dm    - The DM
39031b70465SJoe Wallwork 
391*cc2eee55SJoe Wallwork   Output parameters:
39231b70465SJoe Wallwork . h_max - The maximum tolerated metric magnitude
39331b70465SJoe Wallwork 
39431b70465SJoe Wallwork   Level: beginner
39531b70465SJoe Wallwork 
39631b70465SJoe Wallwork .seealso: DMPlexMetricSetMaximumMagnitude(), DMPlexMetricGetMinimumMagnitude()
39731b70465SJoe Wallwork */
39831b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumMagnitude(DM dm, PetscReal *h_max)
39931b70465SJoe Wallwork {
40031b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
40131b70465SJoe Wallwork   PetscErrorCode ierr;
40231b70465SJoe Wallwork 
40331b70465SJoe Wallwork   PetscFunctionBegin;
40431b70465SJoe Wallwork   if (!plex->metricCtx) {
40531b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
40631b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
40731b70465SJoe Wallwork   }
40831b70465SJoe Wallwork   *h_max = plex->metricCtx->h_max;
40931b70465SJoe Wallwork   PetscFunctionReturn(0);
41031b70465SJoe Wallwork }
41131b70465SJoe Wallwork 
41231b70465SJoe Wallwork /*
41331b70465SJoe Wallwork   DMPlexMetricSetMaximumAnisotropy - Set the maximum tolerated metric anisotropy
41431b70465SJoe Wallwork 
41531b70465SJoe Wallwork   Input parameters:
41631b70465SJoe Wallwork + dm    - The DM
41731b70465SJoe Wallwork - a_max - The maximum tolerated metric anisotropy
41831b70465SJoe Wallwork 
41931b70465SJoe Wallwork   Level: beginner
42031b70465SJoe Wallwork 
42131b70465SJoe Wallwork   Note: If the value zero is given then anisotropy will not be restricted. Otherwise, it should be at least one.
42231b70465SJoe Wallwork 
42331b70465SJoe Wallwork .seealso: DMPlexMetricGetMaximumAnisotropy(), DMPlexMetricSetMaximumMagnitude()
42431b70465SJoe Wallwork */
42531b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetMaximumAnisotropy(DM dm, PetscReal a_max)
42631b70465SJoe Wallwork {
42731b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
42831b70465SJoe Wallwork   PetscErrorCode ierr;
42931b70465SJoe Wallwork 
43031b70465SJoe Wallwork   PetscFunctionBegin;
43131b70465SJoe Wallwork   if (!plex->metricCtx) {
43231b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
43331b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
43431b70465SJoe Wallwork   }
43531b70465SJoe Wallwork   if (a_max < 1.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Anisotropy must be at least one, not %.4e", a_max);
43631b70465SJoe Wallwork   plex->metricCtx->a_max = a_max;
43731b70465SJoe Wallwork   PetscFunctionReturn(0);
43831b70465SJoe Wallwork }
43931b70465SJoe Wallwork 
44031b70465SJoe Wallwork /*
44131b70465SJoe Wallwork   DMPlexMetricGetMaximumAnisotropy - Get the maximum tolerated metric anisotropy
44231b70465SJoe Wallwork 
44331b70465SJoe Wallwork   Input parameters:
44431b70465SJoe Wallwork . dm    - The DM
44531b70465SJoe Wallwork 
446*cc2eee55SJoe Wallwork   Output parameters:
44731b70465SJoe Wallwork . a_max - The maximum tolerated metric anisotropy
44831b70465SJoe Wallwork 
44931b70465SJoe Wallwork   Level: beginner
45031b70465SJoe Wallwork 
45131b70465SJoe Wallwork .seealso: DMPlexMetricSetMaximumAnisotropy(), DMPlexMetricGetMaximumMagnitude()
45231b70465SJoe Wallwork */
45331b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetMaximumAnisotropy(DM dm, PetscReal *a_max)
45431b70465SJoe Wallwork {
45531b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
45631b70465SJoe Wallwork   PetscErrorCode ierr;
45731b70465SJoe Wallwork 
45831b70465SJoe Wallwork   PetscFunctionBegin;
45931b70465SJoe Wallwork   if (!plex->metricCtx) {
46031b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
46131b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
46231b70465SJoe Wallwork   }
46331b70465SJoe Wallwork   *a_max = plex->metricCtx->a_max;
46431b70465SJoe Wallwork   PetscFunctionReturn(0);
46531b70465SJoe Wallwork }
46631b70465SJoe Wallwork 
46731b70465SJoe Wallwork /*
46831b70465SJoe Wallwork   DMPlexMetricSetTargetComplexity - Set the target metric complexity
46931b70465SJoe Wallwork 
47031b70465SJoe Wallwork   Input parameters:
47131b70465SJoe Wallwork + dm               - The DM
47231b70465SJoe Wallwork - targetComplexity - The target metric complexity
47331b70465SJoe Wallwork 
47431b70465SJoe Wallwork   Level: beginner
47531b70465SJoe Wallwork 
47631b70465SJoe Wallwork .seealso: DMPlexMetricGetTargetComplexity(), DMPlexMetricSetNormalizationOrder()
47731b70465SJoe Wallwork */
47831b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetTargetComplexity(DM dm, PetscReal targetComplexity)
47931b70465SJoe Wallwork {
48031b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
48131b70465SJoe Wallwork   PetscErrorCode ierr;
48231b70465SJoe Wallwork 
48331b70465SJoe Wallwork   PetscFunctionBegin;
48431b70465SJoe Wallwork   if (!plex->metricCtx) {
48531b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
48631b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
48731b70465SJoe Wallwork   }
48831b70465SJoe Wallwork   if (targetComplexity <= 0.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Metric complexity must be positive");
48931b70465SJoe Wallwork   plex->metricCtx->targetComplexity = targetComplexity;
49031b70465SJoe Wallwork   PetscFunctionReturn(0);
49131b70465SJoe Wallwork }
49231b70465SJoe Wallwork 
49331b70465SJoe Wallwork /*
49431b70465SJoe Wallwork   DMPlexMetricGetTargetComplexity - Get the target metric complexity
49531b70465SJoe Wallwork 
49631b70465SJoe Wallwork   Input parameters:
49731b70465SJoe Wallwork . dm               - The DM
49831b70465SJoe Wallwork 
499*cc2eee55SJoe Wallwork   Output parameters:
50031b70465SJoe Wallwork . targetComplexity - The target metric complexity
50131b70465SJoe Wallwork 
50231b70465SJoe Wallwork   Level: beginner
50331b70465SJoe Wallwork 
50431b70465SJoe Wallwork .seealso: DMPlexMetricSetTargetComplexity(), DMPlexMetricGetNormalizationOrder()
50531b70465SJoe Wallwork */
50631b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetTargetComplexity(DM dm, PetscReal *targetComplexity)
50731b70465SJoe Wallwork {
50831b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
50931b70465SJoe Wallwork   PetscErrorCode ierr;
51031b70465SJoe Wallwork 
51131b70465SJoe Wallwork   PetscFunctionBegin;
51231b70465SJoe Wallwork   if (!plex->metricCtx) {
51331b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
51431b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
51531b70465SJoe Wallwork   }
51631b70465SJoe Wallwork   *targetComplexity = plex->metricCtx->targetComplexity;
51731b70465SJoe Wallwork   PetscFunctionReturn(0);
51831b70465SJoe Wallwork }
51931b70465SJoe Wallwork 
52031b70465SJoe Wallwork /*
52131b70465SJoe Wallwork   DMPlexMetricSetNormalizationOrder - Set the order p for L-p normalization
52231b70465SJoe Wallwork 
52331b70465SJoe Wallwork   Input parameters:
52431b70465SJoe Wallwork + dm - The DM
52531b70465SJoe Wallwork - p  - The normalization order
52631b70465SJoe Wallwork 
52731b70465SJoe Wallwork   Level: beginner
52831b70465SJoe Wallwork 
52931b70465SJoe Wallwork .seealso: DMPlexMetricGetNormalizationOrder(), DMPlexMetricSetTargetComplexity()
53031b70465SJoe Wallwork */
53131b70465SJoe Wallwork PetscErrorCode DMPlexMetricSetNormalizationOrder(DM dm, PetscReal p)
53231b70465SJoe Wallwork {
53331b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
53431b70465SJoe Wallwork   PetscErrorCode ierr;
53531b70465SJoe Wallwork 
53631b70465SJoe Wallwork   PetscFunctionBegin;
53731b70465SJoe Wallwork   if (!plex->metricCtx) {
53831b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
53931b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
54031b70465SJoe Wallwork   }
54131b70465SJoe Wallwork   if (p < 1.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Normalization order must be one or greater");
54231b70465SJoe Wallwork   plex->metricCtx->p = p;
54331b70465SJoe Wallwork   PetscFunctionReturn(0);
54431b70465SJoe Wallwork }
54531b70465SJoe Wallwork 
54631b70465SJoe Wallwork /*
54731b70465SJoe Wallwork   DMPlexMetricGetNormalizationOrder - Get the order p for L-p normalization
54831b70465SJoe Wallwork 
54931b70465SJoe Wallwork   Input parameters:
55031b70465SJoe Wallwork . dm - The DM
55131b70465SJoe Wallwork 
552*cc2eee55SJoe Wallwork   Output parameters:
55331b70465SJoe Wallwork . p - The normalization order
55431b70465SJoe Wallwork 
55531b70465SJoe Wallwork   Level: beginner
55631b70465SJoe Wallwork 
55731b70465SJoe Wallwork .seealso: DMPlexMetricSetNormalizationOrder(), DMPlexMetricGetTargetComplexity()
55831b70465SJoe Wallwork */
55931b70465SJoe Wallwork PetscErrorCode DMPlexMetricGetNormalizationOrder(DM dm, PetscReal *p)
56031b70465SJoe Wallwork {
56131b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
56231b70465SJoe Wallwork   PetscErrorCode ierr;
56331b70465SJoe Wallwork 
56431b70465SJoe Wallwork   PetscFunctionBegin;
56531b70465SJoe Wallwork   if (!plex->metricCtx) {
56631b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
56731b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
56831b70465SJoe Wallwork   }
56931b70465SJoe Wallwork   *p = plex->metricCtx->p;
57031b70465SJoe Wallwork   PetscFunctionReturn(0);
57131b70465SJoe Wallwork }
57231b70465SJoe Wallwork 
573*cc2eee55SJoe Wallwork /*
574*cc2eee55SJoe Wallwork   DMPlexMetricSetGradationFactor - Set the metric gradation factor
575*cc2eee55SJoe Wallwork 
576*cc2eee55SJoe Wallwork   Input parameters:
577*cc2eee55SJoe Wallwork + dm   - The DM
578*cc2eee55SJoe Wallwork - beta - The metric gradation factor
579*cc2eee55SJoe Wallwork 
580*cc2eee55SJoe Wallwork   Level: beginner
581*cc2eee55SJoe Wallwork 
582*cc2eee55SJoe Wallwork   Notes:
583*cc2eee55SJoe Wallwork 
584*cc2eee55SJoe Wallwork   The gradation factor is the maximum tolerated length ratio between adjacent edges.
585*cc2eee55SJoe Wallwork 
586*cc2eee55SJoe Wallwork   Turn off gradation by passing the value -1. Otherwise, pass a positive value.
587*cc2eee55SJoe Wallwork 
588*cc2eee55SJoe Wallwork .seealso: DMPlexMetricGetGradationFactor()
589*cc2eee55SJoe Wallwork */
590*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetGradationFactor(DM dm, PetscReal beta)
591*cc2eee55SJoe Wallwork {
592*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
593*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
594*cc2eee55SJoe Wallwork 
595*cc2eee55SJoe Wallwork   PetscFunctionBegin;
596*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
597*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
598*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
599*cc2eee55SJoe Wallwork   }
600*cc2eee55SJoe Wallwork   plex->metricCtx->gradationFactor = beta;
601*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
602*cc2eee55SJoe Wallwork }
603*cc2eee55SJoe Wallwork 
604*cc2eee55SJoe Wallwork /*
605*cc2eee55SJoe Wallwork   DMPlexMetricGetGradationFactor - Get the metric gradation factor
606*cc2eee55SJoe Wallwork 
607*cc2eee55SJoe Wallwork   Input parameters:
608*cc2eee55SJoe Wallwork . dm   - The DM
609*cc2eee55SJoe Wallwork 
610*cc2eee55SJoe Wallwork   Output parameters:
611*cc2eee55SJoe Wallwork . beta - The metric gradation factor
612*cc2eee55SJoe Wallwork 
613*cc2eee55SJoe Wallwork   Level: beginner
614*cc2eee55SJoe Wallwork 
615*cc2eee55SJoe Wallwork   Note: The gradation factor is the maximum tolerated length ratio between adjacent edges.
616*cc2eee55SJoe Wallwork 
617*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetGradationFactor()
618*cc2eee55SJoe Wallwork */
619*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetGradationFactor(DM dm, PetscReal *beta)
620*cc2eee55SJoe Wallwork {
621*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
622*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
623*cc2eee55SJoe Wallwork 
624*cc2eee55SJoe Wallwork   PetscFunctionBegin;
625*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
626*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
627*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
628*cc2eee55SJoe Wallwork   }
629*cc2eee55SJoe Wallwork   *beta = plex->metricCtx->gradationFactor;
630*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
631*cc2eee55SJoe Wallwork }
632*cc2eee55SJoe Wallwork 
633*cc2eee55SJoe Wallwork /*
634*cc2eee55SJoe Wallwork   DMPlexMetricSetVerbosity - Set the verbosity of the mesh adaptation package
635*cc2eee55SJoe Wallwork 
636*cc2eee55SJoe Wallwork   Input parameters:
637*cc2eee55SJoe Wallwork + dm        - The DM
638*cc2eee55SJoe Wallwork - verbosity - The verbosity, where -1 is silent and 10 is maximum
639*cc2eee55SJoe Wallwork 
640*cc2eee55SJoe Wallwork .seealso: DMPlexMetricGetVerbosity(), DMPlexMetricSetNumIterations()
641*cc2eee55SJoe Wallwork */
642*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetVerbosity(DM dm, PetscInt verbosity)
643*cc2eee55SJoe Wallwork {
644*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
645*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
646*cc2eee55SJoe Wallwork 
647*cc2eee55SJoe Wallwork   PetscFunctionBegin;
648*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
649*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
650*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
651*cc2eee55SJoe Wallwork   }
652*cc2eee55SJoe Wallwork   plex->metricCtx->verbosity = verbosity;
653*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
654*cc2eee55SJoe Wallwork }
655*cc2eee55SJoe Wallwork 
656*cc2eee55SJoe Wallwork /*
657*cc2eee55SJoe Wallwork   DMPlexMetricGetVerbosity - Get the verbosity of the mesh adaptation package
658*cc2eee55SJoe Wallwork 
659*cc2eee55SJoe Wallwork   Input parameters:
660*cc2eee55SJoe Wallwork . dm        - The DM
661*cc2eee55SJoe Wallwork 
662*cc2eee55SJoe Wallwork   Output parameters:
663*cc2eee55SJoe Wallwork . verbosity - The verbosity, where -1 is silent and 10 is maximum
664*cc2eee55SJoe Wallwork 
665*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations()
666*cc2eee55SJoe Wallwork */
667*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetVerbosity(DM dm, PetscInt *verbosity)
668*cc2eee55SJoe Wallwork {
669*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
670*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
671*cc2eee55SJoe Wallwork 
672*cc2eee55SJoe Wallwork   PetscFunctionBegin;
673*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
674*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
675*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
676*cc2eee55SJoe Wallwork   }
677*cc2eee55SJoe Wallwork   *verbosity = plex->metricCtx->verbosity;
678*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
679*cc2eee55SJoe Wallwork }
680*cc2eee55SJoe Wallwork 
681*cc2eee55SJoe Wallwork /*
682*cc2eee55SJoe Wallwork   DMPlexMetricSetNumIterations - Set the number of parallel adaptation iterations
683*cc2eee55SJoe Wallwork 
684*cc2eee55SJoe Wallwork   Input parameters:
685*cc2eee55SJoe Wallwork + dm      - The DM
686*cc2eee55SJoe Wallwork - numIter - the number of parallel adaptation iterations
687*cc2eee55SJoe Wallwork 
688*cc2eee55SJoe Wallwork   Note: This option is only used by ParMmg, not Mmg or Pragmatic.
689*cc2eee55SJoe Wallwork 
690*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetVerbosity(), DMPlexMetricGetNumIterations()
691*cc2eee55SJoe Wallwork */
692*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricSetNumIterations(DM dm, PetscInt numIter)
693*cc2eee55SJoe Wallwork {
694*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
695*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
696*cc2eee55SJoe Wallwork 
697*cc2eee55SJoe Wallwork   PetscFunctionBegin;
698*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
699*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
700*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
701*cc2eee55SJoe Wallwork   }
702*cc2eee55SJoe Wallwork   plex->metricCtx->numIter = numIter;
703*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
704*cc2eee55SJoe Wallwork }
705*cc2eee55SJoe Wallwork 
706*cc2eee55SJoe Wallwork /*
707*cc2eee55SJoe Wallwork   DMPlexMetricGetNumIterations - Get the number of parallel adaptation iterations
708*cc2eee55SJoe Wallwork 
709*cc2eee55SJoe Wallwork   Input parameters:
710*cc2eee55SJoe Wallwork . dm      - The DM
711*cc2eee55SJoe Wallwork 
712*cc2eee55SJoe Wallwork   Output parameters:
713*cc2eee55SJoe Wallwork . numIter - the number of parallel adaptation iterations
714*cc2eee55SJoe Wallwork 
715*cc2eee55SJoe Wallwork   Note: This option is only used by ParMmg, not Mmg or Pragmatic.
716*cc2eee55SJoe Wallwork 
717*cc2eee55SJoe Wallwork .seealso: DMPlexMetricSetNumIterations(), DMPlexMetricGetVerbosity()
718*cc2eee55SJoe Wallwork */
719*cc2eee55SJoe Wallwork PetscErrorCode DMPlexMetricGetNumIterations(DM dm, PetscInt *numIter)
720*cc2eee55SJoe Wallwork {
721*cc2eee55SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
722*cc2eee55SJoe Wallwork   PetscErrorCode ierr;
723*cc2eee55SJoe Wallwork 
724*cc2eee55SJoe Wallwork   PetscFunctionBegin;
725*cc2eee55SJoe Wallwork   if (!plex->metricCtx) {
726*cc2eee55SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
727*cc2eee55SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
728*cc2eee55SJoe Wallwork   }
729*cc2eee55SJoe Wallwork   *numIter = plex->metricCtx->numIter;
730*cc2eee55SJoe Wallwork   PetscFunctionReturn(0);
731*cc2eee55SJoe Wallwork }
732*cc2eee55SJoe Wallwork 
73320282da2SJoe Wallwork PetscErrorCode DMPlexP1FieldCreate_Private(DM dm, PetscInt f, PetscInt size, Vec *metric)
73420282da2SJoe Wallwork {
73520282da2SJoe Wallwork   MPI_Comm       comm;
73620282da2SJoe Wallwork   PetscErrorCode ierr;
73720282da2SJoe Wallwork   PetscFE        fe;
73820282da2SJoe Wallwork   PetscInt       dim;
73920282da2SJoe Wallwork 
74020282da2SJoe Wallwork   PetscFunctionBegin;
74120282da2SJoe Wallwork 
74220282da2SJoe Wallwork   /* Extract metadata from dm */
74320282da2SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
74420282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
74520282da2SJoe Wallwork 
74620282da2SJoe Wallwork   /* Create a P1 field of the requested size */
74720282da2SJoe Wallwork   ierr = PetscFECreateLagrange(comm, dim, size, PETSC_TRUE, 1, PETSC_DETERMINE, &fe);CHKERRQ(ierr);
74820282da2SJoe Wallwork   ierr = DMSetField(dm, f, NULL, (PetscObject)fe);CHKERRQ(ierr);
74920282da2SJoe Wallwork   ierr = DMCreateDS(dm);CHKERRQ(ierr);
75020282da2SJoe Wallwork   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
75120282da2SJoe Wallwork   ierr = DMCreateLocalVector(dm, metric);CHKERRQ(ierr);
75220282da2SJoe Wallwork 
75320282da2SJoe Wallwork   PetscFunctionReturn(0);
75420282da2SJoe Wallwork }
75520282da2SJoe Wallwork 
75620282da2SJoe Wallwork /*
75720282da2SJoe Wallwork   DMPlexMetricCreate - Create a Riemannian metric field
75820282da2SJoe Wallwork 
75920282da2SJoe Wallwork   Input parameters:
76020282da2SJoe Wallwork + dm     - The DM
76120282da2SJoe Wallwork - f      - The field number to use
76220282da2SJoe Wallwork 
76320282da2SJoe Wallwork   Output parameter:
76420282da2SJoe Wallwork . metric - The metric
76520282da2SJoe Wallwork 
76620282da2SJoe Wallwork   Level: beginner
76720282da2SJoe Wallwork 
76831b70465SJoe Wallwork   Notes:
76931b70465SJoe Wallwork 
77031b70465SJoe Wallwork   It is assumed that the DM is comprised of simplices.
77131b70465SJoe Wallwork 
77231b70465SJoe Wallwork   Command line options for Riemannian metrics:
77331b70465SJoe Wallwork 
77431b70465SJoe Wallwork   -dm_plex_metric_isotropic                 - Is the metric isotropic?
77531b70465SJoe Wallwork   -dm_plex_metric_restrict_anisotropy_first - Should anisotropy be restricted before normalization?
77631b70465SJoe Wallwork   -dm_plex_metric_h_min                     - Minimum tolerated metric magnitude
77731b70465SJoe Wallwork   -dm_plex_metric_h_max                     - Maximum tolerated metric magnitude
77831b70465SJoe Wallwork   -dm_plex_metric_a_max                     - Maximum tolerated anisotropy
77931b70465SJoe Wallwork   -dm_plex_metric_p                         - L-p normalization order
78031b70465SJoe Wallwork   -dm_plex_metric_target_complexity         - Target metric complexity
78120282da2SJoe Wallwork 
78220282da2SJoe Wallwork .seealso: DMPlexMetricCreateUniform(), DMPlexMetricCreateIsotropic()
78320282da2SJoe Wallwork */
78420282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreate(DM dm, PetscInt f, Vec *metric)
78520282da2SJoe Wallwork {
78631b70465SJoe Wallwork   DM_Plex       *plex = (DM_Plex *) dm->data;
78720282da2SJoe Wallwork   PetscErrorCode ierr;
78820282da2SJoe Wallwork   PetscInt       coordDim, Nd;
78920282da2SJoe Wallwork 
79020282da2SJoe Wallwork   PetscFunctionBegin;
79131b70465SJoe Wallwork   if (!plex->metricCtx) {
79231b70465SJoe Wallwork     ierr = PetscNew(&plex->metricCtx);CHKERRQ(ierr);
79331b70465SJoe Wallwork     ierr = DMPlexMetricSetFromOptions(dm);CHKERRQ(ierr);
79431b70465SJoe Wallwork   }
79520282da2SJoe Wallwork   ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr);
79620282da2SJoe Wallwork   Nd = coordDim*coordDim;
79720282da2SJoe Wallwork   ierr = DMPlexP1FieldCreate_Private(dm, f, Nd, metric);CHKERRQ(ierr);
79820282da2SJoe Wallwork   PetscFunctionReturn(0);
79920282da2SJoe Wallwork }
80020282da2SJoe Wallwork 
80120282da2SJoe Wallwork typedef struct {
80220282da2SJoe Wallwork   PetscReal scaling;  /* Scaling for uniform metric diagonal */
80320282da2SJoe Wallwork } DMPlexMetricUniformCtx;
80420282da2SJoe Wallwork 
80520282da2SJoe Wallwork static PetscErrorCode diagonal(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
80620282da2SJoe Wallwork {
80720282da2SJoe Wallwork   DMPlexMetricUniformCtx *user = (DMPlexMetricUniformCtx*)ctx;
80820282da2SJoe Wallwork   PetscInt                i, j;
80920282da2SJoe Wallwork 
81020282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
81120282da2SJoe Wallwork     for (j = 0; j < dim; ++j) {
81220282da2SJoe Wallwork       if (i == j) u[i+dim*j] = user->scaling;
81320282da2SJoe Wallwork       else u[i+dim*j] = 0.0;
81420282da2SJoe Wallwork     }
81520282da2SJoe Wallwork   }
81620282da2SJoe Wallwork   return 0;
81720282da2SJoe Wallwork }
81820282da2SJoe Wallwork 
81920282da2SJoe Wallwork /*
82020282da2SJoe Wallwork   DMPlexMetricCreateUniform - Construct a uniform isotropic metric
82120282da2SJoe Wallwork 
82220282da2SJoe Wallwork   Input parameters:
82320282da2SJoe Wallwork + dm     - The DM
82420282da2SJoe Wallwork . f      - The field number to use
82520282da2SJoe Wallwork - alpha  - Scaling parameter for the diagonal
82620282da2SJoe Wallwork 
82720282da2SJoe Wallwork   Output parameter:
82820282da2SJoe Wallwork . metric - The uniform metric
82920282da2SJoe Wallwork 
83020282da2SJoe Wallwork   Level: beginner
83120282da2SJoe Wallwork 
83220282da2SJoe Wallwork   Note: It is assumed that the DM is comprised of simplices.
83320282da2SJoe Wallwork 
83420282da2SJoe Wallwork .seealso: DMPlexMetricCreate(), DMPlexMetricCreateIsotropic()
83520282da2SJoe Wallwork */
83620282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateUniform(DM dm, PetscInt f, PetscReal alpha, Vec *metric)
83720282da2SJoe Wallwork {
83820282da2SJoe Wallwork   DMPlexMetricUniformCtx user;
83920282da2SJoe Wallwork   PetscErrorCode       (*funcs[1])(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *);
84020282da2SJoe Wallwork   PetscErrorCode         ierr;
84120282da2SJoe Wallwork   void                  *ctxs[1];
84220282da2SJoe Wallwork 
84320282da2SJoe Wallwork   PetscFunctionBegin;
84420282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr);
84520282da2SJoe Wallwork   if (!alpha) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling is undefined");
84620282da2SJoe Wallwork   if (alpha < 1.0e-30) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Uniform metric scaling %e should be positive", alpha);
84720282da2SJoe Wallwork   else user.scaling = alpha;
84820282da2SJoe Wallwork   funcs[0] = diagonal;
84920282da2SJoe Wallwork   ctxs[0] = &user;
85020282da2SJoe Wallwork   ierr = DMProjectFunctionLocal(dm, 0.0, funcs, ctxs, INSERT_ALL_VALUES, *metric);CHKERRQ(ierr);
85120282da2SJoe Wallwork   PetscFunctionReturn(0);
85220282da2SJoe Wallwork }
85320282da2SJoe Wallwork 
85420282da2SJoe Wallwork /*
85520282da2SJoe Wallwork   DMPlexMetricCreateIsotropic - Construct an isotropic metric from an error indicator
85620282da2SJoe Wallwork 
85720282da2SJoe Wallwork   Input parameters:
85820282da2SJoe Wallwork + dm        - The DM
85920282da2SJoe Wallwork . f         - The field number to use
86020282da2SJoe Wallwork - indicator - The error indicator
86120282da2SJoe Wallwork 
86220282da2SJoe Wallwork   Output parameter:
86320282da2SJoe Wallwork . metric    - The isotropic metric
86420282da2SJoe Wallwork 
86520282da2SJoe Wallwork   Level: beginner
86620282da2SJoe Wallwork 
86720282da2SJoe Wallwork   Notes:
86820282da2SJoe Wallwork 
86920282da2SJoe Wallwork   It is assumed that the DM is comprised of simplices.
87020282da2SJoe Wallwork 
87120282da2SJoe Wallwork   The indicator needs to be a scalar field defined at *vertices*.
87220282da2SJoe Wallwork 
87320282da2SJoe Wallwork .seealso: DMPlexMetricCreate(), DMPlexMetricCreateUniform()
87420282da2SJoe Wallwork */
87520282da2SJoe Wallwork PetscErrorCode DMPlexMetricCreateIsotropic(DM dm, PetscInt f, Vec indicator, Vec *metric)
87620282da2SJoe Wallwork {
87720282da2SJoe Wallwork   DM                 dmIndi;
87820282da2SJoe Wallwork   PetscErrorCode     ierr;
87920282da2SJoe Wallwork   PetscInt           dim, d, vStart, vEnd, v;
88020282da2SJoe Wallwork   const PetscScalar *indi;
88120282da2SJoe Wallwork   PetscScalar       *met;
88220282da2SJoe Wallwork 
88320282da2SJoe Wallwork   PetscFunctionBegin;
88420282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
88520282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, f, metric);CHKERRQ(ierr);
88620282da2SJoe Wallwork   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
88720282da2SJoe Wallwork   ierr = VecGetArrayRead(indicator, &indi);CHKERRQ(ierr);
88820282da2SJoe Wallwork   ierr = VecGetArrayWrite(*metric, &met);CHKERRQ(ierr);
88920282da2SJoe Wallwork   ierr = VecGetDM(indicator, &dmIndi);CHKERRQ(ierr);
89020282da2SJoe Wallwork   for (v = vStart; v < vEnd; ++v) {
89120282da2SJoe Wallwork     PetscScalar *vindi, *vmet;
89220282da2SJoe Wallwork     ierr = DMPlexPointLocalRead(dmIndi, v, indi, &vindi);CHKERRQ(ierr);
89320282da2SJoe Wallwork     ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr);
89420282da2SJoe Wallwork     for (d = 0; d < dim; ++d) vmet[d*(dim+1)] = vindi[0];
89520282da2SJoe Wallwork   }
89620282da2SJoe Wallwork   ierr = VecRestoreArrayWrite(*metric, &met);CHKERRQ(ierr);
89720282da2SJoe Wallwork   ierr = VecRestoreArrayRead(indicator, &indi);CHKERRQ(ierr);
89820282da2SJoe Wallwork   PetscFunctionReturn(0);
89920282da2SJoe Wallwork }
90020282da2SJoe Wallwork 
90120282da2SJoe Wallwork static PetscErrorCode DMPlexMetricModify_Private(PetscInt dim, PetscReal h_min, PetscReal h_max, PetscReal a_max, PetscScalar Mp[])
90220282da2SJoe Wallwork {
90320282da2SJoe Wallwork   PetscErrorCode ierr;
90420282da2SJoe Wallwork   PetscInt       i, j, k;
90520282da2SJoe 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);
90620282da2SJoe Wallwork   PetscScalar   *Mpos;
90720282da2SJoe Wallwork 
90820282da2SJoe Wallwork   PetscFunctionBegin;
90920282da2SJoe Wallwork   ierr = PetscMalloc2(dim*dim, &Mpos, dim, &eigs);CHKERRQ(ierr);
91020282da2SJoe Wallwork 
91120282da2SJoe Wallwork   /* Symmetrize */
91220282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
91320282da2SJoe Wallwork     Mpos[i*dim+i] = Mp[i*dim+i];
91420282da2SJoe Wallwork     for (j = i+1; j < dim; ++j) {
91520282da2SJoe Wallwork       Mpos[i*dim+j] = 0.5*(Mp[i*dim+j] + Mp[j*dim+i]);
91620282da2SJoe Wallwork       Mpos[j*dim+i] = Mpos[i*dim+j];
91720282da2SJoe Wallwork     }
91820282da2SJoe Wallwork   }
91920282da2SJoe Wallwork 
92020282da2SJoe Wallwork   /* Compute eigendecomposition */
92120282da2SJoe Wallwork   {
92220282da2SJoe Wallwork     PetscScalar  *work;
92320282da2SJoe Wallwork     PetscBLASInt lwork;
92420282da2SJoe Wallwork 
92520282da2SJoe Wallwork     lwork = 5*dim;
92620282da2SJoe Wallwork     ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr);
92720282da2SJoe Wallwork     {
92820282da2SJoe Wallwork       PetscBLASInt lierr;
92920282da2SJoe Wallwork       PetscBLASInt nb;
93020282da2SJoe Wallwork 
93120282da2SJoe Wallwork       ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr);
93220282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
93320282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
93420282da2SJoe Wallwork       {
93520282da2SJoe Wallwork         PetscReal *rwork;
93620282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
93720282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,rwork,&lierr));
93820282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
93920282da2SJoe Wallwork       }
94020282da2SJoe Wallwork #else
94120282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev",LAPACKsyev_("V","U",&nb,Mpos,&nb,eigs,work,&lwork,&lierr));
94220282da2SJoe Wallwork #endif
94320282da2SJoe Wallwork       if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
94420282da2SJoe Wallwork       ierr = PetscFPTrapPop();CHKERRQ(ierr);
94520282da2SJoe Wallwork     }
94620282da2SJoe Wallwork     ierr = PetscFree(work);CHKERRQ(ierr);
94720282da2SJoe Wallwork   }
94820282da2SJoe Wallwork 
94920282da2SJoe Wallwork   /* Reflect to positive orthant and enforce maximum and minimum size */
95020282da2SJoe Wallwork   max_eig = 0.0;
95120282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
95220282da2SJoe Wallwork     eigs[i] = PetscMin(l_max, PetscMax(l_min, PetscAbsReal(eigs[i])));
95320282da2SJoe Wallwork     max_eig = PetscMax(eigs[i], max_eig);
95420282da2SJoe Wallwork   }
95520282da2SJoe Wallwork 
95620282da2SJoe Wallwork   /* Enforce maximum anisotropy */
95720282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
95820282da2SJoe Wallwork     if (a_max > 1.0) eigs[i] = PetscMax(eigs[i], max_eig*la_min);
95920282da2SJoe Wallwork   }
96020282da2SJoe Wallwork 
96120282da2SJoe Wallwork   /* Reconstruct Hessian */
96220282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
96320282da2SJoe Wallwork     for (j = 0; j < dim; ++j) {
96420282da2SJoe Wallwork       Mp[i*dim+j] = 0.0;
96520282da2SJoe Wallwork       for (k = 0; k < dim; ++k) {
96620282da2SJoe Wallwork         Mp[i*dim+j] += Mpos[k*dim+i] * eigs[k] * Mpos[k*dim+j];
96720282da2SJoe Wallwork       }
96820282da2SJoe Wallwork     }
96920282da2SJoe Wallwork   }
97020282da2SJoe Wallwork   ierr = PetscFree2(Mpos, eigs);CHKERRQ(ierr);
97120282da2SJoe Wallwork 
97220282da2SJoe Wallwork   PetscFunctionReturn(0);
97320282da2SJoe Wallwork }
97420282da2SJoe Wallwork 
97520282da2SJoe Wallwork /*
97620282da2SJoe Wallwork   DMPlexMetricEnforceSPD - Enforce symmetric positive-definiteness of a metric
97720282da2SJoe Wallwork 
97820282da2SJoe Wallwork   Input parameters:
97920282da2SJoe Wallwork + dm                 - The DM
98099abec2bSJoe Wallwork . restrictSizes      - Should maximum/minimum metric magnitudes be enforced?
98199abec2bSJoe Wallwork . restrictAnisotropy - Should maximum anisotropy be enforced?
98220282da2SJoe Wallwork - metric             - The metric
98320282da2SJoe Wallwork 
98420282da2SJoe Wallwork   Output parameter:
98520282da2SJoe Wallwork . metric             - The metric
98620282da2SJoe Wallwork 
98720282da2SJoe Wallwork   Level: beginner
98820282da2SJoe Wallwork 
98920282da2SJoe Wallwork .seealso: DMPlexMetricNormalize(), DMPlexMetricIntersection()
99020282da2SJoe Wallwork */
99199abec2bSJoe Wallwork PetscErrorCode DMPlexMetricEnforceSPD(DM dm, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec metric)
99220282da2SJoe Wallwork {
99320282da2SJoe Wallwork   PetscErrorCode ierr;
99420282da2SJoe Wallwork   PetscInt       dim, vStart, vEnd, v;
99520282da2SJoe Wallwork   PetscScalar   *met;
99620282da2SJoe Wallwork   PetscReal      h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0;
99720282da2SJoe Wallwork 
99820282da2SJoe Wallwork   PetscFunctionBegin;
99920282da2SJoe Wallwork 
100020282da2SJoe Wallwork   /* Extract metadata from dm */
100120282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
100220282da2SJoe Wallwork   if (restrictSizes) {
100399abec2bSJoe Wallwork     ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr);
100499abec2bSJoe Wallwork     ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr);
100599abec2bSJoe Wallwork     h_min = PetscMax(h_min, 1.0e-30);
100699abec2bSJoe Wallwork     h_max = PetscMin(h_max, 1.0e+30);
100799abec2bSJoe Wallwork     if (h_min >= h_max) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max);
100899abec2bSJoe Wallwork   }
100999abec2bSJoe Wallwork   if (restrictAnisotropy) {
101099abec2bSJoe Wallwork     ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr);
101199abec2bSJoe Wallwork     a_max = PetscMin(a_max, 1.0e+30);
101220282da2SJoe Wallwork   }
101320282da2SJoe Wallwork 
101420282da2SJoe Wallwork   /* Enforce SPD */
101520282da2SJoe Wallwork   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
101620282da2SJoe Wallwork   ierr = VecGetArray(metric, &met);CHKERRQ(ierr);
101720282da2SJoe Wallwork   for (v = vStart; v < vEnd; ++v) {
101820282da2SJoe Wallwork     PetscScalar *vmet;
101920282da2SJoe Wallwork     ierr = DMPlexPointLocalRef(dm, v, met, &vmet);CHKERRQ(ierr);
102020282da2SJoe Wallwork     ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, vmet);CHKERRQ(ierr);
102120282da2SJoe Wallwork   }
102220282da2SJoe Wallwork   ierr = VecRestoreArray(metric, &met);CHKERRQ(ierr);
102320282da2SJoe Wallwork 
102420282da2SJoe Wallwork   PetscFunctionReturn(0);
102520282da2SJoe Wallwork }
102620282da2SJoe Wallwork 
102720282da2SJoe Wallwork static void detMFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
102820282da2SJoe Wallwork                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
102920282da2SJoe Wallwork                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
103020282da2SJoe Wallwork                      PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
103120282da2SJoe Wallwork {
103220282da2SJoe Wallwork   const PetscScalar p = constants[0];
103320282da2SJoe Wallwork   PetscReal         detH = 0.0;
103420282da2SJoe Wallwork 
103520282da2SJoe Wallwork   if      (dim == 2) DMPlex_Det2D_Scalar_Internal(&detH, u);
103620282da2SJoe Wallwork   else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detH, u);
103720282da2SJoe Wallwork   f0[0] = PetscPowReal(detH, p/(2.0*p + dim));
103820282da2SJoe Wallwork }
103920282da2SJoe Wallwork 
104020282da2SJoe Wallwork /*
104120282da2SJoe Wallwork   DMPlexMetricNormalize - Apply L-p normalization to a metric
104220282da2SJoe Wallwork 
104320282da2SJoe Wallwork   Input parameters:
104420282da2SJoe Wallwork + dm                 - The DM
104520282da2SJoe Wallwork . metricIn           - The unnormalized metric
104616522936SJoe Wallwork . restrictSizes      - Should maximum/minimum metric magnitudes be enforced?
104716522936SJoe Wallwork - restrictAnisotropy - Should maximum metric anisotropy be enforced?
104820282da2SJoe Wallwork 
104920282da2SJoe Wallwork   Output parameter:
105020282da2SJoe Wallwork . metricOut          - The normalized metric
105120282da2SJoe Wallwork 
105220282da2SJoe Wallwork   Level: beginner
105320282da2SJoe Wallwork 
105420282da2SJoe Wallwork .seealso: DMPlexMetricEnforceSPD(), DMPlexMetricIntersection()
105520282da2SJoe Wallwork */
105616522936SJoe Wallwork PetscErrorCode DMPlexMetricNormalize(DM dm, Vec metricIn, PetscBool restrictSizes, PetscBool restrictAnisotropy, Vec *metricOut)
105720282da2SJoe Wallwork {
105820282da2SJoe Wallwork   MPI_Comm         comm;
105916522936SJoe Wallwork   PetscBool        restrictAnisotropyFirst;
106020282da2SJoe Wallwork   PetscDS          ds;
106120282da2SJoe Wallwork   PetscErrorCode   ierr;
106220282da2SJoe Wallwork   PetscInt         dim, Nd, vStart, vEnd, v, i;
106320282da2SJoe Wallwork   PetscScalar     *met, integral, constants[1];
106420282da2SJoe Wallwork   PetscReal        p, h_min = 1.0e-30, h_max = 1.0e+30, a_max = 0.0, factGlob, target;
106520282da2SJoe Wallwork 
106620282da2SJoe Wallwork   PetscFunctionBegin;
106720282da2SJoe Wallwork 
106820282da2SJoe Wallwork   /* Extract metadata from dm */
106920282da2SJoe Wallwork   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
107020282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
107120282da2SJoe Wallwork   Nd = dim*dim;
107220282da2SJoe Wallwork 
107320282da2SJoe Wallwork   /* Set up metric and ensure it is SPD */
107420282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricOut);CHKERRQ(ierr);
107520282da2SJoe Wallwork   ierr = VecCopy(metricIn, *metricOut);CHKERRQ(ierr);
107616522936SJoe Wallwork   ierr = DMPlexMetricRestrictAnisotropyFirst(dm, &restrictAnisotropyFirst);CHKERRQ(ierr);
107716522936SJoe Wallwork   ierr = DMPlexMetricEnforceSPD(dm, PETSC_FALSE, (PetscBool)(restrictAnisotropy && restrictAnisotropyFirst), *metricOut);CHKERRQ(ierr);
107820282da2SJoe Wallwork 
107920282da2SJoe Wallwork   /* Compute global normalization factor */
108016522936SJoe Wallwork   ierr = DMPlexMetricGetTargetComplexity(dm, &target);CHKERRQ(ierr);
108116522936SJoe Wallwork   ierr = DMPlexMetricGetNormalizationOrder(dm, &p);CHKERRQ(ierr);
108216522936SJoe Wallwork   constants[0] = p;
108320282da2SJoe Wallwork   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
108420282da2SJoe Wallwork   ierr = PetscDSSetConstants(ds, 1, constants);CHKERRQ(ierr);
108520282da2SJoe Wallwork   ierr = PetscDSSetObjective(ds, 0, detMFunc);CHKERRQ(ierr);
108620282da2SJoe Wallwork   ierr = DMPlexComputeIntegralFEM(dm, *metricOut, &integral, NULL);CHKERRQ(ierr);
108720282da2SJoe Wallwork   factGlob = PetscPowReal(target/PetscRealPart(integral), 2.0/dim);
108820282da2SJoe Wallwork 
108920282da2SJoe Wallwork   /* Apply local scaling */
109020282da2SJoe Wallwork   if (restrictSizes) {
109116522936SJoe Wallwork     ierr = DMPlexMetricGetMinimumMagnitude(dm, &h_min);CHKERRQ(ierr);
109216522936SJoe Wallwork     ierr = DMPlexMetricGetMaximumMagnitude(dm, &h_max);CHKERRQ(ierr);
109316522936SJoe Wallwork     h_min = PetscMax(h_min, 1.0e-30);
109416522936SJoe Wallwork     h_max = PetscMin(h_max, 1.0e+30);
109516522936SJoe Wallwork     if (h_min >= h_max) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Incompatible min/max metric magnitudes (%.4e not smaller than %.4e)", h_min, h_max);
109616522936SJoe Wallwork   }
109716522936SJoe Wallwork   if (restrictAnisotropy && !restrictAnisotropyFirst) {
109816522936SJoe Wallwork     ierr = DMPlexMetricGetMaximumAnisotropy(dm, &a_max);CHKERRQ(ierr);
109916522936SJoe Wallwork     a_max = PetscMin(a_max, 1.0e+30);
110020282da2SJoe Wallwork   }
110120282da2SJoe Wallwork   ierr = VecGetArray(*metricOut, &met);CHKERRQ(ierr);
110216522936SJoe Wallwork   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
110320282da2SJoe Wallwork   for (v = vStart; v < vEnd; ++v) {
110420282da2SJoe Wallwork     PetscScalar *Mp;
110520282da2SJoe Wallwork     PetscReal    detM, fact;
110620282da2SJoe Wallwork 
110720282da2SJoe Wallwork     ierr = DMPlexPointLocalRef(dm, v, met, &Mp);CHKERRQ(ierr);
110820282da2SJoe Wallwork     if      (dim == 2) DMPlex_Det2D_Scalar_Internal(&detM, Mp);
110920282da2SJoe Wallwork     else if (dim == 3) DMPlex_Det3D_Scalar_Internal(&detM, Mp);
111020282da2SJoe Wallwork     else SETERRQ1(comm, PETSC_ERR_SUP, "Dimension %d not supported", dim);
111120282da2SJoe Wallwork     fact = factGlob * PetscPowReal(PetscAbsReal(detM), -1.0/(2*p+dim));
111220282da2SJoe Wallwork     for (i = 0; i < Nd; ++i) Mp[i] *= fact;
111320282da2SJoe Wallwork     if (restrictSizes) { ierr = DMPlexMetricModify_Private(dim, h_min, h_max, a_max, Mp);CHKERRQ(ierr); }
111420282da2SJoe Wallwork   }
111520282da2SJoe Wallwork   ierr = VecRestoreArray(*metricOut, &met);CHKERRQ(ierr);
111620282da2SJoe Wallwork 
111720282da2SJoe Wallwork   PetscFunctionReturn(0);
111820282da2SJoe Wallwork }
111920282da2SJoe Wallwork 
112020282da2SJoe Wallwork /*
112120282da2SJoe Wallwork   DMPlexMetricAverage - Compute the average of a list of metrics
112220282da2SJoe Wallwork 
112320282da2SJoe Wallwork   Input Parameter:
112420282da2SJoe Wallwork + dm         - The DM
112520282da2SJoe Wallwork . numMetrics - The number of metrics to be averaged
112620282da2SJoe Wallwork . weights    - Weights for the average
112720282da2SJoe Wallwork - metrics    - The metrics to be averaged
112820282da2SJoe Wallwork 
112920282da2SJoe Wallwork   Output Parameter:
113020282da2SJoe Wallwork . metricAvg  - The averaged metric
113120282da2SJoe Wallwork 
113220282da2SJoe Wallwork   Level: beginner
113320282da2SJoe Wallwork 
113420282da2SJoe Wallwork   Notes:
113520282da2SJoe Wallwork   The weights should sum to unity.
113620282da2SJoe Wallwork 
113720282da2SJoe Wallwork   If weights are not provided then an unweighted average is used.
113820282da2SJoe Wallwork 
113920282da2SJoe Wallwork .seealso: DMPlexMetricAverage2(), DMPlexMetricAverage3(), DMPlexMetricIntersection()
114020282da2SJoe Wallwork */
114120282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage(DM dm, PetscInt numMetrics, PetscReal weights[], Vec metrics[], Vec *metricAvg)
114220282da2SJoe Wallwork {
114320282da2SJoe Wallwork   PetscBool      haveWeights = PETSC_TRUE;
114420282da2SJoe Wallwork   PetscErrorCode ierr;
114520282da2SJoe Wallwork   PetscInt       i;
114620282da2SJoe Wallwork   PetscReal      sum = 0.0, tol = 1.0e-10;
114720282da2SJoe Wallwork 
114820282da2SJoe Wallwork   PetscFunctionBegin;
114920282da2SJoe Wallwork   if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot average %d < 1 metrics", numMetrics); }
115020282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricAvg);CHKERRQ(ierr);
115120282da2SJoe Wallwork   ierr = VecSet(*metricAvg, 0.0);CHKERRQ(ierr);
115220282da2SJoe Wallwork 
115320282da2SJoe Wallwork   /* Default to the unweighted case */
115420282da2SJoe Wallwork   if (!weights) {
115520282da2SJoe Wallwork     ierr = PetscMalloc1(numMetrics, &weights);CHKERRQ(ierr);
115620282da2SJoe Wallwork     haveWeights = PETSC_FALSE;
115720282da2SJoe Wallwork     for (i = 0; i < numMetrics; ++i) {weights[i] = 1.0/numMetrics; }
115820282da2SJoe Wallwork   }
115920282da2SJoe Wallwork 
116020282da2SJoe Wallwork   /* Check weights sum to unity */
116120282da2SJoe Wallwork   for (i = 0; i < numMetrics; ++i) { sum += weights[i]; }
116220282da2SJoe Wallwork   if (PetscAbsReal(sum - 1) > tol) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Weights do not sum to unity"); }
116320282da2SJoe Wallwork 
116420282da2SJoe Wallwork   /* Compute metric average */
116520282da2SJoe Wallwork   for (i = 0; i < numMetrics; ++i) { ierr = VecAXPY(*metricAvg, weights[i], metrics[i]);CHKERRQ(ierr); }
116620282da2SJoe Wallwork   if (!haveWeights) {ierr = PetscFree(weights); }
116720282da2SJoe Wallwork   PetscFunctionReturn(0);
116820282da2SJoe Wallwork }
116920282da2SJoe Wallwork 
117020282da2SJoe Wallwork /*
117120282da2SJoe Wallwork   DMPlexMetricAverage2 - Compute the unweighted average of two metrics
117220282da2SJoe Wallwork 
117320282da2SJoe Wallwork   Input Parameter:
117420282da2SJoe Wallwork + dm         - The DM
117520282da2SJoe Wallwork . metric1    - The first metric to be averaged
117620282da2SJoe Wallwork - metric2    - The second metric to be averaged
117720282da2SJoe Wallwork 
117820282da2SJoe Wallwork   Output Parameter:
117920282da2SJoe Wallwork . metricAvg  - The averaged metric
118020282da2SJoe Wallwork 
118120282da2SJoe Wallwork   Level: beginner
118220282da2SJoe Wallwork 
118320282da2SJoe Wallwork .seealso: DMPlexMetricAverage(), DMPlexMetricAverage3()
118420282da2SJoe Wallwork */
118520282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage2(DM dm, Vec metric1, Vec metric2, Vec *metricAvg)
118620282da2SJoe Wallwork {
118720282da2SJoe Wallwork   PetscErrorCode ierr;
118820282da2SJoe Wallwork   PetscReal      weights[2] = {0.5, 0.5};
118920282da2SJoe Wallwork   Vec            metrics[2] = {metric1, metric2};
119020282da2SJoe Wallwork 
119120282da2SJoe Wallwork   PetscFunctionBegin;
119220282da2SJoe Wallwork   ierr = DMPlexMetricAverage(dm, 2, weights, metrics, metricAvg);CHKERRQ(ierr);
119320282da2SJoe Wallwork   PetscFunctionReturn(0);
119420282da2SJoe Wallwork }
119520282da2SJoe Wallwork 
119620282da2SJoe Wallwork /*
119720282da2SJoe Wallwork   DMPlexMetricAverage3 - Compute the unweighted average of three metrics
119820282da2SJoe Wallwork 
119920282da2SJoe Wallwork   Input Parameter:
120020282da2SJoe Wallwork + dm         - The DM
120120282da2SJoe Wallwork . metric1    - The first metric to be averaged
120220282da2SJoe Wallwork . metric2    - The second metric to be averaged
120320282da2SJoe Wallwork - metric3    - The third metric to be averaged
120420282da2SJoe Wallwork 
120520282da2SJoe Wallwork   Output Parameter:
120620282da2SJoe Wallwork . metricAvg  - The averaged metric
120720282da2SJoe Wallwork 
120820282da2SJoe Wallwork   Level: beginner
120920282da2SJoe Wallwork 
121020282da2SJoe Wallwork .seealso: DMPlexMetricAverage(), DMPlexMetricAverage2()
121120282da2SJoe Wallwork */
121220282da2SJoe Wallwork PetscErrorCode DMPlexMetricAverage3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricAvg)
121320282da2SJoe Wallwork {
121420282da2SJoe Wallwork   PetscErrorCode ierr;
121520282da2SJoe Wallwork   PetscReal      weights[3] = {1.0/3.0, 1.0/3.0, 1.0/3.0};
121620282da2SJoe Wallwork   Vec            metrics[3] = {metric1, metric2, metric3};
121720282da2SJoe Wallwork 
121820282da2SJoe Wallwork   PetscFunctionBegin;
121920282da2SJoe Wallwork   ierr = DMPlexMetricAverage(dm, 3, weights, metrics, metricAvg);CHKERRQ(ierr);
122020282da2SJoe Wallwork   PetscFunctionReturn(0);
122120282da2SJoe Wallwork }
122220282da2SJoe Wallwork 
122320282da2SJoe Wallwork static PetscErrorCode DMPlexMetricIntersection_Private(PetscInt dim, PetscScalar M1[], PetscScalar M2[])
122420282da2SJoe Wallwork {
122520282da2SJoe Wallwork   PetscErrorCode ierr;
122620282da2SJoe Wallwork   PetscInt       i, j, k, l, m;
122720282da2SJoe Wallwork   PetscReal     *evals, *evals1;
122820282da2SJoe Wallwork   PetscScalar   *evecs, *sqrtM1, *isqrtM1;
122920282da2SJoe Wallwork 
123020282da2SJoe Wallwork   PetscFunctionBegin;
123120282da2SJoe Wallwork   ierr = PetscMalloc5(dim*dim, &evecs, dim*dim, &sqrtM1, dim*dim, &isqrtM1, dim, &evals, dim, &evals1);CHKERRQ(ierr);
123220282da2SJoe Wallwork   for (i = 0; i < dim; ++i) {
123320282da2SJoe Wallwork     for (j = 0; j < dim; ++j) {
123420282da2SJoe Wallwork       evecs[i*dim+j] = M1[i*dim+j];
123520282da2SJoe Wallwork     }
123620282da2SJoe Wallwork   }
123720282da2SJoe Wallwork   {
123820282da2SJoe Wallwork     PetscScalar *work;
123920282da2SJoe Wallwork     PetscBLASInt lwork;
124020282da2SJoe Wallwork 
124120282da2SJoe Wallwork     lwork = 5*dim;
124220282da2SJoe Wallwork     ierr = PetscMalloc1(5*dim, &work);CHKERRQ(ierr);
124320282da2SJoe Wallwork     {
124420282da2SJoe Wallwork       PetscBLASInt lierr, nb;
124520282da2SJoe Wallwork       PetscReal    sqrtk;
124620282da2SJoe Wallwork 
124720282da2SJoe Wallwork       /* Compute eigendecomposition of M1 */
124820282da2SJoe Wallwork       ierr = PetscBLASIntCast(dim, &nb);CHKERRQ(ierr);
124920282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
125020282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
125120282da2SJoe Wallwork       {
125220282da2SJoe Wallwork         PetscReal *rwork;
125320282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
125420282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, rwork, &lierr));
125520282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
125620282da2SJoe Wallwork       }
125720282da2SJoe Wallwork #else
125820282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals1, work, &lwork, &lierr));
125920282da2SJoe Wallwork #endif
126020282da2SJoe Wallwork       if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
126120282da2SJoe Wallwork       ierr = PetscFPTrapPop();
126220282da2SJoe Wallwork 
126320282da2SJoe Wallwork       /* Compute square root and reciprocal */
126420282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
126520282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
126620282da2SJoe Wallwork           sqrtM1[i*dim+j] = 0.0;
126720282da2SJoe Wallwork           isqrtM1[i*dim+j] = 0.0;
126820282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
126920282da2SJoe Wallwork             sqrtk = PetscSqrtReal(evals1[k]);
127020282da2SJoe Wallwork             sqrtM1[i*dim+j] += evecs[k*dim+i] * sqrtk * evecs[k*dim+j];
127120282da2SJoe Wallwork             isqrtM1[i*dim+j] += evecs[k*dim+i] * (1.0/sqrtk) * evecs[k*dim+j];
127220282da2SJoe Wallwork           }
127320282da2SJoe Wallwork         }
127420282da2SJoe Wallwork       }
127520282da2SJoe Wallwork 
127620282da2SJoe Wallwork       /* Map into the space spanned by the eigenvectors of M1 */
127720282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
127820282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
127920282da2SJoe Wallwork           evecs[i*dim+j] = 0.0;
128020282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
128120282da2SJoe Wallwork             for (l = 0; l < dim; ++l) {
128220282da2SJoe Wallwork               evecs[i*dim+j] += isqrtM1[i*dim+k] * M2[l*dim+k] * isqrtM1[j*dim+l];
128320282da2SJoe Wallwork             }
128420282da2SJoe Wallwork           }
128520282da2SJoe Wallwork         }
128620282da2SJoe Wallwork       }
128720282da2SJoe Wallwork 
128820282da2SJoe Wallwork       /* Compute eigendecomposition */
128920282da2SJoe Wallwork       ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
129020282da2SJoe Wallwork #if defined(PETSC_USE_COMPLEX)
129120282da2SJoe Wallwork       {
129220282da2SJoe Wallwork         PetscReal *rwork;
129320282da2SJoe Wallwork         ierr = PetscMalloc1(3*dim, &rwork);CHKERRQ(ierr);
129420282da2SJoe Wallwork         PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, rwork, &lierr));
129520282da2SJoe Wallwork         ierr = PetscFree(rwork);CHKERRQ(ierr);
129620282da2SJoe Wallwork       }
129720282da2SJoe Wallwork #else
129820282da2SJoe Wallwork       PetscStackCallBLAS("LAPACKsyev", LAPACKsyev_("V", "U", &nb, evecs, &nb, evals, work, &lwork, &lierr));
129920282da2SJoe Wallwork #endif
130020282da2SJoe Wallwork       if (lierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int) lierr);
130120282da2SJoe Wallwork       ierr = PetscFPTrapPop();
130220282da2SJoe Wallwork 
130320282da2SJoe Wallwork       /* Modify eigenvalues */
130420282da2SJoe Wallwork       for (i = 0; i < dim; ++i) evals[i] = PetscMin(evals[i], evals1[i]);
130520282da2SJoe Wallwork 
130620282da2SJoe Wallwork       /* Map back to get the intersection */
130720282da2SJoe Wallwork       for (i = 0; i < dim; ++i) {
130820282da2SJoe Wallwork         for (j = 0; j < dim; ++j) {
130920282da2SJoe Wallwork           M2[i*dim+j] = 0.0;
131020282da2SJoe Wallwork           for (k = 0; k < dim; ++k) {
131120282da2SJoe Wallwork             for (l = 0; l < dim; ++l) {
131220282da2SJoe Wallwork               for (m = 0; m < dim; ++m) {
131320282da2SJoe Wallwork                 M2[i*dim+j] += sqrtM1[i*dim+k] * evecs[l*dim+k] * evals[l] * evecs[l*dim+m] * sqrtM1[j*dim+m];
131420282da2SJoe Wallwork               }
131520282da2SJoe Wallwork             }
131620282da2SJoe Wallwork           }
131720282da2SJoe Wallwork         }
131820282da2SJoe Wallwork       }
131920282da2SJoe Wallwork     }
132020282da2SJoe Wallwork     ierr = PetscFree(work);CHKERRQ(ierr);
132120282da2SJoe Wallwork   }
132220282da2SJoe Wallwork   ierr = PetscFree5(evecs, sqrtM1, isqrtM1, evals, evals1);CHKERRQ(ierr);
132320282da2SJoe Wallwork   PetscFunctionReturn(0);
132420282da2SJoe Wallwork }
132520282da2SJoe Wallwork 
132620282da2SJoe Wallwork /*
132720282da2SJoe Wallwork   DMPlexMetricIntersection - Compute the intersection of a list of metrics
132820282da2SJoe Wallwork 
132920282da2SJoe Wallwork   Input Parameter:
133020282da2SJoe Wallwork + dm         - The DM
133120282da2SJoe Wallwork . numMetrics - The number of metrics to be intersected
133220282da2SJoe Wallwork - metrics    - The metrics to be intersected
133320282da2SJoe Wallwork 
133420282da2SJoe Wallwork   Output Parameter:
133520282da2SJoe Wallwork . metricInt  - The intersected metric
133620282da2SJoe Wallwork 
133720282da2SJoe Wallwork   Level: beginner
133820282da2SJoe Wallwork 
133920282da2SJoe Wallwork   Notes:
134020282da2SJoe Wallwork 
134120282da2SJoe Wallwork   The intersection of a list of metrics has the maximal ellipsoid which fits within the ellipsoids of the component metrics.
134220282da2SJoe Wallwork 
134320282da2SJoe Wallwork   The implementation used here is only consistent with the maximal ellipsoid definition in the case numMetrics = 2.
134420282da2SJoe Wallwork 
134520282da2SJoe Wallwork .seealso: DMPlexMetricIntersection2(), DMPlexMetricIntersection3(), DMPlexMetricAverage()
134620282da2SJoe Wallwork */
134720282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection(DM dm, PetscInt numMetrics, Vec metrics[], Vec *metricInt)
134820282da2SJoe Wallwork {
134920282da2SJoe Wallwork   PetscErrorCode ierr;
135020282da2SJoe Wallwork   PetscInt       dim, vStart, vEnd, v, i;
135120282da2SJoe Wallwork   PetscScalar   *met, *meti, *M, *Mi;
135220282da2SJoe Wallwork 
135320282da2SJoe Wallwork   PetscFunctionBegin;
135420282da2SJoe Wallwork   if (numMetrics < 1) { SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot intersect %d < 1 metrics", numMetrics); }
135520282da2SJoe Wallwork 
135620282da2SJoe Wallwork   /* Extract metadata from dm */
135720282da2SJoe Wallwork   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
135820282da2SJoe Wallwork   ierr = DMPlexMetricCreate(dm, 0, metricInt);CHKERRQ(ierr);
135920282da2SJoe Wallwork   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
136020282da2SJoe Wallwork 
136120282da2SJoe Wallwork   /* Copy over the first metric */
136220282da2SJoe Wallwork   ierr = VecCopy(metrics[0], *metricInt);CHKERRQ(ierr);
136320282da2SJoe Wallwork 
136420282da2SJoe Wallwork   /* Intersect subsequent metrics in turn */
136520282da2SJoe Wallwork   if (numMetrics > 1) {
136620282da2SJoe Wallwork     ierr = VecGetArray(*metricInt, &met);CHKERRQ(ierr);
136720282da2SJoe Wallwork     for (i = 1; i < numMetrics; ++i) {
136820282da2SJoe Wallwork       ierr = VecGetArray(metrics[i], &meti);CHKERRQ(ierr);
136920282da2SJoe Wallwork       for (v = vStart; v < vEnd; ++v) {
137020282da2SJoe Wallwork         ierr = DMPlexPointLocalRef(dm, v, met, &M);CHKERRQ(ierr);
137120282da2SJoe Wallwork         ierr = DMPlexPointLocalRef(dm, v, meti, &Mi);CHKERRQ(ierr);
137220282da2SJoe Wallwork         ierr = DMPlexMetricIntersection_Private(dim, Mi, M);CHKERRQ(ierr);
137320282da2SJoe Wallwork       }
137420282da2SJoe Wallwork       ierr = VecRestoreArray(metrics[i], &meti);CHKERRQ(ierr);
137520282da2SJoe Wallwork     }
137620282da2SJoe Wallwork     ierr = VecRestoreArray(*metricInt, &met);CHKERRQ(ierr);
137720282da2SJoe Wallwork   }
137820282da2SJoe Wallwork 
137920282da2SJoe Wallwork   PetscFunctionReturn(0);
138020282da2SJoe Wallwork }
138120282da2SJoe Wallwork 
138220282da2SJoe Wallwork /*
138320282da2SJoe Wallwork   DMPlexMetricIntersection2 - Compute the intersection of two metrics
138420282da2SJoe Wallwork 
138520282da2SJoe Wallwork   Input Parameter:
138620282da2SJoe Wallwork + dm        - The DM
138720282da2SJoe Wallwork . metric1   - The first metric to be intersected
138820282da2SJoe Wallwork - metric2   - The second metric to be intersected
138920282da2SJoe Wallwork 
139020282da2SJoe Wallwork   Output Parameter:
139120282da2SJoe Wallwork . metricInt - The intersected metric
139220282da2SJoe Wallwork 
139320282da2SJoe Wallwork   Level: beginner
139420282da2SJoe Wallwork 
139520282da2SJoe Wallwork .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection3()
139620282da2SJoe Wallwork */
139720282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection2(DM dm, Vec metric1, Vec metric2, Vec *metricInt)
139820282da2SJoe Wallwork {
139920282da2SJoe Wallwork   PetscErrorCode ierr;
140020282da2SJoe Wallwork   Vec            metrics[2] = {metric1, metric2};
140120282da2SJoe Wallwork 
140220282da2SJoe Wallwork   PetscFunctionBegin;
140320282da2SJoe Wallwork   ierr = DMPlexMetricIntersection(dm, 2, metrics, metricInt);CHKERRQ(ierr);
140420282da2SJoe Wallwork   PetscFunctionReturn(0);
140520282da2SJoe Wallwork }
140620282da2SJoe Wallwork 
140720282da2SJoe Wallwork /*
140820282da2SJoe Wallwork   DMPlexMetricIntersection3 - Compute the intersection of three metrics
140920282da2SJoe Wallwork 
141020282da2SJoe Wallwork   Input Parameter:
141120282da2SJoe Wallwork + dm        - The DM
141220282da2SJoe Wallwork . metric1   - The first metric to be intersected
141320282da2SJoe Wallwork . metric2   - The second metric to be intersected
141420282da2SJoe Wallwork - metric3   - The third metric to be intersected
141520282da2SJoe Wallwork 
141620282da2SJoe Wallwork   Output Parameter:
141720282da2SJoe Wallwork . metricInt - The intersected metric
141820282da2SJoe Wallwork 
141920282da2SJoe Wallwork   Level: beginner
142020282da2SJoe Wallwork 
142120282da2SJoe Wallwork .seealso: DMPlexMetricIntersection(), DMPlexMetricIntersection2()
142220282da2SJoe Wallwork */
142320282da2SJoe Wallwork PetscErrorCode DMPlexMetricIntersection3(DM dm, Vec metric1, Vec metric2, Vec metric3, Vec *metricInt)
142420282da2SJoe Wallwork {
142520282da2SJoe Wallwork   PetscErrorCode ierr;
142620282da2SJoe Wallwork   Vec            metrics[3] = {metric1, metric2, metric3};
142720282da2SJoe Wallwork 
142820282da2SJoe Wallwork   PetscFunctionBegin;
142920282da2SJoe Wallwork   ierr = DMPlexMetricIntersection(dm, 3, metrics, metricInt);CHKERRQ(ierr);
143020282da2SJoe Wallwork   PetscFunctionReturn(0);
143120282da2SJoe Wallwork }
1432