MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
mesh-optimizer.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// --------------------------------------------------
13// Mesh Optimizer Miniapp: Optimize high-order meshes
14// --------------------------------------------------
15//
16// This miniapp performs mesh optimization using the Target-Matrix Optimization
17// Paradigm (TMOP) by P.Knupp et al., and a global variational minimization
18// approach. It minimizes the quantity sum_T int_T mu(J(x)), where T are the
19// target (ideal) elements, J is the Jacobian of the transformation from the
20// target to the physical element, and mu is the mesh quality metric. This
21// metric can measure shape, size or alignment of the region around each
22// quadrature point. The combination of targets & quality metrics is used to
23// optimize the physical node positions, i.e., they must be as close as possible
24// to the shape / size / alignment of their targets. This code also demonstrates
25// a possible use of nonlinear operators (the class TMOP_QualityMetric, defining
26// mu(J), and the class TMOP_Integrator, defining int mu(J)), as well as their
27// coupling to Newton methods for solving minimization problems. Note that the
28// utilized Newton methods are oriented towards avoiding invalid meshes with
29// negative Jacobian determinants. Each Newton step requires the inversion of a
30// Jacobian matrix, which is done through an inner linear solver.
31//
32// Compile with: make mesh-optimizer
33//
34// Sample runs:
35// Adapted analytic shape:
36// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -bnd -qt 1 -qo 8
37// Adapted analytic size+orientation:
38// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -bnd -qt 1 -qo 8
39// Adapted analytic shape+orientation:
40// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -bnd -qt 1 -qo 8 -fd
41//
42// Adapted analytic shape and/or size with hr-adaptivity:
43// mesh-optimizer -m square01.mesh -o 2 -tid 9 -ni 50 -li 20 -hmid 55 -mid 7 -hr
44// mesh-optimizer -m square01.mesh -o 2 -tid 10 -ni 50 -li 20 -hmid 55 -mid 7 -hr
45// mesh-optimizer -m square01.mesh -o 2 -tid 11 -ni 50 -li 20 -hmid 58 -mid 7 -hr
46//
47// Adapted discrete size:
48// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 94 -tid 5 -ni 50 -qo 4 -nor
49// (requires GSLIB):
50// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 80 -tid 5 -ni 50 -qo 4 -nor -mno 1 -ae 1
51// Adapted discrete size NC mesh;
52// mesh-optimizer -m amr-quad-q2.mesh -o 2 -rs 2 -mid 94 -tid 5 -ni 50 -qo 4 -nor
53// Adapted discrete size 3D with PA:
54// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 321 -tid 5 -ls 3 -nor -pa
55// Adapted discrete size 3D with PA on device (requires CUDA):
56// * mesh-optimizer -m cube.mesh -o 3 -rs 3 -mid 321 -tid 5 -ls 3 -nor -lc 0.1 -pa -d cuda
57// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
58// mesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
59// Adapted discrete size+aspect_ratio:
60// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
61// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
62// Adapted discrete size+orientation:
63// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -nor
64// Adapted discrete aspect ratio (3D):
65// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
66//
67// Adaptive limiting:
68// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5
69// Adaptive limiting through the L-BFGS solver:
70// mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 0.5 -st 1
71// Adaptive limiting through FD (requires GSLIB):
72// * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1
73//
74// Blade shape:
75// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8
76// (requires CUDA):
77// * mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8 -d cuda
78// Blade shape with FD-based solver:
79// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 4 -bnd -qt 1 -qo 8 -fd
80// Blade limited shape:
81// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
82// ICF shape and equal size:
83// mesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
84// ICF shape and initial size:
85// mesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
86// ICF shape:
87// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8
88// ICF limited shape:
89// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 -lc 10
90// ICF combo shape + size (rings, slow convergence):
91// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 1000 -bnd -qt 1 -qo 8 -cmb 1
92// Mixed tet / cube / hex mesh with limiting:
93// mesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
94// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
95// * mesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -mid 303 -tid 1 -ni 20 -li 500 -fix-bnd
96// 2D non-conforming shape and equal size:
97// mesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -bnd -qt 1 -qo 8
98//
99// 2D untangling:
100// mesh-optimizer -m jagged.mesh -o 2 -mid 22 -tid 1 -ni 50 -li 50 -qo 4 -fd -vl 1
101// 2D untangling with shifted barrier metric:
102// mesh-optimizer -m jagged.mesh -o 2 -mid 4 -tid 1 -ni 50 -qo 4 -fd -vl 1 -btype 1
103// 3D untangling (the mesh is in the mfem/data GitHub repository):
104// * mesh-optimizer -m ../../../mfem_data/cube-holes-inv.mesh -o 3 -mid 313 -tid 1 -rtol 1e-5 -li 50 -qo 4 -fd -vl 1
105
106#include "mfem.hpp"
108#include <fstream>
109#include <iostream>
110#include "mesh-optimizer.hpp"
111
112using namespace mfem;
113using namespace std;
114
115int main(int argc, char *argv[])
116{
117 // 0. Set the method's default parameters.
118 const char *mesh_file = "icf.mesh";
119 int mesh_poly_deg = 1;
120 int rs_levels = 0;
121 real_t jitter = 0.0;
122 int metric_id = 1;
123 int target_id = 1;
124 real_t lim_const = 0.0;
125 real_t adapt_lim_const = 0.0;
126 int quad_type = 1;
127 int quad_order = 8;
128 int solver_type = 0;
129 int solver_iter = 20;
130#ifdef MFEM_USE_SINGLE
131 real_t solver_rtol = 1e-4;
132#else
133 real_t solver_rtol = 1e-10;
134#endif
135 int solver_art_type = 0;
136 int lin_solver = 2;
137 int max_lin_iter = 100;
138 bool move_bnd = true;
139 int combomet = 0;
140 bool bal_expl_combo = false;
141 bool hradaptivity = false;
142 int h_metric_id = -1;
143 bool normalization = false;
144 bool visualization = true;
145 int verbosity_level = 0;
146 bool fdscheme = false;
147 int adapt_eval = 0;
148 bool exactaction = false;
149 bool integ_over_targ = true;
150 const char *devopt = "cpu";
151 bool pa = false;
152 int n_hr_iter = 5;
153 int n_h_iter = 1;
154 int mesh_node_ordering = 0;
155 int barrier_type = 0;
156 int worst_case_type = 0;
157
158 // 1. Parse command-line options.
159 OptionsParser args(argc, argv);
160 args.AddOption(&mesh_file, "-m", "--mesh",
161 "Mesh file to use.");
162 args.AddOption(&mesh_poly_deg, "-o", "--order",
163 "Polynomial degree of mesh finite element space.");
164 args.AddOption(&rs_levels, "-rs", "--refine-serial",
165 "Number of times to refine the mesh uniformly in serial.");
166 args.AddOption(&jitter, "-ji", "--jitter",
167 "Random perturbation scaling factor.");
168 args.AddOption(&metric_id, "-mid", "--metric-id",
169 "Mesh optimization metric:\n\t"
170 "T-metrics\n\t"
171 "1 : |T|^2 -- 2D no type\n\t"
172 "2 : 0.5|T|^2/tau-1 -- 2D shape (condition number)\n\t"
173 "7 : |T-T^-t|^2 -- 2D shape+size\n\t"
174 "9 : tau*|T-T^-t|^2 -- 2D shape+size\n\t"
175 "14 : |T-I|^2 -- 2D shape+size+orientation\n\t"
176 "22 : 0.5(|T|^2-2*tau)/(tau-tau_0) -- 2D untangling\n\t"
177 "50 : 0.5|T^tT|^2/tau^2-1 -- 2D shape\n\t"
178 "55 : (tau-1)^2 -- 2D size\n\t"
179 "56 : 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 2D size\n\t"
180 "58 : |T^tT|^2/(tau^2)-2*|T|^2/tau+2 -- 2D shape\n\t"
181 "77 : 0.5(tau-1/tau)^2 -- 2D size\n\t"
182 "80 : (1-gamma)mu_2 + gamma mu_77 -- 2D shape+size\n\t"
183 "85 : |T-|T|/sqrt(2)I|^2 -- 2D shape+orientation\n\t"
184 "90 : balanced combo mu_50 & mu_77 -- 2D shape+size\n\t"
185 "94 : balanced combo mu_2 & mu_56 -- 2D shape+size\n\t"
186 "98 : (1/tau)|T-I|^2 -- 2D shape+size+orientation\n\t"
187 // "211: (tau-1)^2-tau+sqrt(tau^2+eps) -- 2D untangling\n\t"
188 // "211: (tau-1)^2-tau+sqrt(tau^2) -- 2D untangling\n\t"
189 // "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t"
190 "301: (|T||T^-1|)/3-1 -- 3D shape\n\t"
191 "302: (|T|^2|T^-1|^2)/9-1 -- 3D shape\n\t"
192 "303: (|T|^2)/3/tau^(2/3)-1 -- 3D shape\n\t"
193 "304: (|T|^3)/3^{3/2}/tau-1 -- 3D shape\n\t"
194 //"311: (tau-1)^2-tau+sqrt(tau^2+eps)-- 3D untangling\n\t"
195 "313: (|T|^2)(tau-tau0)^(-2/3)/3 -- 3D untangling\n\t"
196 "315: (tau-1)^2 -- 3D no type\n\t"
197 "316: 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 3D no type\n\t"
198 "321: |T-T^-t|^2 -- 3D shape+size\n\t"
199 "322: |T-adjT^-t|^2 -- 3D shape+size\n\t"
200 "323: |J|^3-3sqrt(3)ln(det(J))-3sqrt(3) -- 3D shape+size\n\t"
201 "328: balanced combo mu_301 & mu_316 -- 3D shape+size\n\t"
202 "332: (1-gamma) mu_302 + gamma mu_315 -- 3D shape+size\n\t"
203 "333: (1-gamma) mu_302 + gamma mu_316 -- 3D shape+size\n\t"
204 "334: (1-gamma) mu_303 + gamma mu_316 -- 3D shape+size\n\t"
205 "328: balanced combo mu_302 & mu_318 -- 3D shape+size\n\t"
206 "347: (1-gamma) mu_304 + gamma mu_316 -- 3D shape+size\n\t"
207 // "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t"
208 "360: (|T|^3)/3^{3/2}-tau -- 3D shape\n\t"
209 "A-metrics\n\t"
210 "11 : (1/4*alpha)|A-(adjA)^T(W^TW)/omega|^2 -- 2D shape\n\t"
211 "36 : (1/alpha)|A-W|^2 -- 2D shape+size+orientation\n\t"
212 "107: (1/2*alpha)|A-|A|/|W|W|^2 -- 2D shape+orientation\n\t"
213 "126: (1-gamma)nu_11 + gamma*nu_14a -- 2D shape+size\n\t"
214 );
215 args.AddOption(&target_id, "-tid", "--target-id",
216 "Target (ideal element) type:\n\t"
217 "1: Ideal shape, unit size\n\t"
218 "2: Ideal shape, equal size\n\t"
219 "3: Ideal shape, initial size\n\t"
220 "4: Given full analytic Jacobian (in physical space)\n\t"
221 "5: Ideal shape, given size (in physical space)");
222 args.AddOption(&lim_const, "-lc", "--limit-const", "Limiting constant.");
223 args.AddOption(&adapt_lim_const, "-alc", "--adapt-limit-const",
224 "Adaptive limiting coefficient constant.");
225 args.AddOption(&quad_type, "-qt", "--quad-type",
226 "Quadrature rule type:\n\t"
227 "1: Gauss-Lobatto\n\t"
228 "2: Gauss-Legendre\n\t"
229 "3: Closed uniform points");
230 args.AddOption(&quad_order, "-qo", "--quad_order",
231 "Order of the quadrature rule.");
232 args.AddOption(&solver_type, "-st", "--solver-type",
233 " Type of solver: (default) 0: Newton, 1: LBFGS");
234 args.AddOption(&solver_iter, "-ni", "--newton-iters",
235 "Maximum number of Newton iterations.");
236 args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance",
237 "Relative tolerance for the Newton solver.");
238 args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol",
239 "Type of adaptive relative linear solver tolerance:\n\t"
240 "0: None (default)\n\t"
241 "1: Eisenstat-Walker type 1\n\t"
242 "2: Eisenstat-Walker type 2");
243 args.AddOption(&lin_solver, "-ls", "--lin-solver",
244 "Linear solver:\n\t"
245 "0: l1-Jacobi\n\t"
246 "1: CG\n\t"
247 "2: MINRES\n\t"
248 "3: MINRES + Jacobi preconditioner\n\t"
249 "4: MINRES + l1-Jacobi preconditioner");
250 args.AddOption(&max_lin_iter, "-li", "--lin-iter",
251 "Maximum number of iterations in the linear solve.");
252 args.AddOption(&move_bnd, "-bnd", "--move-boundary", "-fix-bnd",
253 "--fix-boundary",
254 "Enable motion along horizontal and vertical boundaries.");
255 args.AddOption(&combomet, "-cmb", "--combo-type",
256 "Combination of metrics options:\n\t"
257 "0: Use single metric\n\t"
258 "1: Shape + space-dependent size given analytically\n\t"
259 "2: Shape + adapted size given discretely; shared target");
260 args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
261 "-no-bec", "--balance-explicit-combo",
262 "Automatic balancing of explicit combo metrics.");
263 args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
264 "--no-hr-adaptivity",
265 "Enable hr-adaptivity.");
266 args.AddOption(&h_metric_id, "-hmid", "--h-metric",
267 "Same options as metric_id. Used to determine refinement"
268 " type for each element if h-adaptivity is enabled.");
269 args.AddOption(&normalization, "-nor", "--normalization", "-no-nor",
270 "--no-normalization",
271 "Make all terms in the optimization functional unitless.");
272 args.AddOption(&fdscheme, "-fd", "--fd_approximation",
273 "-no-fd", "--no-fd-approx",
274 "Enable finite difference based derivative computations.");
275 args.AddOption(&exactaction, "-ex", "--exact_action",
276 "-no-ex", "--no-exact-action",
277 "Enable exact action of TMOP_Integrator.");
278 args.AddOption(&integ_over_targ, "-it", "--integrate-target",
279 "-ir", "--integrate-reference",
280 "Integrate over target (-it) or reference (-ir) element.");
281 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
282 "--no-visualization",
283 "Enable or disable GLVis visualization.");
284 args.AddOption(&verbosity_level, "-vl", "--verbosity-level",
285 "Verbosity level for the involved iterative solvers:\n\t"
286 "0: no output\n\t"
287 "1: Newton iterations\n\t"
288 "2: Newton iterations + linear solver summaries\n\t"
289 "3: newton iterations + linear solver iterations");
290 args.AddOption(&adapt_eval, "-ae", "--adaptivity-evaluator",
291 "0 - Advection based (DEFAULT), 1 - GSLIB.");
292 args.AddOption(&devopt, "-d", "--device",
293 "Device configuration string, see Device::Configure().");
294 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
295 "--no-partial-assembly", "Enable Partial Assembly.");
296 args.AddOption(&n_hr_iter, "-nhr", "--n_hr_iter",
297 "Number of hr-adaptivity iterations.");
298 args.AddOption(&n_h_iter, "-nh", "--n_h_iter",
299 "Number of h-adaptivity iterations per r-adaptivity"
300 "iteration.");
301 args.AddOption(&mesh_node_ordering, "-mno", "--mesh_node_ordering",
302 "Ordering of mesh nodes."
303 "0 (default): byNodes, 1: byVDIM");
304 args.AddOption(&barrier_type, "-btype", "--barrier-type",
305 "0 - None,"
306 "1 - Shifted Barrier,"
307 "2 - Pseudo Barrier.");
308 args.AddOption(&worst_case_type, "-wctype", "--worst-case-type",
309 "0 - None,"
310 "1 - Beta,"
311 "2 - PMean.");
312 args.Parse();
313 if (!args.Good())
314 {
315 args.PrintUsage(cout);
316 return 1;
317 }
318 args.PrintOptions(cout);
319
320 if (h_metric_id < 0) { h_metric_id = metric_id; }
321
322 if (hradaptivity)
323 {
324 MFEM_VERIFY(strcmp(devopt,"cpu")==0, "HR-adaptivity is currently only"
325 " supported on cpus.");
326 }
327 Device device(devopt);
328 device.Print();
329
330 // 2. Initialize and refine the starting mesh.
331 Mesh *mesh = new Mesh(mesh_file, 1, 1, false);
332 for (int lev = 0; lev < rs_levels; lev++) { mesh->UniformRefinement(); }
333 const int dim = mesh->Dimension();
334
335 if (hradaptivity) { mesh->EnsureNCMesh(); }
336
337 // 3. Define a finite element space on the mesh-> Here we use vector finite
338 // elements which are tensor products of quadratic finite elements. The
339 // number of components in the vector finite element space is specified by
340 // the last parameter of the FiniteElementSpace constructor.
342 if (mesh_poly_deg <= 0)
343 {
344 fec = new QuadraticPosFECollection;
345 mesh_poly_deg = 2;
346 }
347 else { fec = new H1_FECollection(mesh_poly_deg, dim); }
348 FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec, dim,
349 mesh_node_ordering);
350
351 // 4. Make the mesh curved based on the above finite element space. This
352 // means that we define the mesh elements through a fespace-based
353 // transformation of the reference element.
354 mesh->SetNodalFESpace(fespace);
355
356 // 5. Set up an empty right-hand side vector b, which is equivalent to b=0.
357 Vector b(0);
358
359 // 6. Get the mesh nodes (vertices and other degrees of freedom in the finite
360 // element space) as a finite element grid function in fespace. Note that
361 // changing x automatically changes the shapes of the mesh elements.
362 GridFunction x(fespace);
363 mesh->SetNodalGridFunction(&x);
364
365 // 7. Define a vector representing the minimal local mesh size in the mesh
366 // nodes. We index the nodes using the scalar version of the degrees of
367 // freedom in fespace. Note: this is partition-dependent.
368 //
369 // In addition, compute average mesh size and total volume.
370 Vector h0(fespace->GetNDofs());
371 h0 = infinity();
372 real_t mesh_volume = 0.0;
373 Array<int> dofs;
374 for (int i = 0; i < mesh->GetNE(); i++)
375 {
376 // Get the local scalar element degrees of freedom in dofs.
377 fespace->GetElementDofs(i, dofs);
378 // Adjust the value of h0 in dofs based on the local mesh size.
379 const real_t hi = mesh->GetElementSize(i);
380 for (int j = 0; j < dofs.Size(); j++)
381 {
382 h0(dofs[j]) = min(h0(dofs[j]), hi);
383 }
384 mesh_volume += mesh->GetElementVolume(i);
385 }
386 const real_t small_phys_size = pow(mesh_volume, 1.0 / dim) / 100.0;
387
388 // 8. Add a random perturbation to the nodes in the interior of the domain.
389 // We define a random grid function of fespace and make sure that it is
390 // zero on the boundary and its values are locally of the order of h0.
391 // The latter is based on the DofToVDof() method which maps the scalar to
392 // the vector degrees of freedom in fespace.
393 GridFunction rdm(fespace);
394 rdm.Randomize();
395 rdm -= 0.25; // Shift to random values in [-0.5,0.5].
396 rdm *= jitter;
397 rdm.HostReadWrite();
398 // Scale the random values to be of order of the local mesh size.
399 for (int i = 0; i < fespace->GetNDofs(); i++)
400 {
401 for (int d = 0; d < dim; d++)
402 {
403 rdm(fespace->DofToVDof(i,d)) *= h0(i);
404 }
405 }
406 Array<int> vdofs;
407 for (int i = 0; i < fespace->GetNBE(); i++)
408 {
409 // Get the vector degrees of freedom in the boundary element.
410 fespace->GetBdrElementVDofs(i, vdofs);
411 // Set the boundary values to zero.
412 for (int j = 0; j < vdofs.Size(); j++) { rdm(vdofs[j]) = 0.0; }
413 }
414 x -= rdm;
415 x.SetTrueVector();
417
418 // 9. Save the starting (prior to the optimization) mesh to a file. This
419 // output can be viewed later using GLVis: "glvis -m perturbed.mesh".
420 {
421 ofstream mesh_ofs("perturbed.mesh");
422 mesh->Print(mesh_ofs);
423 }
424
425 // 10. Store the starting (prior to the optimization) positions.
426 GridFunction x0(fespace);
427 x0 = x;
428
429 // 11. Form the integrator that uses the chosen metric and target.
430 real_t min_detJ = -0.1;
431 TMOP_QualityMetric *metric = NULL;
432 switch (metric_id)
433 {
434 // T-metrics
435 case 1: metric = new TMOP_Metric_001; break;
436 case 2: metric = new TMOP_Metric_002; break;
437 case 4: metric = new TMOP_Metric_004; break;
438 case 7: metric = new TMOP_Metric_007; break;
439 case 9: metric = new TMOP_Metric_009; break;
440 case 14: metric = new TMOP_Metric_014; break;
441 case 22: metric = new TMOP_Metric_022(min_detJ); break;
442 case 50: metric = new TMOP_Metric_050; break;
443 case 55: metric = new TMOP_Metric_055; break;
444 case 56: metric = new TMOP_Metric_056; break;
445 case 58: metric = new TMOP_Metric_058; break;
446 case 66: metric = new TMOP_Metric_066(0.5); break;
447 case 77: metric = new TMOP_Metric_077; break;
448 case 80: metric = new TMOP_Metric_080(0.5); break;
449 case 85: metric = new TMOP_Metric_085; break;
450 case 90: metric = new TMOP_Metric_090; break;
451 case 94: metric = new TMOP_Metric_094; break;
452 case 98: metric = new TMOP_Metric_098; break;
453 // case 211: metric = new TMOP_Metric_211; break;
454 // case 252: metric = new TMOP_Metric_252(min_detJ); break;
455 case 301: metric = new TMOP_Metric_301; break;
456 case 302: metric = new TMOP_Metric_302; break;
457 case 303: metric = new TMOP_Metric_303; break;
458 case 304: metric = new TMOP_Metric_304; break;
459 // case 311: metric = new TMOP_Metric_311; break;
460 case 313: metric = new TMOP_Metric_313(min_detJ); break;
461 case 315: metric = new TMOP_Metric_315; break;
462 case 316: metric = new TMOP_Metric_316; break;
463 case 321: metric = new TMOP_Metric_321; break;
464 case 322: metric = new TMOP_Metric_322; break;
465 case 323: metric = new TMOP_Metric_323; break;
466 case 328: metric = new TMOP_Metric_328; break;
467 case 332: metric = new TMOP_Metric_332(0.5); break;
468 case 333: metric = new TMOP_Metric_333(0.5); break;
469 case 334: metric = new TMOP_Metric_334(0.5); break;
470 case 338: metric = new TMOP_Metric_338; break;
471 case 347: metric = new TMOP_Metric_347(0.5); break;
472 // case 352: metric = new TMOP_Metric_352(min_detJ); break;
473 case 360: metric = new TMOP_Metric_360; break;
474 // A-metrics
475 case 11: metric = new TMOP_AMetric_011; break;
476 case 36: metric = new TMOP_AMetric_036; break;
477 case 107: metric = new TMOP_AMetric_107a; break;
478 case 126: metric = new TMOP_AMetric_126(0.9); break;
479 default:
480 cout << "Unknown metric_id: " << metric_id << endl;
481 return 3;
482 }
483 TMOP_QualityMetric *h_metric = NULL;
484 if (hradaptivity)
485 {
486 switch (h_metric_id)
487 {
488 case 1: h_metric = new TMOP_Metric_001; break;
489 case 2: h_metric = new TMOP_Metric_002; break;
490 case 7: h_metric = new TMOP_Metric_007; break;
491 case 9: h_metric = new TMOP_Metric_009; break;
492 case 55: h_metric = new TMOP_Metric_055; break;
493 case 56: h_metric = new TMOP_Metric_056; break;
494 case 58: h_metric = new TMOP_Metric_058; break;
495 case 77: h_metric = new TMOP_Metric_077; break;
496 case 315: h_metric = new TMOP_Metric_315; break;
497 case 316: h_metric = new TMOP_Metric_316; break;
498 case 321: h_metric = new TMOP_Metric_321; break;
499 default: cout << "Metric_id not supported for h-adaptivity: " << h_metric_id <<
500 endl;
501 return 3;
502 }
503 }
504
506 switch (barrier_type)
507 {
508 case 0: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::None;
509 break;
510 case 1: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::Shifted;
511 break;
512 case 2: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::Pseudo;
513 break;
514 default: cout << "barrier_type not supported: " << barrier_type << endl;
515 return 3;
516 }
517
519 switch (worst_case_type)
520 {
521 case 0: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::None;
522 break;
523 case 1: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::Beta;
524 break;
525 case 2: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::PMean;
526 break;
527 default: cout << "worst_case_type not supported: " << worst_case_type << endl;
528 return 3;
529 }
530
531 TMOP_QualityMetric *untangler_metric = NULL;
532 if (barrier_type > 0 || worst_case_type > 0)
533 {
534 if (barrier_type > 0)
535 {
536 MFEM_VERIFY(metric_id == 4 || metric_id == 14 || metric_id == 66,
537 "Metric not supported for shifted/pseudo barriers.");
538 }
539 untangler_metric = new TMOP_WorstCaseUntangleOptimizer_Metric(*metric,
540 2,
541 1.5,
542 0.001, //0.01 for pseudo barrier
543 0.001,
544 btype,
545 wctype);
546 }
547
548 if (metric_id < 300 || h_metric_id < 300)
549 {
550 MFEM_VERIFY(dim == 2, "Incompatible metric for 3D meshes");
551 }
552 if (metric_id >= 300 || h_metric_id >= 300)
553 {
554 MFEM_VERIFY(dim == 3, "Incompatible metric for 2D meshes");
555 }
556
558 TargetConstructor *target_c = NULL;
559 HessianCoefficient *adapt_coeff = NULL;
560 HRHessianCoefficient *hr_adapt_coeff = NULL;
561 H1_FECollection ind_fec(mesh_poly_deg, dim);
562 FiniteElementSpace ind_fes(mesh, &ind_fec);
563 FiniteElementSpace ind_fesv(mesh, &ind_fec, dim);
564 GridFunction size(&ind_fes), aspr(&ind_fes), ori(&ind_fes);
565 GridFunction aspr3d(&ind_fesv);
566
567 const AssemblyLevel al =
568 pa ? AssemblyLevel::PARTIAL : AssemblyLevel::LEGACY;
569
570 switch (target_id)
571 {
572 case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break;
573 case 2: target_t = TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE; break;
574 case 3: target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; break;
575 case 4: // Analytic
576 {
578 AnalyticAdaptTC *tc = new AnalyticAdaptTC(target_t);
579 adapt_coeff = new HessianCoefficient(dim, metric_id);
580 tc->SetAnalyticTargetSpec(NULL, NULL, adapt_coeff);
581 target_c = tc;
582 break;
583 }
584 case 5: // Discrete size 2D or 3D
585 {
587 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
588 if (adapt_eval == 0)
589 {
591 }
592 else
593 {
594#ifdef MFEM_USE_GSLIB
596#else
597 MFEM_ABORT("MFEM is not built with GSLIB.");
598#endif
599 }
600 ConstructSizeGF(size);
602 target_c = tc;
603 break;
604 }
605 case 6: // Discrete size + aspect ratio - 2D
606 {
607 GridFunction d_x(&ind_fes), d_y(&ind_fes), disc(&ind_fes);
608
610 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
612 disc.ProjectCoefficient(mat_coeff);
613 if (adapt_eval == 0)
614 {
616 }
617 else
618 {
619#ifdef MFEM_USE_GSLIB
621#else
622 MFEM_ABORT("MFEM is not built with GSLIB.");
623#endif
624 }
625
626 // Diffuse the interface
628
629 // Get partials with respect to x and y of the grid function
630 disc.GetDerivative(1,0,d_x);
631 disc.GetDerivative(1,1,d_y);
632
633 // Compute the squared magnitude of the gradient
634 for (int i = 0; i < size.Size(); i++)
635 {
636 size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2);
637 }
638 const real_t max = size.Max();
639
640 for (int i = 0; i < d_x.Size(); i++)
641 {
642 d_x(i) = std::abs(d_x(i));
643 d_y(i) = std::abs(d_y(i));
644 }
645 const real_t eps = 0.01;
646 const real_t aspr_ratio = 20.0;
647 const real_t size_ratio = 40.0;
648
649 for (int i = 0; i < size.Size(); i++)
650 {
651 size(i) = (size(i)/max);
652 aspr(i) = (d_x(i)+eps)/(d_y(i)+eps);
653 aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i));
654 if (aspr(i) > aspr_ratio) {aspr(i) = aspr_ratio;}
655 if (aspr(i) < 1.0/aspr_ratio) {aspr(i) = 1.0/aspr_ratio;}
656 }
657 Vector vals;
658 const int NE = mesh->GetNE();
659 real_t volume = 0.0, volume_ind = 0.0;
660
661 for (int i = 0; i < NE; i++)
662 {
664 const IntegrationRule &ir =
665 IntRules.Get(mesh->GetElementBaseGeometry(i), Tr->OrderJ());
666 size.GetValues(i, ir, vals);
667 for (int j = 0; j < ir.GetNPoints(); j++)
668 {
669 const IntegrationPoint &ip = ir.IntPoint(j);
670 Tr->SetIntPoint(&ip);
671 volume += ip.weight * Tr->Weight();
672 volume_ind += vals(j) * ip.weight * Tr->Weight();
673 }
674 }
675
676 const real_t avg_zone_size = volume / NE;
677
678 const real_t small_avg_ratio = (volume_ind + (volume - volume_ind) /
679 size_ratio) /
680 volume;
681
682 const real_t small_zone_size = small_avg_ratio * avg_zone_size;
683 const real_t big_zone_size = size_ratio * small_zone_size;
684
685 for (int i = 0; i < size.Size(); i++)
686 {
687 const real_t val = size(i);
688 const real_t a = (big_zone_size - small_zone_size) / small_zone_size;
689 size(i) = big_zone_size / (1.0+a*val);
690 }
691
692 DiffuseField(size, 2);
693 DiffuseField(aspr, 2);
694
697 target_c = tc;
698 break;
699 }
700 case 7: // Discrete aspect ratio 3D
701 {
703 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
704 if (adapt_eval == 0)
705 {
707 }
708 else
709 {
710#ifdef MFEM_USE_GSLIB
712#else
713 MFEM_ABORT("MFEM is not built with GSLIB.");
714#endif
715 }
717 aspr3d.ProjectCoefficient(fd_aspr3d);
718
720 target_c = tc;
721 break;
722 }
723 case 8: // shape/size + orientation 2D
724 {
726 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
727 if (adapt_eval == 0)
728 {
730 }
731 else
732 {
733#ifdef MFEM_USE_GSLIB
735#else
736 MFEM_ABORT("MFEM is not built with GSLIB.");
737#endif
738 }
739
740 ConstantCoefficient size_coeff(0.1*0.1);
741 size.ProjectCoefficient(size_coeff);
743
745 ori.ProjectCoefficient(ori_coeff);
747 target_c = tc;
748 break;
749 }
750 // Targets used for hr-adaptivity tests.
751 case 9: // size target in an annular region.
752 case 10: // size+aspect-ratio in an annular region.
753 case 11: // size+aspect-ratio target for a rotate sine wave
754 {
756 AnalyticAdaptTC *tc = new AnalyticAdaptTC(target_t);
757 hr_adapt_coeff = new HRHessianCoefficient(dim, target_id - 9);
758 tc->SetAnalyticTargetSpec(NULL, NULL, hr_adapt_coeff);
759 target_c = tc;
760 break;
761 }
762 default: cout << "Unknown target_id: " << target_id << endl; return 3;
763 }
764 if (target_c == NULL)
765 {
766 target_c = new TargetConstructor(target_t);
767 }
768 target_c->SetNodes(x0);
769
770 // Automatically balanced gamma in composite metrics.
771 auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
772 if (metric_combo && bal_expl_combo)
773 {
774 Vector bal_weights;
775 metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights);
776 metric_combo->SetWeights(bal_weights);
777 }
778
779 TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
780 ? untangler_metric
781 : metric;
782 auto tmop_integ = new TMOP_Integrator(metric_to_use, target_c, h_metric);
783 tmop_integ->IntegrateOverTarget(integ_over_targ);
784 if (barrier_type > 0 || worst_case_type > 0)
785 {
786 tmop_integ->ComputeUntangleMetricQuantiles(x, *fespace);
787 }
788
789 // Finite differences for computations of derivatives.
790 if (fdscheme)
791 {
792 MFEM_VERIFY(pa == false, "PA for finite differences is not implemented.");
793 tmop_integ->EnableFiniteDifferences(x);
794 }
795 tmop_integ->SetExactActionFlag(exactaction);
796
797 // Setup the quadrature rules for the TMOP integrator.
798 IntegrationRules *irules = NULL;
799 switch (quad_type)
800 {
801 case 1: irules = &IntRulesLo; break;
802 case 2: irules = &IntRules; break;
803 case 3: irules = &IntRulesCU; break;
804 default: cout << "Unknown quad_type: " << quad_type << endl; return 3;
805 }
806 tmop_integ->SetIntegrationRules(*irules, quad_order);
807 if (dim == 2)
808 {
809 cout << "Triangle quadrature points: "
810 << irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
811 << "\nQuadrilateral quadrature points: "
812 << irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
813 }
814 if (dim == 3)
815 {
816 cout << "Tetrahedron quadrature points: "
817 << irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
818 << "\nHexahedron quadrature points: "
819 << irules->Get(Geometry::CUBE, quad_order).GetNPoints()
820 << "\nPrism quadrature points: "
821 << irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
822 }
823
824 // Limit the node movement.
825 // The limiting distances can be given by a general function of space.
826 FiniteElementSpace dist_fespace(mesh, fec); // scalar space
827 GridFunction dist(&dist_fespace);
828 dist = 1.0;
829 // The small_phys_size is relevant only with proper normalization.
830 if (normalization) { dist = small_phys_size; }
831 ConstantCoefficient lim_coeff(lim_const);
832 if (lim_const != 0.0) { tmop_integ->EnableLimiting(x0, dist, lim_coeff); }
833
834 // Adaptive limiting.
835 GridFunction adapt_lim_gf0(&ind_fes);
836 ConstantCoefficient adapt_lim_coeff(adapt_lim_const);
837 AdaptivityEvaluator *adapt_lim_eval = NULL;
838 if (adapt_lim_const > 0.0)
839 {
840 MFEM_VERIFY(pa == false, "PA is not implemented for adaptive limiting");
841
842 FunctionCoefficient adapt_lim_gf0_coeff(adapt_lim_fun);
843 adapt_lim_gf0.ProjectCoefficient(adapt_lim_gf0_coeff);
844
845 if (adapt_eval == 0) { adapt_lim_eval = new AdvectorCG(al); }
846 else if (adapt_eval == 1)
847 {
848#ifdef MFEM_USE_GSLIB
849 adapt_lim_eval = new InterpolatorFP;
850#else
851 MFEM_ABORT("MFEM is not built with GSLIB support!");
852#endif
853 }
854 else { MFEM_ABORT("Bad interpolation option."); }
855
856 tmop_integ->EnableAdaptiveLimiting(adapt_lim_gf0, adapt_lim_coeff,
857 *adapt_lim_eval);
858 if (visualization)
859 {
860 socketstream vis1;
861 common::VisualizeField(vis1, "localhost", 19916, adapt_lim_gf0, "Zeta 0",
862 300, 600, 300, 300);
863 }
864 }
865
866 // Has to be after the enabling of the limiting / alignment, as it computes
867 // normalization factors for these terms as well.
868 if (normalization) { tmop_integ->EnableNormalization(x0); }
869
870 // 12. Setup the final NonlinearForm (which defines the integral of interest,
871 // its first and second derivatives). Here we can use a combination of
872 // metrics, i.e., optimize the sum of two integrals, where both are
873 // scaled by used-defined space-dependent weights. Note that there are no
874 // command-line options for the weights and the type of the second
875 // metric; one should update those in the code.
876 NonlinearForm a(fespace);
877 if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
878 ConstantCoefficient *metric_coeff1 = NULL;
879 TMOP_QualityMetric *metric2 = NULL;
880 TargetConstructor *target_c2 = NULL;
881 FunctionCoefficient metric_coeff2(weight_fun);
882
883 // Explicit combination of metrics.
884 if (combomet > 0)
885 {
886 // First metric.
887 metric_coeff1 = new ConstantCoefficient(1.0);
888 tmop_integ->SetCoefficient(*metric_coeff1);
889
890 // Second metric.
891 if (dim == 2) { metric2 = new TMOP_Metric_077; }
892 else { metric2 = new TMOP_Metric_315; }
893 TMOP_Integrator *tmop_integ2 = NULL;
894 if (combomet == 1)
895 {
896 target_c2 = new TargetConstructor(
898 target_c2->SetVolumeScale(0.01);
899 target_c2->SetNodes(x0);
900 tmop_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
901 tmop_integ2->SetCoefficient(metric_coeff2);
902 }
903 else { tmop_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
904 tmop_integ2->IntegrateOverTarget(integ_over_targ);
905 tmop_integ2->SetIntegrationRules(*irules, quad_order);
906 if (fdscheme) { tmop_integ2->EnableFiniteDifferences(x); }
907 tmop_integ2->SetExactActionFlag(exactaction);
908
910 combo->AddTMOPIntegrator(tmop_integ);
911 combo->AddTMOPIntegrator(tmop_integ2);
912 if (normalization) { combo->EnableNormalization(x0); }
913 if (lim_const != 0.0) { combo->EnableLimiting(x0, dist, lim_coeff); }
914
915 a.AddDomainIntegrator(combo);
916 }
917 else
918 {
919 a.AddDomainIntegrator(tmop_integ);
920 }
921
922 if (pa) { a.Setup(); }
923
924 // Compute the minimum det(J) of the starting mesh.
925 min_detJ = infinity();
926 const int NE = mesh->GetNE();
927 for (int i = 0; i < NE; i++)
928 {
929 const IntegrationRule &ir =
930 irules->Get(fespace->GetFE(i)->GetGeomType(), quad_order);
932 for (int j = 0; j < ir.GetNPoints(); j++)
933 {
934 transf->SetIntPoint(&ir.IntPoint(j));
935 min_detJ = min(min_detJ, transf->Jacobian().Det());
936 }
937 }
938 cout << "Minimum det(J) of the original mesh is " << min_detJ << endl;
939
940 if (min_detJ < 0.0 && barrier_type == 0
941 && metric_id != 22 && metric_id != 211 && metric_id != 252
942 && metric_id != 311 && metric_id != 313 && metric_id != 352)
943 {
944 MFEM_ABORT("The input mesh is inverted! Try an untangling metric.");
945 }
946 if (min_detJ < 0.0)
947 {
948 MFEM_VERIFY(target_t == TargetConstructor::IDEAL_SHAPE_UNIT_SIZE,
949 "Untangling is supported only for ideal targets.");
950
951 const DenseMatrix &Wideal =
953 min_detJ /= Wideal.Det();
954
955 // Slightly below minJ0 to avoid div by 0.
956 min_detJ -= 0.01 * h0.Min();
957 }
958
959 // For HR tests, the energy is normalized by the number of elements.
960 const real_t init_energy = a.GetGridFunctionEnergy(x) /
961 (hradaptivity ? mesh->GetNE() : 1);
962 real_t init_metric_energy = init_energy;
963 if (lim_const > 0.0 || adapt_lim_const > 0.0)
964 {
965 lim_coeff.constant = 0.0;
966 adapt_lim_coeff.constant = 0.0;
967 init_metric_energy = a.GetGridFunctionEnergy(x) /
968 (hradaptivity ? mesh->GetNE() : 1);
969 lim_coeff.constant = lim_const;
970 adapt_lim_coeff.constant = adapt_lim_const;
971 }
972
973 // Visualize the starting mesh and metric values.
974 // Note that for combinations of metrics, this only shows the first metric.
975 if (visualization)
976 {
977 char title[] = "Initial metric values";
978 vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 0);
979 }
980
981 // 13. Fix all boundary nodes, or fix only a given component depending on the
982 // boundary attributes of the given mesh. Attributes 1/2/3 correspond to
983 // fixed x/y/z components of the node. Attribute 4 corresponds to an
984 // entirely fixed node. Other boundary attributes do not affect the node
985 // movement boundary conditions.
986 if (move_bnd == false)
987 {
988 Array<int> ess_bdr(mesh->bdr_attributes.Max());
989 ess_bdr = 1;
990 a.SetEssentialBC(ess_bdr);
991 }
992 else
993 {
994 int n = 0;
995 for (int i = 0; i < mesh->GetNBE(); i++)
996 {
997 const int nd = fespace->GetBE(i)->GetDof();
998 const int attr = mesh->GetBdrElement(i)->GetAttribute();
999 MFEM_VERIFY(!(dim == 2 && attr == 3),
1000 "Boundary attribute 3 must be used only for 3D meshes. "
1001 "Adjust the attributes (1/2/3/4 for fixed x/y/z/all "
1002 "components, rest for free nodes), or use -fix-bnd.");
1003 if (attr == 1 || attr == 2 || attr == 3) { n += nd; }
1004 if (attr == 4) { n += nd * dim; }
1005 }
1006 Array<int> ess_vdofs(n);
1007 n = 0;
1008 for (int i = 0; i < mesh->GetNBE(); i++)
1009 {
1010 const int nd = fespace->GetBE(i)->GetDof();
1011 const int attr = mesh->GetBdrElement(i)->GetAttribute();
1012 fespace->GetBdrElementVDofs(i, vdofs);
1013 if (attr == 1) // Fix x components.
1014 {
1015 for (int j = 0; j < nd; j++)
1016 { ess_vdofs[n++] = vdofs[j]; }
1017 }
1018 else if (attr == 2) // Fix y components.
1019 {
1020 for (int j = 0; j < nd; j++)
1021 { ess_vdofs[n++] = vdofs[j+nd]; }
1022 }
1023 else if (attr == 3) // Fix z components.
1024 {
1025 for (int j = 0; j < nd; j++)
1026 { ess_vdofs[n++] = vdofs[j+2*nd]; }
1027 }
1028 else if (attr == 4) // Fix all components.
1029 {
1030 for (int j = 0; j < vdofs.Size(); j++)
1031 { ess_vdofs[n++] = vdofs[j]; }
1032 }
1033 }
1034 a.SetEssentialVDofs(ess_vdofs);
1035 }
1036
1037 // As we use the inexact Newton method to solve the resulting nonlinear
1038 // system, here we setup the linear solver for the system's Jacobian.
1039 Solver *S = NULL, *S_prec = NULL;
1040#ifdef MFEM_USE_SINGLE
1041 const real_t linsol_rtol = 1e-5;
1042#else
1043 const real_t linsol_rtol = 1e-12;
1044#endif
1045 // Level of output.
1046 IterativeSolver::PrintLevel linsolver_print;
1047 if (verbosity_level == 2)
1048 { linsolver_print.Errors().Warnings().FirstAndLast(); }
1049 if (verbosity_level > 2)
1050 { linsolver_print.Errors().Warnings().Iterations(); }
1051 if (lin_solver == 0)
1052 {
1053 S = new DSmoother(1, 1.0, max_lin_iter);
1054 }
1055 else if (lin_solver == 1)
1056 {
1057 CGSolver *cg = new CGSolver;
1058 cg->SetMaxIter(max_lin_iter);
1059 cg->SetRelTol(linsol_rtol);
1060 cg->SetAbsTol(0.0);
1061 cg->SetPrintLevel(linsolver_print);
1062 S = cg;
1063 }
1064 else
1065 {
1066 MINRESSolver *minres = new MINRESSolver;
1067 minres->SetMaxIter(max_lin_iter);
1068 minres->SetRelTol(linsol_rtol);
1069 minres->SetAbsTol(0.0);
1070 minres->SetPrintLevel(linsolver_print);
1071 if (lin_solver == 3 || lin_solver == 4)
1072 {
1073 if (pa)
1074 {
1075 MFEM_VERIFY(lin_solver != 4, "PA l1-Jacobi is not implemented");
1076 auto js = new OperatorJacobiSmoother;
1077 js->SetPositiveDiagonal(true);
1078 S_prec = js;
1079 }
1080 else
1081 {
1082 auto ds = new DSmoother((lin_solver == 3) ? 0 : 1, 1.0, 1);
1083 ds->SetPositiveDiagonal(true);
1084 S_prec = ds;
1085 }
1086 minres->SetPreconditioner(*S_prec);
1087 }
1088 S = minres;
1089 }
1090
1091 //
1092 // Perform the nonlinear optimization.
1093 //
1094 const IntegrationRule &ir =
1095 irules->Get(fespace->GetFE(0)->GetGeomType(), quad_order);
1096 TMOPNewtonSolver solver(ir, solver_type);
1097 // Provide all integration rules in case of a mixed mesh.
1098 solver.SetIntegrationRules(*irules, quad_order);
1099 // Specify linear solver when we use a Newton-based solver.
1100 if (solver_type == 0) { solver.SetPreconditioner(*S); }
1101 // For untangling, the solver will update the min det(T) values.
1102 solver.SetMinDetPtr(&min_detJ);
1103 solver.SetMaxIter(solver_iter);
1104 solver.SetRelTol(solver_rtol);
1105 solver.SetAbsTol(0.0);
1106 if (solver_art_type > 0)
1107 {
1108 solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9);
1109 }
1110 // Level of output.
1111 IterativeSolver::PrintLevel newton_print;
1112 if (verbosity_level > 0)
1113 { newton_print.Errors().Warnings().Iterations(); }
1114 solver.SetPrintLevel(newton_print);
1115 // hr-adaptivity solver.
1116 // If hr-adaptivity is disabled, r-adaptivity is done once using the
1117 // TMOPNewtonSolver.
1118 // Otherwise, "hr_iter" iterations of r-adaptivity are done followed by
1119 // "h_per_r_iter" iterations of h-adaptivity after each r-adaptivity.
1120 // The solver terminates if an h-adaptivity iteration does not modify
1121 // any element in the mesh.
1122 TMOPHRSolver hr_solver(*mesh, a, solver,
1123 x, move_bnd, hradaptivity,
1124 mesh_poly_deg, h_metric_id,
1125 n_hr_iter, n_h_iter);
1126 hr_solver.AddGridFunctionForUpdate(&x0);
1127 if (adapt_lim_const > 0.)
1128 {
1129 hr_solver.AddGridFunctionForUpdate(&adapt_lim_gf0);
1130 hr_solver.AddFESpaceForUpdate(&ind_fes);
1131 }
1132 hr_solver.Mult();
1133
1134 // 15. Save the optimized mesh to a file. This output can be viewed later
1135 // using GLVis: "glvis -m optimized.mesh".
1136 {
1137 ofstream mesh_ofs("optimized.mesh");
1138 mesh_ofs.precision(14);
1139 mesh->Print(mesh_ofs);
1140 }
1141
1142 // Report the final energy of the functional.
1143 const real_t fin_energy = a.GetGridFunctionEnergy(x) /
1144 (hradaptivity ? mesh->GetNE() : 1);
1145 real_t fin_metric_energy = fin_energy;
1146 if (lim_const > 0.0 || adapt_lim_const > 0.0)
1147 {
1148 lim_coeff.constant = 0.0;
1149 adapt_lim_coeff.constant = 0.0;
1150 fin_metric_energy = a.GetGridFunctionEnergy(x) /
1151 (hradaptivity ? mesh->GetNE() : 1);
1152 lim_coeff.constant = lim_const;
1153 adapt_lim_coeff.constant = adapt_lim_const;
1154 }
1155 std::cout << std::scientific << std::setprecision(4);
1156 cout << "Initial strain energy: " << init_energy
1157 << " = metrics: " << init_metric_energy
1158 << " + extra terms: " << init_energy - init_metric_energy << endl;
1159 cout << " Final strain energy: " << fin_energy
1160 << " = metrics: " << fin_metric_energy
1161 << " + extra terms: " << fin_energy - fin_metric_energy << endl;
1162 cout << "The strain energy decreased by: "
1163 << (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
1164
1165 // Visualize the final mesh and metric values.
1166 if (visualization)
1167 {
1168 char title[] = "Final metric values";
1169 vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 600);
1170 }
1171
1172 if (adapt_lim_const > 0.0 && visualization)
1173 {
1174 socketstream vis0;
1175 common::VisualizeField(vis0, "localhost", 19916, adapt_lim_gf0, "Xi 0",
1176 600, 600, 300, 300);
1177 }
1178
1179 // Visualize the mesh displacement.
1180 if (visualization)
1181 {
1182 osockstream sock(19916, "localhost");
1183 sock << "solution\n";
1184 mesh->Print(sock);
1185 x0 -= x;
1186 x0.Save(sock);
1187 sock.send();
1188 sock << "window_title 'Displacements'\n"
1189 << "window_geometry "
1190 << 1200 << " " << 0 << " " << 600 << " " << 600 << "\n"
1191 << "keys jRmclA" << endl;
1192 }
1193
1194 delete S;
1195 delete S_prec;
1196 delete target_c2;
1197 delete metric2;
1198 delete metric_coeff1;
1199 delete adapt_lim_eval;
1200 delete target_c;
1201 delete hr_adapt_coeff;
1202 delete adapt_coeff;
1203 delete h_metric;
1204 delete metric;
1205 delete untangler_metric;
1206 delete fespace;
1207 delete fec;
1208 delete mesh;
1209
1210 return 0;
1211}
virtual void SetAnalyticTargetSpec(Coefficient *sspec, VectorCoefficient *vspec, TMOPMatrixCoefficient *mspec)
Definition tmop.cpp:1733
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
int Size() const
Return the logical size of the array.
Definition array.hpp:144
Conjugate gradient method.
Definition solvers.hpp:513
A coefficient that is constant across space and time.
Data type for scaled Jacobi-type smoother of sparse matrix.
void SetPositiveDiagonal(bool pos_diag=true)
Replace diag entries with their abs values. Relevant only when type = 0.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
real_t Det() const
Definition densemat.cpp:535
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:123
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:286
virtual void SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_)
Definition tmop.cpp:1982
virtual void SetSerialDiscreteTargetSize(const GridFunction &tspec_)
Definition tmop.cpp:1962
void SetAdaptivityEvaluator(AdaptivityEvaluator *ae)
Definition tmop.hpp:1662
virtual void SetSerialDiscreteTargetOrientation(const GridFunction &tspec_)
Definition tmop.cpp:1992
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:131
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint,...
Definition eltrans.hpp:119
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:93
int GetAttribute() const
Return element's attribute.
Definition element.hpp:55
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:220
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3204
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:2846
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:710
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:749
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3168
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:303
int DofToVDof(int dof, int vd, int ndofs=-1) const
Compute a single vdof corresponding to the index dof and the vector index vd.
Definition fespace.cpp:249
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:326
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:329
A general function coefficient.
const DenseMatrix & GetGeomToPerfGeomJac(int GeomType) const
Definition geom.hpp:98
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:144
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:150
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
Container class for integration rules.
Definition intrules.hpp:416
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetRelTol(real_t rtol)
Definition solvers.hpp:209
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:71
void SetMaxIter(int max_it)
Definition solvers.hpp:211
void SetAbsTol(real_t atol)
Definition solvers.hpp:210
MINRES method.
Definition solvers.hpp:628
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.hpp:640
Mesh data type.
Definition mesh.hpp:56
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:282
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2288
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1226
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1298
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:107
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
Builds the transformation defining the i-th element in ElTr. ElTr must be allocated in advance and wi...
Definition mesh.cpp:357
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition mesh.cpp:6200
real_t GetElementVolume(int i)
Definition mesh.cpp:121
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition mesh.cpp:6153
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1229
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:10626
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1385
void SetAdaptiveLinRtol(const int type=2, const real_t rtol0=0.5, const real_t rtol_max=0.9, const real_t alpha=0.5 *(1.0+sqrt(5.0)), const real_t gamma=1.0)
Enable adaptive linear solver relative tolerance algorithm.
Definition solvers.cpp:1929
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:313
void SetPositiveDiagonal(bool pos_diag=true)
Replace diagonal entries with their absolute values.
Definition solvers.hpp:349
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Version of QuadraticFECollection with positive basis functions.
Definition fe_coll.hpp:796
Base class for solvers.
Definition operator.hpp:683
void EnableLimiting(const GridFunction &n0, const GridFunction &dist, Coefficient &w0, TMOP_LimiterFunction *lfunc=NULL)
Adds the limiting term to the first integrator. Disables it for the rest.
Definition tmop.cpp:4724
void EnableNormalization(const GridFunction &x)
Normalization factor that considers all integrators in the combination.
Definition tmop.cpp:4823
void AddTMOPIntegrator(TMOP_Integrator *ti)
Adds a new TMOP_Integrator to the combination.
Definition tmop.hpp:2271
void AddGridFunctionForUpdate(GridFunction *gf)
Definition tmop_amr.hpp:252
void AddFESpaceForUpdate(FiniteElementSpace *fes)
Definition tmop_amr.hpp:253
void SetIntegrationRules(IntegrationRules &irules, int order)
Prescribe a set of integration rules; relevant for mixed meshes.
void SetMinDetPtr(real_t *md_ptr)
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
2D barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:1114
2D barrier Shape+Orientation (OS) metric (polyconvex).
Definition tmop.hpp:1132
2D barrier Shape+Size (VS) metric (polyconvex).
Definition tmop.hpp:1150
A TMOP integrator class based on any given TMOP_QualityMetric and TargetConstructor.
Definition tmop.hpp:1738
void SetExactActionFlag(bool flag_)
Flag to control if exact action of Integration is effected.
Definition tmop.hpp:2241
void SetCoefficient(Coefficient &w1)
Sets a scaling Coefficient for the quality metric term of the integrator.
Definition tmop.hpp:2045
void EnableFiniteDifferences(const GridFunction &x)
Enables FD-based approximation and computes dx.
Definition tmop.cpp:4535
void SetIntegrationRules(IntegrationRules &irules, int order)
Prescribe a set of integration rules; relevant for mixed meshes.
Definition tmop.hpp:2021
void IntegrateOverTarget(bool integ_over_target_)
Definition tmop.hpp:2030
2D non-barrier metric without a type.
Definition tmop.hpp:222
2D barrier Shape+Size (VS) metric (not polyconvex).
Definition tmop.hpp:341
2D barrier Shape+Size (VS) metric (not polyconvex).
Definition tmop.hpp:359
2D non-barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:375
2D Shifted barrier form of shape metric (mu_2).
Definition tmop.hpp:394
2D barrier shape (S) metric (not polyconvex).
Definition tmop.hpp:471
2D barrier Shape+Orientation (OS) metric (polyconvex).
Definition tmop.hpp:557
2D compound barrier Shape+Size (VS) metric (balanced).
Definition tmop.hpp:572
2D compound barrier Shape+Size (VS) metric (balanced).
Definition tmop.hpp:593
2D barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:614
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:668
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:687
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:708
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:729
3D Shape (S) metric, untangling version of 303.
Definition tmop.hpp:769
3D Size (V) metric.
Definition tmop.hpp:790
3D Size (V) metric.
Definition tmop.hpp:808
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:848
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:869
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:890
3D compound barrier Shape+Size (VS) metric (polyconvex, balanced).
Definition tmop.hpp:911
3D compound barrier Shape+Size (VS) metric (polyconvex).
Definition tmop.hpp:932
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:953
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:972
3D compound barrier Shape+Size (VS) metric (polyconvex, balanced).
Definition tmop.hpp:994
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:1015
3D non-barrier Shape (S) metric.
Definition tmop.hpp:1056
Abstract class for local mesh quality metrics in the target-matrix optimization paradigm (TMOP) by P....
Definition tmop.hpp:24
Base class representing target-matrix construction algorithms for mesh optimization via the target-ma...
Definition tmop.hpp:1334
void SetVolumeScale(real_t vol_scale)
Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1.
Definition tmop.hpp:1419
void SetNodes(const GridFunction &n)
Set the nodes to be used in the target-matrix construction.
Definition tmop.hpp:1413
TargetType
Target-matrix construction algorithms supported by this class.
Definition tmop.hpp:1338
A general vector function coefficient.
Vector data type.
Definition vector.hpp:80
void Randomize(int seed=0)
Set random values in the vector.
Definition vector.cpp:816
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:494
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1212
int dim
Definition ex24.cpp:53
@ disc
Definition ex25.cpp:151
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t adapt_lim_fun(const Vector &x)
IntegrationRules IntRulesCU(0, Quadrature1D::ClosedUniform)
real_t weight_fun(const Vector &x)
real_t material_indicator_2d(const Vector &x)
IntegrationRules IntRulesLo(0, Quadrature1D::GaussLobatto)
void ConstructSizeGF(GridFunction &size)
real_t discrete_ori_2d(const Vector &x)
void discrete_aspr_3d(const Vector &x, Vector &v)
void DiffuseField(ParGridFunction &field, int smooth_steps)
void VisualizeField(socketstream &sock, const char *vishost, int visport, GridFunction &gf, const char *title, int x, int y, int w, int h, const char *keys, bool vec)
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:45
Geometry Geometries
Definition fe.cpp:49
AssemblyLevel
Enumeration defining the assembly level for bilinear and nonlinear form classes derived from Operator...
void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, Mesh &mesh, char *title, int position)
float real_t
Definition config.hpp:43
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:486
Settings for the output behavior of the IterativeSolver.
Definition solvers.hpp:79