MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
pmesh-optimizer.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, 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 - Parallel Version
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 pmesh-optimizer
33//
34// Sample runs:
35// Adapted analytic shape:
36// mpirun -np 4 pmesh-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// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -bnd -qt 1 -qo 8
39// Adapted analytic shape+orientation (AD):
40// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 3 -rs 2 -mid 85 -tid 4 -ni 100 -bnd -qt 1 -qo 8 -rtol 1e-6
41//
42// Adapted analytic shape and/or size with hr-adaptivity:
43// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -tid 9 -ni 50 -li 20 -hmid 55 -mid 7 -hr
44// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -tid 10 -ni 50 -li 20 -hmid 55 -mid 7 -hr
45// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -tid 11 -ni 50 -li 20 -hmid 58 -mid 7 -hr
46//
47// Adapted discrete size:
48// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 94 -tid 5 -ni 50 -qo 4 -nor
49// (requires GSLIB):
50// * mpirun -np 4 pmesh-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// mpirun -np 4 pmesh-optimizer -m amr-quad-q2.mesh -o 2 -rs 2 -mid 94 -tid 5 -ni 50 -qo 4 -nor
53// Adapted discrete size NC mesh (GPU+GSLIB);
54// * mpirun -np 4 pmesh-optimizer -m ../../data/amr-hex.mesh -o 2 -rs 1 -mid 321 -tid 5 -fix-bnd -ni 50 -qo 6 -nor -vl 2 -ae 1 -d debug
55// Adapted discrete size 3D with PA:
56// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 321 -tid 5 -ls 3 -nor -pa -rtol 1e-8
57// Adapted discrete size 3D with PA on device (requires CUDA):
58// * mpirun -n 4 pmesh-optimizer -m cube.mesh -o 3 -rs 3 -mid 321 -tid 5 -ls 3 -nor -lc 0.1 -pa -d cuda
59// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
60// mpirun -np 4 pmesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
61// Adapted discrete size+aspect_ratio:
62// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
63// Adapted discrete size+orientation (AD):
64// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -nor -rtol 1e-6
65// Adapted discrete aspect ratio (3D):
66// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
67//
68// Periodic 2D + adapted discrete size:
69// mpirun -np 4 pmesh-optimizer -m ../../data/periodic-square.mesh -o 2 -rs 4 -mid 94 -tid 5 -qo 4 -nor
70// mpirun -np 4 pmesh-optimizer -m periodic-tri.mesh -o 2 -rs 3 -mid 94 -tid 5 -qo 4 -nor
71// Periodic 3D + adapted discrete size + PA:
72// mpirun -np 4 pmesh-optimizer -m periodic-cube.mesh -o 2 -rs 2 -mid 338 -tid 5 -nor -rtol 1e-6 -qo 4 -pa
73// Periodic 2D NC mesh + adapted discrete size + PA:
74// (the mesh is in the mfem/data GitHub repository)
75// * mpirun -np 4 pmesh-optimizer -m ../../../data/periodic/per-amr-square.mesh -o 2 -mid 94 -tid 5 -ni 50 -qo 4 -nor -pa
76//
77// Adaptive limiting:
78// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -rs 1 -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 1.0
79// mpirun -np 8 pmesh-optimizer -m stretched3D.mesh -rs 2 -o 2 -mid 302 -tid 1 -rtol 1e-7 -qo 5 -nor -vl 1 -alc 2.0 -pa
80// Adaptive limiting through the L-BFGS solver:
81// mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 400 -qo 5 -nor -vl 1 -alc 1.0 -st 1 -rtol 1e-8
82//
83// Blade shape:
84// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8
85// Blade shape + bounded Jacobian determinant:
86// * mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8 -db
87// Blade shape (AD):
88// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 11 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8
89// (requires CUDA):
90// * mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8 -d cuda
91// Blade limited shape:
92// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
93// ICF shape and equal size:
94// mpirun -np 4 pmesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
95// ICF shape and initial size:
96// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
97// ICF shape:
98// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8
99// ICF limited shape:
100// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 -lc 10
101// ICF combo shape + size (rings, slow convergence):
102// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 1000 -bnd -qt 1 -qo 8 -cmb 1
103// Mixed tet / cube / hex mesh with limiting:
104// mpirun -np 4 pmesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
105// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
106// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -mid 303 -tid 1 -ni 20 -li 500 -fix-bnd
107// 2D non-conforming shape and equal size:
108// mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -bnd -qt 1 -qo 8
109//
110// 2D untangling:
111// mpirun -np 4 pmesh-optimizer -m jagged.mesh -o 2 -mid 22 -tid 1 -ni 50 -li 50 -qo 4 -fd -vl 1
112// 2D untangling with shifted barrier metric:
113// mpirun -np 4 pmesh-optimizer -m jagged.mesh -o 2 -mid 4 -tid 1 -ni 50 -qo 4 -vl 1 -btype 1
114// 3D untangling (the mesh is in the mfem/data GitHub repository):
115// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/cube-holes-inv.mesh -o 3 -mid 313 -tid 1 -rtol 1e-5 -li 50 -qo 4 -fd -vl 1
116// Shape optimization for a Kershaw transformed mesh using partial assembly:
117// Mesh for Kershaw transformation must be a Cartesian mesh with nx % 6 = ny % 2 = nz % 2 = 0.
118// Kershaw transformation can be imposed using the transformation ('t') feature in the mesh-explorer miniapp.
119// * mpirun - np 6 pmesh-optimizer -m kershaw-24x24x24.mesh -mid 303 -tid 1 -bnd -ni 100 -art 1 -ls 3 -qo 8 -li 40 -o 2 -pa
120
121#include "mfem.hpp"
123#include <iostream>
124#include <fstream>
125#include "mesh-optimizer.hpp"
126
127using namespace mfem;
128using namespace std;
129
130int main (int argc, char *argv[])
131{
132 // 0. Initialize MPI and HYPRE.
133 Mpi::Init(argc, argv);
134 int myid = Mpi::WorldRank();
135 Hypre::Init();
136
137 // Set the method's default parameters.
138 const char *mesh_file = "icf.mesh";
139 int mesh_poly_deg = 1;
140 int rs_levels = 0;
141 int rp_levels = 0;
142 real_t jitter = 0.0;
143 int metric_id = 1;
144 int target_id = 1;
145 real_t lim_const = 0.0;
146 real_t adapt_lim_const = 0.0;
147 int quad_type = 1;
148 int quad_order = 8;
149 int solver_type = 0;
150 int solver_iter = 20;
151#ifdef MFEM_USE_SINGLE
152 real_t solver_rtol = 1e-4;
153#else
154 real_t solver_rtol = 1e-10;
155#endif
156 int solver_art_type = 0;
157 int lin_solver = 2;
158 int max_lin_iter = 100;
159 bool move_bnd = true;
160 int combomet = 0;
161 bool bal_expl_combo = false;
162 bool hradaptivity = false;
163 int h_metric_id = -1;
164 bool normalization = false;
165 bool visualization = true;
166 int verbosity_level = 0;
167 bool fdscheme = false;
168 int adapt_eval = 0;
169 bool exactaction = false;
170 bool integ_over_targ = true;
171 const char *devopt = "cpu";
172 bool pa = false;
173 int n_hr_iter = 5;
174 int n_h_iter = 1;
175 int mesh_node_order = 0;
176 int barrier_type = 0;
177 int worst_case_type = 0;
178 bool detj_bound = false;
179
180 // Parse command-line options.
181 OptionsParser args(argc, argv);
182 args.AddOption(&mesh_file, "-m", "--mesh",
183 "Mesh file to use.");
184 args.AddOption(&mesh_poly_deg, "-o", "--order",
185 "Polynomial degree of mesh finite element space.");
186 args.AddOption(&rs_levels, "-rs", "--refine-serial",
187 "Number of times to refine the mesh uniformly in serial.");
188 args.AddOption(&rp_levels, "-rp", "--refine-parallel",
189 "Number of times to refine the mesh uniformly in parallel.");
190 args.AddOption(&jitter, "-ji", "--jitter",
191 "Random perturbation scaling factor.");
192 args.AddOption(&metric_id, "-mid", "--metric-id",
193 "Mesh optimization metric:\n\t"
194 "T-metrics\n\t"
195 "1 : |T|^2 -- 2D no type\n\t"
196 "2 : 0.5|T|^2/tau-1 -- 2D shape (condition number)\n\t"
197 "7 : |T-T^-t|^2 -- 2D shape+size\n\t"
198 "9 : tau*|T-T^-t|^2 -- 2D shape+size\n\t"
199 "14 : |T-I|^2 -- 2D shape+size+orientation\n\t"
200 "22 : 0.5(|T|^2-2*tau)/(tau-tau_0) -- 2D untangling\n\t"
201 "50 : 0.5|T^tT|^2/tau^2-1 -- 2D shape\n\t"
202 "55 : (tau-1)^2 -- 2D size\n\t"
203 "56 : 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 2D size\n\t"
204 "58 : |T^tT|^2/(tau^2)-2*|T|^2/tau+2 -- 2D shape\n\t"
205 "77 : 0.5(tau-1/tau)^2 -- 2D size\n\t"
206 "80 : (1-gamma)mu_2 + gamma mu_77 -- 2D shape+size\n\t"
207 "85 : |T-|T|/sqrt(2)I|^2 -- 2D shape+orientation\n\t"
208 "90 : balanced combo mu_50 & mu_77 -- 2D shape+size\n\t"
209 "94 : balanced combo mu_2 & mu_56 -- 2D shape+size\n\t"
210 "98 : (1/tau)|T-I|^2 -- 2D shape+size+orientation\n\t"
211 // "211: (tau-1)^2-tau+sqrt(tau^2+eps) -- 2D untangling\n\t"
212 // "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t"
213 "301: (|T||T^-1|)/3-1 -- 3D shape\n\t"
214 "302: (|T|^2|T^-1|^2)/9-1 -- 3D shape\n\t"
215 "303: (|T|^2)/3/tau^(2/3)-1 -- 3D shape\n\t"
216 "304: (|T|^3)/3^{3/2}/tau-1 -- 3D shape\n\t"
217 // "311: (tau-1)^2-tau+sqrt(tau^2+eps)-- 3D untangling\n\t"
218 "313: (|T|^2)(tau-tau0)^(-2/3)/3 -- 3D untangling\n\t"
219 "315: (tau-1)^2 -- 3D no type\n\t"
220 "316: 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 3D no type\n\t"
221 "321: |T-T^-t|^2 -- 3D shape+size\n\t"
222 "322: |T-adjT^-t|^2 -- 3D shape+size\n\t"
223 "323: |J|^3-3sqrt(3)ln(det(J))-3sqrt(3) -- 3D shape+size\n\t"
224 "328: balanced combo mu_301 & mu_316 -- 3D shape+size\n\t"
225 "332: (1-gamma) mu_302 + gamma mu_315 -- 3D shape+size\n\t"
226 "333: (1-gamma) mu_302 + gamma mu_316 -- 3D shape+size\n\t"
227 "334: (1-gamma) mu_303 + gamma mu_316 -- 3D shape+size\n\t"
228 "328: balanced combo mu_302 & mu_318 -- 3D shape+size\n\t"
229 "347: (1-gamma) mu_304 + gamma mu_316 -- 3D shape+size\n\t"
230 // "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t"
231 "360: (|T|^3)/3^{3/2}-tau -- 3D shape\n\t"
232 "A-metrics\n\t"
233 "11 : (1/4*alpha)|A-(adjA)^T(W^TW)/omega|^2 -- 2D shape\n\t"
234 "36 : (1/alpha)|A-W|^2 -- 2D shape+size+orientation\n\t"
235 "49 : (1-gamma) mu_2 + gamma nu_50 -- 2D shape+skew\n\t"
236 "51 : see fem/tmop.hpp -- 2D size+skew\n\t"
237 "107: (1/2*alpha)|A-|A|/|W|W|^2 -- 2D shape+orientation\n\t"
238 "126: (1-gamma)nu_11 + gamma*nu_14a -- 2D shape+size\n\t"
239 );
240 args.AddOption(&target_id, "-tid", "--target-id",
241 "Target (ideal element) type:\n\t"
242 "1: Ideal shape, unit size\n\t"
243 "2: Ideal shape, equal size\n\t"
244 "3: Ideal shape, initial size\n\t"
245 "4: Given full analytic Jacobian (in physical space)\n\t"
246 "5: Ideal shape, given size (in physical space)");
247 args.AddOption(&lim_const, "-lc", "--limit-const", "Limiting constant.");
248 args.AddOption(&adapt_lim_const, "-alc", "--adapt-limit-const",
249 "Adaptive limiting coefficient constant.");
250 args.AddOption(&quad_type, "-qt", "--quad-type",
251 "Quadrature rule type:\n\t"
252 "1: Gauss-Lobatto\n\t"
253 "2: Gauss-Legendre\n\t"
254 "3: Closed uniform points");
255 args.AddOption(&quad_order, "-qo", "--quad_order",
256 "Order of the quadrature rule.");
257 args.AddOption(&solver_type, "-st", "--solver-type",
258 " Type of solver: (default) 0: Newton, 1: LBFGS");
259 args.AddOption(&solver_iter, "-ni", "--newton-iters",
260 "Maximum number of Newton iterations.");
261 args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance",
262 "Relative tolerance for the Newton solver.");
263 args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol",
264 "Type of adaptive relative linear solver tolerance:\n\t"
265 "0: None (default)\n\t"
266 "1: Eisenstat-Walker type 1\n\t"
267 "2: Eisenstat-Walker type 2");
268 args.AddOption(&lin_solver, "-ls", "--lin-solver",
269 "Linear solver:\n\t"
270 "0: l1-Jacobi\n\t"
271 "1: CG\n\t"
272 "2: MINRES\n\t"
273 "3: MINRES + Jacobi preconditioner\n\t"
274 "4: MINRES + l1-Jacobi preconditioner");
275 args.AddOption(&max_lin_iter, "-li", "--lin-iter",
276 "Maximum number of iterations in the linear solve.");
277 args.AddOption(&move_bnd, "-bnd", "--move-boundary", "-fix-bnd",
278 "--fix-boundary",
279 "Enable motion along horizontal and vertical boundaries.");
280 args.AddOption(&combomet, "-cmb", "--combo-type",
281 "Combination of metrics options:\n\t"
282 "0: Use single metric\n\t"
283 "1: Shape + space-dependent size given analytically\n\t"
284 "2: Shape + adapted size given discretely; shared target");
285 args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
286 "-no-bec", "--balance-explicit-combo",
287 "Automatic balancing of explicit combo metrics.");
288 args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
289 "--no-hr-adaptivity",
290 "Enable hr-adaptivity.");
291 args.AddOption(&h_metric_id, "-hmid", "--h-metric",
292 "Same options as metric_id. Used to determine refinement"
293 " type for each element if h-adaptivity is enabled.");
294 args.AddOption(&normalization, "-nor", "--normalization", "-no-nor",
295 "--no-normalization",
296 "Make all terms in the optimization functional unitless.");
297 args.AddOption(&fdscheme, "-fd", "--fd_approximation",
298 "-no-fd", "--no-fd-approx",
299 "Enable finite difference based derivative computations.");
300 args.AddOption(&exactaction, "-ex", "--exact_action",
301 "-no-ex", "--no-exact-action",
302 "Enable exact action of TMOP_Integrator.");
303 args.AddOption(&integ_over_targ, "-it", "--integrate-target",
304 "-ir", "--integrate-reference",
305 "Integrate over target (-it) or reference (-ir) element.");
306 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
307 "--no-visualization",
308 "Enable or disable GLVis visualization.");
309 args.AddOption(&verbosity_level, "-vl", "--verbosity-level",
310 "Verbosity level for the involved iterative solvers:\n\t"
311 "0: no output\n\t"
312 "1: Newton iterations\n\t"
313 "2: Newton iterations + linear solver summaries\n\t"
314 "3: newton iterations + linear solver iterations");
315 args.AddOption(&adapt_eval, "-ae", "--adaptivity-evaluator",
316 "0 - Advection based (DEFAULT), 1 - GSLIB.");
317 args.AddOption(&devopt, "-d", "--device",
318 "Device configuration string, see Device::Configure().");
319 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
320 "--no-partial-assembly", "Enable Partial Assembly.");
321 args.AddOption(&n_hr_iter, "-nhr", "--n_hr_iter",
322 "Number of hr-adaptivity iterations.");
323 args.AddOption(&n_h_iter, "-nh", "--n_h_iter",
324 "Number of h-adaptivity iterations per r-adaptivity"
325 "iteration.");
326 args.AddOption(&mesh_node_order, "-mno", "--mesh_node_ordering",
327 "Ordering of mesh nodes."
328 "0 (default): byNodes, 1: byVDIM");
329 args.AddOption(&barrier_type, "-btype", "--barrier-type",
330 "0 - None,"
331 "1 - Shifted Barrier,"
332 "2 - Pseudo Barrier.");
333 args.AddOption(&worst_case_type, "-wctype", "--worst-case-type",
334 "0 - None,"
335 "1 - Beta,"
336 "2 - PMean.");
337 args.AddOption(&detj_bound, "-db", "--detj-bound",
338 "-no-db", "--no-detj-bound",
339 "Enable or disable strict enforcement of positive Jacobian "
340 "determinants to guarantee mesh validity for tensor-product " "elements.");
341 args.Parse();
342 if (!args.Good())
343 {
344 if (myid == 0) { args.PrintUsage(cout); }
345 return 1;
346 }
347 if (myid == 0) { args.PrintOptions(cout); }
348 if (h_metric_id < 0) { h_metric_id = metric_id; }
349
350 if (hradaptivity)
351 {
352 MFEM_VERIFY(strcmp(devopt,"cpu")==0, "HR-adaptivity is currently only"
353 " supported on cpus.");
354 }
355 Device device(devopt);
356 if (myid == 0) { device.Print();}
357
358 // Initialize and refine the starting mesh.
359 Mesh *mesh = new Mesh(mesh_file, 1, 1, false);
360 for (int lev = 0; lev < rs_levels; lev++) { mesh->UniformRefinement(); }
361 const int dim = mesh->Dimension();
362
363 if (hradaptivity) { mesh->EnsureNCMesh(); }
364
365 ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
366 delete mesh;
367 for (int lev = 0; lev < rp_levels; lev++) { pmesh->UniformRefinement(); }
368
369 auto s = pmesh->GetNodalFESpace();
370 const bool periodic = (s && s->IsDGSpace()) ? true : false;
371
372 // Define a FE space on the mesh, based on the input order. This space will
373 // also be used to represent the nodal positions of the mesh. We use a vector
374 // FE space which is a tensor product of a scalar FE space. The number of
375 // components in the vector finite element space matches the dimension.
377 if (mesh_poly_deg <= 0) { mesh_poly_deg = 2; }
378 if (periodic)
379 {
380 fec = new L2_FECollection(mesh_poly_deg, dim, BasisType::GaussLobatto);
381 }
382 else { fec = new H1_FECollection(mesh_poly_deg, dim); }
383 auto pfespace = new ParFiniteElementSpace(pmesh, fec, dim, mesh_node_order);
384
385 // Make the starting mesh curved. This means we define the mesh elements
386 // through a FE-based transformation of the reference element.
387 pmesh->SetNodalFESpace(pfespace);
388
389 // Get the mesh nodes (vertices and other DOFs in the FE space) as a FE grid
390 // function in pfespace. Note that changing x automatically changes the
391 // shapes of the mesh elements.
392 ParGridFunction x(pfespace);
393 pmesh->SetNodalGridFunction(&x);
394
395 // We create an H1 space for the mesh displacement. The displacement is
396 // always in a continuous space, even if the mesh is periodic.
397 // The nonlinear problem will be solved for the continuous displacement.
398 H1_FECollection fec_h1(mesh_poly_deg, dim);
399 ParFiniteElementSpace pfes_h1(pmesh, &fec_h1, dim, mesh_node_order);
400 ParGridFunction dx(&pfes_h1); dx = 0.0;
401
402 // Define a vector representing the minimal local mesh size in the mesh
403 // nodes. We index the nodes by the scalar version of the DOFs in pfespace.
404 // In addition, compute average mesh size and total volume.
405 // Note: this is MPI partition-dependent.
406 Vector h0(pfes_h1.GetNDofs());
407 h0 = infinity();
408 real_t mesh_volume = 0.0;
409 Array<int> dofs;
410 for (int i = 0; i < pmesh->GetNE(); i++)
411 {
412 // Get the local scalar element degrees of freedom in dofs.
413 pfes_h1.GetElementDofs(i, dofs);
414 // Adjust the value of h0 in dofs based on the local mesh size.
415 const real_t hi = pmesh->GetElementSize(i);
416 for (int j = 0; j < dofs.Size(); j++)
417 {
418 h0(dofs[j]) = min(h0(dofs[j]), hi);
419 }
420 mesh_volume += pmesh->GetElementVolume(i);
421 }
422 MPI_Allreduce(MPI_IN_PLACE, &mesh_volume, 1, MPITypeMap<real_t>::mpi_type,
423 MPI_SUM, MPI_COMM_WORLD);
424 const real_t small_phys_size = pow(mesh_volume, 1.0 / dim) / 100.0;
425
426 // Add a random perturbation to the nodes in the interior of the domain.
427 // We define a random grid function of pfespace and make sure that it is
428 // zero on the boundary and its values are locally of the order of h0.
429 // The latter is based on the DofToVDof() method which maps the scalar to
430 // the vector degrees of freedom in pfespace.
431 if (jitter > 0.0)
432 {
433 // The perturbation is always in H1, even though the mesh nodes can be in
434 // L2 when the mesh is periodic.
435 ParGridFunction rdm(&pfes_h1);
436 rdm.Randomize();
437 rdm -= 0.25; // Shift to random values in [-0.5,0.5].
438 rdm *= jitter;
439 rdm.HostReadWrite();
440 // Scale the random values to be of order of the local mesh size.
441 for (int i = 0; i < pfes_h1.GetNDofs(); i++)
442 {
443 for (int d = 0; d < dim; d++)
444 {
445 rdm(pfes_h1.DofToVDof(i, d)) *= h0(i);
446 }
447 }
448 // Set the boundary values to zero. Note that periodic periodic boundaries
449 // will be free to move.
450 Array<int> vdofs;
451 for (int i = 0; i < pfes_h1.GetNBE(); i++)
452 {
453 pfes_h1.GetBdrElementVDofs(i, vdofs);
454 for (int j = 0; j < vdofs.Size(); j++) { rdm(vdofs[j]) = 0.0; }
455 }
456
457 if (periodic)
458 {
459 // For H1 the perturbation is controlled by the true nodes.
460 rdm.SetFromTrueVector();
461 ParGridFunction rdm_l2(pfespace);
462 rdm_l2.ProjectGridFunction(rdm);
463 x -= rdm_l2;
464 }
465 else
466 {
467 x -= rdm;
468 // For H1 the perturbation is controlled by the true nodes.
470 }
471
472 if (visualization)
473 {
474 socketstream vis1;
475 common::VisualizeMesh(vis1, "localhost", 19916, *pmesh, "Perturbed",
476 300, 600, 300, 300);
477 }
478 }
479
480 // Save the starting (prior to the optimization) mesh to a file. This
481 // output can be viewed later using GLVis: "glvis -m perturbed -np #tasks".
482 {
483 ostringstream mesh_name;
484 mesh_name << "perturbed.mesh";
485 ofstream mesh_ofs(mesh_name.str().c_str());
486 mesh_ofs.precision(8);
487 pmesh->PrintAsOne(mesh_ofs);
488 }
489
490 // Store the starting (prior to the optimization) positions.
491 ParGridFunction x0(x);
492
493 // Form the integrator that uses the chosen metric and target.
494 real_t min_detJ = -0.1;
495 TMOP_QualityMetric *metric = NULL;
496 switch (metric_id)
497 {
498 // T-metrics
499 case 1: metric = new TMOP_Metric_001; break;
500 case 2: metric = new TMOP_Metric_002; break;
501 case 4: metric = new TMOP_Metric_004; break;
502 case 7: metric = new TMOP_Metric_007; break;
503 case 9: metric = new TMOP_Metric_009; break;
504 case 14: metric = new TMOP_Metric_014; break;
505 case 22: metric = new TMOP_Metric_022(min_detJ); break;
506 case 50: metric = new TMOP_Metric_050; break;
507 case 55: metric = new TMOP_Metric_055; break;
508 case 56: metric = new TMOP_Metric_056; break;
509 case 58: metric = new TMOP_Metric_058; break;
510 case 66: metric = new TMOP_Metric_066(0.5); break;
511 case 77: metric = new TMOP_Metric_077; break;
512 case 80: metric = new TMOP_Metric_080(0.5); break;
513 case 85: metric = new TMOP_Metric_085; break;
514 case 90: metric = new TMOP_Metric_090; break;
515 case 94: metric = new TMOP_Metric_094; break;
516 case 98: metric = new TMOP_Metric_098; break;
517 // case 211: metric = new TMOP_Metric_211; break;
518 // case 252: metric = new TMOP_Metric_252(min_detJ); break;
519 case 301: metric = new TMOP_Metric_301; break;
520 case 302: metric = new TMOP_Metric_302; break;
521 case 303: metric = new TMOP_Metric_303; break;
522 case 304: metric = new TMOP_Metric_304; break;
523 // case 311: metric = new TMOP_Metric_311; break;
524 case 313: metric = new TMOP_Metric_313(min_detJ); break;
525 case 315: metric = new TMOP_Metric_315; break;
526 case 316: metric = new TMOP_Metric_316; break;
527 case 321: metric = new TMOP_Metric_321; break;
528 case 322: metric = new TMOP_Metric_322; break;
529 case 323: metric = new TMOP_Metric_323; break;
530 case 328: metric = new TMOP_Metric_328; break;
531 case 332: metric = new TMOP_Metric_332(0.5); break;
532 case 333: metric = new TMOP_Metric_333(0.5); break;
533 case 334: metric = new TMOP_Metric_334(0.5); break;
534 case 338: metric = new TMOP_Metric_338; break;
535 case 347: metric = new TMOP_Metric_347(0.5); break;
536 // case 352: metric = new TMOP_Metric_352(min_detJ); break;
537 case 360: metric = new TMOP_Metric_360; break;
538 // A-metrics
539 case 11: metric = new TMOP_AMetric_011; break;
540 case 36: metric = new TMOP_AMetric_036; break;
541 case 49: metric = new TMOP_AMetric_049(0.9); break;
542 case 51: metric = new TMOP_AMetric_051; break;
543 case 107: metric = new TMOP_AMetric_107; break;
544 case 126: metric = new TMOP_AMetric_126(0.9); break;
545 default:
546 if (myid == 0) { cout << "Unknown metric_id: " << metric_id << endl; }
547 return 3;
548 }
549 TMOP_QualityMetric *h_metric = NULL;
550 if (hradaptivity)
551 {
552 switch (h_metric_id)
553 {
554 case 1: h_metric = new TMOP_Metric_001; break;
555 case 2: h_metric = new TMOP_Metric_002; break;
556 case 7: h_metric = new TMOP_Metric_007; break;
557 case 9: h_metric = new TMOP_Metric_009; break;
558 case 55: h_metric = new TMOP_Metric_055; break;
559 case 56: h_metric = new TMOP_Metric_056; break;
560 case 58: h_metric = new TMOP_Metric_058; break;
561 case 77: h_metric = new TMOP_Metric_077; break;
562 case 315: h_metric = new TMOP_Metric_315; break;
563 case 316: h_metric = new TMOP_Metric_316; break;
564 case 321: h_metric = new TMOP_Metric_321; break;
565 default: cout << "Metric_id not supported for h-adaptivity: " << h_metric_id <<
566 endl;
567 return 3;
568 }
569 }
570
572 switch (barrier_type)
573 {
574 case 0: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::None;
575 break;
576 case 1: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::Shifted;
577 break;
578 case 2: btype = TMOP_WorstCaseUntangleOptimizer_Metric::BarrierType::Pseudo;
579 break;
580 default: cout << "barrier_type not supported: " << barrier_type << endl;
581 return 3;
582 }
583
585 switch (worst_case_type)
586 {
587 case 0: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::None;
588 break;
589 case 1: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::Beta;
590 break;
591 case 2: wctype = TMOP_WorstCaseUntangleOptimizer_Metric::WorstCaseType::PMean;
592 break;
593 default: cout << "worst_case_type not supported: " << worst_case_type << endl;
594 return 3;
595 }
596
597 TMOP_QualityMetric *untangler_metric = NULL;
598 if (barrier_type > 0 || worst_case_type > 0)
599 {
600 if (barrier_type > 0)
601 {
602 MFEM_VERIFY(metric_id == 4 || metric_id == 14 || metric_id == 66,
603 "Metric not supported for shifted/pseudo barriers.");
604 }
605 untangler_metric = new TMOP_WorstCaseUntangleOptimizer_Metric(*metric,
606 2,
607 1.5,
608 0.001,//0.01 for pseudo barrier
609 0.001,
610 btype,
611 wctype);
612 }
613
614 if (metric_id < 300 || h_metric_id < 300)
615 {
616 MFEM_VERIFY(dim == 2, "Incompatible metric for 3D meshes");
617 }
618 if (metric_id >= 300 || h_metric_id >= 300)
619 {
620 MFEM_VERIFY(dim == 3, "Incompatible metric for 2D meshes");
621 }
622
624 TargetConstructor *target_c = NULL;
625 HessianCoefficient *adapt_coeff = NULL;
626 HRHessianCoefficient *hr_adapt_coeff = NULL;
627 int ind_fec_order = (target_id >= 5 && target_id <= 8 && !fdscheme) ?
628 1 : mesh_poly_deg;
629 H1_FECollection ind_fec(ind_fec_order, dim);
630 ParFiniteElementSpace ind_fes(pmesh, &ind_fec);
631 ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim);
632 ParGridFunction size(&ind_fes), aspr(&ind_fes), ori(&ind_fes);
633 ParGridFunction aspr3d(&ind_fesv);
634
635 const AssemblyLevel al =
636 pa ? AssemblyLevel::PARTIAL : AssemblyLevel::LEGACY;
637
638 switch (target_id)
639 {
640 case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break;
641 case 2: target_t = TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE; break;
642 case 3: target_t = TargetConstructor::IDEAL_SHAPE_GIVEN_SIZE; break;
643 case 4:
644 {
646 AnalyticAdaptTC *tc = new AnalyticAdaptTC(target_t);
647 adapt_coeff = new HessianCoefficient(dim, metric_id);
648 tc->SetAnalyticTargetSpec(NULL, NULL, adapt_coeff);
649 target_c = tc;
650 break;
651 }
652 case 5: // Discrete size 2D or 3D
653 {
655 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
656 if (adapt_eval == 0)
657 {
659 }
660 else
661 {
662#ifdef MFEM_USE_GSLIB
664#else
665 MFEM_ABORT("MFEM is not built with GSLIB.");
666#endif
667 }
668 ConstructSizeGF(size);
669 tc->SetParDiscreteTargetSize(size);
670 tc->SetMinSizeForTargets(size.Min());
671 target_c = tc;
672 break;
673 }
674 case 6: // material indicator 2D
675 {
676 ParGridFunction d_x(&ind_fes), d_y(&ind_fes), disc(&ind_fes);
677
679 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
681 disc.ProjectCoefficient(mat_coeff);
682 if (adapt_eval == 0)
683 {
685 }
686 else
687 {
688#ifdef MFEM_USE_GSLIB
690#else
691 MFEM_ABORT("MFEM is not built with GSLIB.");
692#endif
693 }
694 // Diffuse the interface
696
697 // Get partials with respect to x and y of the grid function
698 disc.GetDerivative(1,0,d_x);
699 disc.GetDerivative(1,1,d_y);
700
701 // Compute the squared magnitude of the gradient
702 for (int i = 0; i < size.Size(); i++)
703 {
704 size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2);
705 }
706 const real_t max = size.Max();
707 real_t max_all;
708 MPI_Allreduce(&max, &max_all, 1, MPITypeMap<real_t>::mpi_type,
709 MPI_MAX, MPI_COMM_WORLD);
710
711 for (int i = 0; i < d_x.Size(); i++)
712 {
713 d_x(i) = std::abs(d_x(i));
714 d_y(i) = std::abs(d_y(i));
715 }
716 const real_t eps = 0.01;
717 const real_t aspr_ratio = 20.0;
718 const real_t size_ratio = 40.0;
719
720 for (int i = 0; i < size.Size(); i++)
721 {
722 size(i) = (size(i)/max_all);
723 aspr(i) = (d_x(i)+eps)/(d_y(i)+eps);
724 aspr(i) = 0.1 + 0.9*(1-size(i))*(1-size(i));
725 if (aspr(i) > aspr_ratio) {aspr(i) = aspr_ratio;}
726 if (aspr(i) < 1.0/aspr_ratio) {aspr(i) = 1.0/aspr_ratio;}
727 }
728 Vector vals;
729 const int NE = pmesh->GetNE();
730 real_t volume = 0.0, volume_ind = 0.0;
731
732 for (int i = 0; i < NE; i++)
733 {
735 const IntegrationRule &ir =
736 IntRules.Get(pmesh->GetElementBaseGeometry(i), Tr->OrderJ());
737 size.GetValues(i, ir, vals);
738 for (int j = 0; j < ir.GetNPoints(); j++)
739 {
740 const IntegrationPoint &ip = ir.IntPoint(j);
741 Tr->SetIntPoint(&ip);
742 volume += ip.weight * Tr->Weight();
743 volume_ind += vals(j) * ip.weight * Tr->Weight();
744 }
745 }
746 real_t volume_all, volume_ind_all;
747 MPI_Allreduce(&volume, &volume_all, 1, MPITypeMap<real_t>::mpi_type,
748 MPI_SUM, MPI_COMM_WORLD);
749 MPI_Allreduce(&volume_ind, &volume_ind_all, 1,
750 MPITypeMap<real_t>::mpi_type, MPI_SUM, MPI_COMM_WORLD);
751 const int NE_ALL = pmesh->GetGlobalNE();
752
753 const real_t avg_zone_size = volume_all / NE_ALL;
754
755 const real_t small_avg_ratio =
756 (volume_ind_all + (volume_all - volume_ind_all) / size_ratio)
757 / volume_all;
758
759 const real_t small_zone_size = small_avg_ratio * avg_zone_size;
760 const real_t big_zone_size = size_ratio * small_zone_size;
761
762 for (int i = 0; i < size.Size(); i++)
763 {
764 const real_t val = size(i);
765 const real_t a = (big_zone_size - small_zone_size) / small_zone_size;
766 size(i) = big_zone_size / (1.0+a*val);
767 }
768
769 DiffuseField(size, 2);
770 DiffuseField(aspr, 2);
771
772 tc->SetParDiscreteTargetSize(size);
773 tc->SetMinSizeForTargets(size.Min());
775 target_c = tc;
776 break;
777 }
778 case 7: // Discrete aspect ratio 3D
779 {
781 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
782 if (adapt_eval == 0)
783 {
785 }
786 else
787 {
788#ifdef MFEM_USE_GSLIB
790#else
791 MFEM_ABORT("MFEM is not built with GSLIB.");
792#endif
793 }
795 aspr3d.ProjectCoefficient(fd_aspr3d);
797 target_c = tc;
798 break;
799 }
800 case 8: // shape/size + orientation 2D
801 {
803 DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
804 if (adapt_eval == 0)
805 {
807 }
808 else
809 {
810#ifdef MFEM_USE_GSLIB
812#else
813 MFEM_ABORT("MFEM is not built with GSLIB.");
814#endif
815 }
816
817 ConstantCoefficient size_coeff(0.1*0.1);
818 size.ProjectCoefficient(size_coeff);
819 tc->SetParDiscreteTargetSize(size);
820 tc->SetMinSizeForTargets(size.Min());
821
823 ori.ProjectCoefficient(ori_coeff);
825 target_c = tc;
826 break;
827 }
828 // Targets used for hr-adaptivity tests.
829 case 9: // size target in an annular region.
830 case 10: // size+aspect-ratio in an annular region.
831 case 11: // size+aspect-ratio target for a rotate sine wave
832 {
834 AnalyticAdaptTC *tc = new AnalyticAdaptTC(target_t);
835 hr_adapt_coeff = new HRHessianCoefficient(dim, target_id - 9);
836 tc->SetAnalyticTargetSpec(NULL, NULL, hr_adapt_coeff);
837 target_c = tc;
838 break;
839 }
840 default:
841 if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; }
842 return 3;
843 }
844 if (target_c == NULL)
845 {
846 target_c = new TargetConstructor(target_t, MPI_COMM_WORLD);
847 }
848 target_c->SetNodes(x0);
849
850 TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
851 ? untangler_metric
852 : metric;
853 auto tmop_integ = new TMOP_Integrator(metric_to_use, target_c, h_metric);
854 tmop_integ->IntegrateOverTarget(integ_over_targ);
855 if (barrier_type > 0 || worst_case_type > 0)
856 {
857 tmop_integ->ComputeUntangleMetricQuantiles(x, *pfespace);
858 }
859
860 // Finite differences for computations of derivatives.
861 if (fdscheme)
862 {
863 MFEM_VERIFY(pa == false, "PA for finite differences is not implemented.");
864 tmop_integ->EnableFiniteDifferences(x);
865 }
866 tmop_integ->SetExactActionFlag(exactaction);
867
868 // Setup the quadrature rules for the TMOP integrator.
869 IntegrationRules *irules = NULL;
870 switch (quad_type)
871 {
872 case 1: irules = &IntRulesLo; break;
873 case 2: irules = &IntRules; break;
874 case 3: irules = &IntRulesCU; break;
875 default:
876 if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
877 return 3;
878 }
879 tmop_integ->SetIntegrationRules(*irules, quad_order);
880 if (myid == 0 && dim == 2)
881 {
882 cout << "Triangle quadrature points: "
883 << irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
884 << "\nQuadrilateral quadrature points: "
885 << irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
886 }
887 if (myid == 0 && dim == 3)
888 {
889 cout << "Tetrahedron quadrature points: "
890 << irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
891 << "\nHexahedron quadrature points: "
892 << irules->Get(Geometry::CUBE, quad_order).GetNPoints()
893 << "\nPrism quadrature points: "
894 << irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
895 }
896
897 // Automatically balanced gamma in composite metrics.
898 auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
899 if (metric_combo && bal_expl_combo)
900 {
901 Vector bal_weights;
902 auto ir = irules->Get(pmesh->GetTypicalElementGeometry(), quad_order);
903 metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights, pa, &ir);
904 metric_combo->SetWeights(bal_weights);
905 }
906
907 // Limit the node movement.
908 // The limiting distances can be given by a general function of space.
909 ParFiniteElementSpace dist_pfespace(pmesh, &fec_h1); // scalar space
910 ParGridFunction dist(&dist_pfespace);
911 dist = 1.0;
912 // The small_phys_size is relevant only with proper normalization.
913 if (normalization) { dist = small_phys_size; }
914 ConstantCoefficient lim_coeff(lim_const);
915 if (lim_const != 0.0) { tmop_integ->EnableLimiting(x0, dist, lim_coeff); }
916
917 // Adaptive limiting.
918 ParGridFunction adapt_lim_gf0_1(&ind_fes);
919 ParGridFunction adapt_lim_gf0_2(&ind_fes);
920 ConstantCoefficient adapt_lim_coeff_1(adapt_lim_const);
921 const real_t adapt_lim_const_2 = 0.5 * adapt_lim_const;
922 ConstantCoefficient adapt_lim_coeff_2(adapt_lim_const_2);
923 AdaptivityEvaluator *adapt_lim_eval = NULL;
924 if (adapt_lim_const > 0.0)
925 {
926 FunctionCoefficient adapt_lim_gf0_coeff_1(adapt_lim_fun);
927 FunctionCoefficient adapt_lim_gf0_coeff_2(adapt_lim_fun2);
928 adapt_lim_gf0_1.ProjectCoefficient(adapt_lim_gf0_coeff_1);
929 adapt_lim_gf0_2.ProjectCoefficient(adapt_lim_gf0_coeff_2);
930
931 if (adapt_eval == 0) { adapt_lim_eval = new AdvectorCG(al); }
932 else if (adapt_eval == 1)
933 {
934#ifdef MFEM_USE_GSLIB
935 adapt_lim_eval = new InterpolatorFP;
936#else
937 MFEM_ABORT("MFEM is not built with GSLIB support!");
938#endif
939 }
940 else { MFEM_ABORT("Bad interpolation option."); }
941
943 Array<Coefficient *> coeff(2);
944 Array<real_t> delta_max(2);
945 z0[0] = &adapt_lim_gf0_1;
946 z0[1] = &adapt_lim_gf0_2;
947 coeff[0] = &adapt_lim_coeff_1;
948 coeff[1] = &adapt_lim_coeff_2;
949 delta_max[0] = 1.0;
950 delta_max[1] = 0.5;
951 tmop_integ->EnableAdaptiveLimiting(z0, coeff, *adapt_lim_eval, delta_max);
952 if (visualization)
953 {
954 socketstream vis1, vis2;
955 common::VisualizeField(vis1, "localhost", 19916, adapt_lim_gf0_1,
956 "Zeta0(1) - initial mesh", 300, 600, 300, 300);
957 common::VisualizeField(vis2, "localhost", 19916, adapt_lim_gf0_2,
958 "Zeta0(2) - initial mesh", 300, 900, 300, 300);
959 }
960 }
961
962 //
963 // Setup the ParNonlinearForm which defines the integral of interest, its
964 // first and second derivatives.
965 //
966 // Note that the TMOP optimization always operates on H1 spaces. For periodic
967 // meshes, TMOP solves for a continuous periodic displacement.
968 ParNonlinearForm a(&pfes_h1);
969 if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
970 // We can use a combination of metrics, i.e., optimize the sum of two
971 // integrals, where both are scaled by used-defined space-dependent weights.
972 // Note that there are no command-line options for the weights and the type
973 // of the second metric; one should update those in the code.
974 ConstantCoefficient *metric_coeff1 = NULL;
975 TMOP_QualityMetric *metric2 = NULL;
976 TargetConstructor *target_c2 = NULL;
977 FunctionCoefficient metric_coeff2(weight_fun);
978 TMOPComboIntegrator *combo = nullptr;
979 if (combomet > 0)
980 {
981 // First metric.
982 metric_coeff1 = new ConstantCoefficient(1.0);
983 tmop_integ->SetCoefficient(*metric_coeff1);
984
985 // Second metric.
986 if (dim == 2) { metric2 = new TMOP_Metric_077; }
987 else { metric2 = new TMOP_Metric_315; }
988 TMOP_Integrator *tmop_integ2 = NULL;
989 if (combomet == 1)
990 {
991 target_c2 = new TargetConstructor(
993 target_c2->SetVolumeScale(0.01);
994 target_c2->SetNodes(x0);
995 tmop_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
996 tmop_integ2->SetCoefficient(metric_coeff2);
997 }
998 else { tmop_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
999 tmop_integ2->IntegrateOverTarget(integ_over_targ);
1000 tmop_integ2->SetIntegrationRules(*irules, quad_order);
1001 if (fdscheme) { tmop_integ2->EnableFiniteDifferences(x); }
1002 tmop_integ2->SetExactActionFlag(exactaction);
1003
1004 combo = new TMOPComboIntegrator;
1005 combo->AddTMOPIntegrator(tmop_integ);
1006 combo->AddTMOPIntegrator(tmop_integ2);
1007 if (lim_const != 0.0) { combo->EnableLimiting(x0, dist, lim_coeff); }
1008
1009 a.AddDomainIntegrator(combo);
1010 }
1011 else { a.AddDomainIntegrator(tmop_integ); }
1012 // The PA setup must be performed after all integrators have been added.
1013 if (pa) { a.Setup(); }
1014
1015 // Has to be after the enabling of the limiting / alignment, as it computes
1016 // normalization factors for these terms as well.
1017 if (normalization)
1018 {
1019 tmop_integ->ParEnableNormalization(x0);
1020 if (combomet) { combo->ParEnableNormalization(x0); }
1021 }
1022
1023 // Compute the minimum det(J) of the starting mesh.
1024 min_detJ = infinity();
1025 const int NE = pmesh->GetNE();
1026 for (int i = 0; i < NE; i++)
1027 {
1028 const IntegrationRule &ir =
1029 irules->Get(pfespace->GetFE(i)->GetGeomType(), quad_order);
1031 for (int j = 0; j < ir.GetNPoints(); j++)
1032 {
1033 transf->SetIntPoint(&ir.IntPoint(j));
1034 min_detJ = min(min_detJ, transf->Jacobian().Det());
1035 }
1036 }
1037 real_t minJ0;
1038 MPI_Allreduce(&min_detJ, &minJ0, 1, MPITypeMap<real_t>::mpi_type,
1039 MPI_MIN, MPI_COMM_WORLD);
1040 min_detJ = minJ0;
1041 if (myid == 0)
1042 { cout << "Minimum det(J) of the original mesh is " << min_detJ << endl; }
1043
1044 if (min_detJ < 0.0 && barrier_type == 0
1045 && metric_id != 22 && metric_id != 211 && metric_id != 252
1046 && metric_id != 311 && metric_id != 313 && metric_id != 352)
1047 {
1048 MFEM_ABORT("The input mesh is inverted! Try an untangling metric.");
1049 }
1050 if (min_detJ < 0.0)
1051 {
1052 MFEM_VERIFY(target_t == TargetConstructor::IDEAL_SHAPE_UNIT_SIZE,
1053 "Untangling is supported only for ideal targets.");
1054
1055 const DenseMatrix &Wideal =
1057 min_detJ /= Wideal.Det();
1058
1059 real_t h0_min = h0.Min();
1060 MPI_Allreduce(MPI_IN_PLACE, &h0_min, 1, MPITypeMap<real_t>::mpi_type,
1061 MPI_MIN, MPI_COMM_WORLD);
1062 // Slightly below minJ0 to avoid div by 0.
1063 min_detJ -= 0.01 * h0_min;
1064 }
1065
1066 // For HR tests, the energy is normalized by the number of elements.
1067 if (periodic) { tmop_integ->SetInitialMeshPos(&x0); }
1068 const real_t init_energy = a.GetParGridFunctionEnergy(periodic ? dx : x) /
1069 (hradaptivity ? pmesh->GetGlobalNE() : 1);
1070 real_t init_metric_energy = init_energy;
1071 if (lim_const > 0.0 || adapt_lim_const > 0.0)
1072 {
1073 lim_coeff.constant = 0.0;
1074 adapt_lim_coeff_1.constant = 0.0;
1075 adapt_lim_coeff_2.constant = 0.0;
1076 init_metric_energy = a.GetParGridFunctionEnergy(periodic ? dx : x) /
1077 (hradaptivity ? pmesh->GetGlobalNE() : 1);
1078 lim_coeff.constant = lim_const;
1079 adapt_lim_coeff_1.constant = adapt_lim_const;
1080 adapt_lim_coeff_2.constant = adapt_lim_const_2;
1081 }
1082
1083 // Visualize the starting mesh and metric values.
1084 // Note that for combinations of metrics, this only shows the first metric.
1085 if (visualization)
1086 {
1087 char title[] = "Initial metric values";
1088 vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 0);
1089 }
1090
1091 // Fix all boundary nodes, or fix only a given component depending on the
1092 // boundary attributes of the given mesh.
1093 // Attributes 1/2/3 correspond to fixed x/y/z components of the node.
1094 // Attribute 4 corresponds to an entirely fixed node.
1095 // All other attributes represent unconstrained boundary nodes.
1096 if (move_bnd == false)
1097 {
1098 Array<int> ess_bdr(pmesh->bdr_attributes.Max());
1099 ess_bdr = 1;
1100 a.SetEssentialBC(ess_bdr);
1101 }
1102 else
1103 {
1104 int n = 0;
1105 for (int i = 0; i < pmesh->GetNBE(); i++)
1106 {
1107 const int nd = pfes_h1.GetBE(i)->GetDof();
1108 const int attr = pmesh->GetBdrElement(i)->GetAttribute();
1109 MFEM_VERIFY(!(dim == 2 && attr == 3),
1110 "Boundary attribute 3 must be used only for 3D meshes. "
1111 "Adjust the attributes (1/2/3/4 for fixed x/y/z/all "
1112 "components, rest for free nodes), or use -fix-bnd.");
1113 if (attr == 1 || attr == 2 || attr == 3) { n += nd; }
1114 if (attr == 4) { n += nd * dim; }
1115 }
1116 Array<int> vdofs, ess_vdofs(n);
1117 n = 0;
1118 for (int i = 0; i < pmesh->GetNBE(); i++)
1119 {
1120 const int nd = pfes_h1.GetBE(i)->GetDof();
1121 const int attr = pmesh->GetBdrElement(i)->GetAttribute();
1122 pfes_h1.GetBdrElementVDofs(i, vdofs);
1123 if (attr == 1) // Fix x components.
1124 {
1125 for (int j = 0; j < nd; j++)
1126 { ess_vdofs[n++] = vdofs[j]; }
1127 }
1128 else if (attr == 2) // Fix y components.
1129 {
1130 for (int j = 0; j < nd; j++)
1131 { ess_vdofs[n++] = vdofs[j+nd]; }
1132 }
1133 else if (attr == 3) // Fix z components.
1134 {
1135 for (int j = 0; j < nd; j++)
1136 { ess_vdofs[n++] = vdofs[j+2*nd]; }
1137 }
1138 else if (attr == 4) // Fix all components.
1139 {
1140 for (int j = 0; j < vdofs.Size(); j++)
1141 { ess_vdofs[n++] = vdofs[j]; }
1142 }
1143 }
1144 a.SetEssentialVDofs(ess_vdofs);
1145 }
1146
1147 // As we use the inexact Newton method to solve the resulting nonlinear
1148 // system, here we setup the linear solver for the system's Jacobian.
1149 Solver *S = NULL, *S_prec = NULL;
1150#ifdef MFEM_USE_SINGLE
1151 const real_t linsol_rtol = 1e-5;
1152#else
1153 const real_t linsol_rtol = 1e-12;
1154#endif
1155 // Level of output.
1156 IterativeSolver::PrintLevel linsolver_print;
1157 if (verbosity_level == 2)
1158 { linsolver_print.Errors().Warnings().FirstAndLast(); }
1159 if (verbosity_level > 2)
1160 { linsolver_print.Errors().Warnings().Iterations(); }
1161 if (lin_solver == 0)
1162 {
1163 S = new DSmoother(1, 1.0, max_lin_iter);
1164 }
1165 else if (lin_solver == 1)
1166 {
1167 CGSolver *cg = new CGSolver(MPI_COMM_WORLD);
1168 cg->SetMaxIter(max_lin_iter);
1169 cg->SetRelTol(linsol_rtol);
1170 cg->SetAbsTol(0.0);
1171 cg->SetPrintLevel(linsolver_print);
1172 S = cg;
1173 }
1174 else
1175 {
1176 MINRESSolver *minres = new MINRESSolver(MPI_COMM_WORLD);
1177 minres->SetMaxIter(max_lin_iter);
1178 minres->SetRelTol(linsol_rtol);
1179 minres->SetAbsTol(0.0);
1180 minres->SetPrintLevel(linsolver_print);
1181 if (lin_solver == 3 || lin_solver == 4)
1182 {
1183 if (pa)
1184 {
1185 MFEM_VERIFY(lin_solver != 4, "PA l1-Jacobi is not implemented");
1186 auto js = new OperatorJacobiSmoother;
1187 js->SetPositiveDiagonal(true);
1188 S_prec = js;
1189 }
1190 else
1191 {
1192 auto hs = new HypreSmoother;
1193 hs->SetType((lin_solver == 3) ? HypreSmoother::Jacobi
1194 /* */ : HypreSmoother::l1Jacobi, 1);
1195 hs->SetPositiveDiagonal(true);
1196 S_prec = hs;
1197 }
1198 minres->SetPreconditioner(*S_prec);
1199 }
1200 S = minres;
1201 }
1202
1203 //
1204 // Perform the nonlinear optimization.
1205 //
1206 const IntegrationRule &ir =
1207 irules->Get(pmesh->GetTypicalElementGeometry(), quad_order);
1208 TMOPNewtonSolver solver(pfespace->GetComm(), ir, solver_type);
1209 // Provide all integration rules in case of a mixed mesh.
1210 solver.SetIntegrationRules(*irules, quad_order);
1211 // Specify linear solver when we use a Newton-based solver.
1212 if (solver_type == 0) { solver.SetPreconditioner(*S); }
1213 // For untangling, the solver will update the min det(T) values.
1214 solver.SetMinDetPtr(&min_detJ);
1215 solver.SetMaxIter(solver_iter);
1216 solver.SetRelTol(solver_rtol);
1217 solver.SetAbsTol(0.0);
1218 if (solver_art_type > 0)
1219 {
1220 solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9);
1221 }
1222 if (detj_bound)
1223 {
1224 const int bound_refs = 4; // number of refinements to compute bounds
1225 const int bound_recs = 4; // number of recursions for the bound search
1226 solver.EnsurePositiveDeterminantBound(*pmesh, bound_refs, bound_recs);
1227 }
1228 // Level of output.
1229 IterativeSolver::PrintLevel newton_print;
1230 if (verbosity_level > 0) { newton_print.Errors().Warnings().Iterations(); }
1231 else { newton_print.Errors().Warnings(); }
1232 solver.SetPrintLevel(newton_print);
1233 // hr-adaptivity solver.
1234 // If hr-adaptivity is disabled, r-adaptivity is done once using the
1235 // TMOPNewtonSolver.
1236 // Otherwise, "hr_iter" iterations of r-adaptivity are done followed by
1237 // "h_per_r_iter" iterations of h-adaptivity after each r-adaptivity.
1238 // The solver terminates if an h-adaptivity iteration does not modify
1239 // any element in the mesh.
1240 TMOPHRSolver hr_solver(*pmesh, a, solver,
1241 x, move_bnd, hradaptivity,
1242 mesh_poly_deg, h_metric_id,
1243 n_hr_iter, n_h_iter);
1244 hr_solver.AddGridFunctionForUpdate(&x0);
1245 hr_solver.AddFESpaceForUpdate(&pfes_h1);
1246 if (adapt_lim_const > 0.)
1247 {
1248 hr_solver.AddGridFunctionForUpdate(&adapt_lim_gf0_1);
1249 hr_solver.AddGridFunctionForUpdate(&adapt_lim_gf0_2);
1250 hr_solver.AddFESpaceForUpdate(&ind_fes);
1251 }
1252 hr_solver.Mult();
1253
1254 // Save the optimized mesh to a file. This output can be viewed later
1255 // using GLVis: "glvis -m optimized -np num_mpi_tasks".
1256 {
1257 ostringstream mesh_name;
1258 mesh_name << "optimized.mesh";
1259 ofstream mesh_ofs(mesh_name.str().c_str());
1260 mesh_ofs.precision(8);
1261 pmesh->PrintAsOne(mesh_ofs);
1262 }
1263
1264 // Report the final energy of the functional.
1265 if (periodic)
1266 {
1267 ParGridFunction dx_L2(x); dx_L2 -= x0;
1268 // Assumes Gauss-Lobatto and continuity in x and x_0 across faces.
1269 dx.ProjectGridFunction(dx_L2);
1270 }
1271 if (periodic) { tmop_integ->SetInitialMeshPos(&x0); }
1272 const real_t fin_energy = a.GetParGridFunctionEnergy(periodic ? dx : x) /
1273 (hradaptivity ? pmesh->GetGlobalNE() : 1);
1274 real_t fin_metric_energy = fin_energy;
1275 if (lim_const > 0.0 || adapt_lim_const > 0.0)
1276 {
1277 lim_coeff.constant = 0.0;
1278 adapt_lim_coeff_1.constant = 0.0;
1279 adapt_lim_coeff_2.constant = 0.0;
1280 fin_metric_energy = a.GetParGridFunctionEnergy(periodic ? dx : x) /
1281 (hradaptivity ? pmesh->GetGlobalNE() : 1);
1282 lim_coeff.constant = lim_const;
1283 adapt_lim_coeff_1.constant = adapt_lim_const;
1284 adapt_lim_coeff_2.constant = adapt_lim_const_2;
1285 }
1286 if (myid == 0)
1287 {
1288 std::cout << std::scientific << std::setprecision(4);
1289 cout << "Initial strain energy: " << init_energy
1290 << " = metrics: " << init_metric_energy
1291 << " + extra terms: " << init_energy - init_metric_energy << endl;
1292 cout << " Final strain energy: " << fin_energy
1293 << " = metrics: " << fin_metric_energy
1294 << " + extra terms: " << fin_energy - fin_metric_energy << endl;
1295 cout << "The strain energy decreased by: "
1296 << (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
1297 }
1298
1299 // Visualize the final mesh and metric values.
1300 if (visualization)
1301 {
1302 char title[] = "Final metric values";
1303 vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 600);
1304 }
1305
1306 if (adapt_lim_const > 0.0 && visualization)
1307 {
1308 socketstream vis1, vis2;
1309 common::VisualizeField(vis1, "localhost", 19916, adapt_lim_gf0_1,
1310 "Zeta0(1) - final mesh", 600, 600, 300, 300);
1311 common::VisualizeField(vis2, "localhost", 19916, adapt_lim_gf0_2,
1312 "Zeta0(2) - final mesh", 600, 900, 300, 300);
1313 }
1314
1315 // Visualize the mesh displacement.
1316 if (visualization)
1317 {
1318 x0 -= x;
1319 socketstream sock;
1320 if (myid == 0)
1321 {
1322 sock.open("localhost", 19916);
1323 sock << "solution\n";
1324 }
1325 pmesh->PrintAsOne(sock);
1326 x0.SaveAsOne(sock);
1327 if (myid == 0)
1328 {
1329 sock << "window_title 'Displacements'\n"
1330 << "window_geometry "
1331 << 1200 << " " << 0 << " " << 600 << " " << 600 << "\n"
1332 << "keys jRmclA" << endl;
1333 }
1334 }
1335
1336 delete S;
1337 delete S_prec;
1338 delete target_c2;
1339 delete metric2;
1340 delete metric_coeff1;
1341 delete adapt_lim_eval;
1342 delete target_c;
1343 delete hr_adapt_coeff;
1344 delete adapt_coeff;
1345 delete h_metric;
1346 delete metric;
1347 delete untangler_metric;
1348 delete pfespace;
1349 delete fec;
1350 delete pmesh;
1351
1352 return 0;
1353}
virtual void SetAnalyticTargetSpec(Coefficient *sspec, VectorCoefficient *vspec, TMOPMatrixCoefficient *mspec)
Definition tmop.cpp:2603
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
int Size() const
Return the logical size of the array.
Definition array.hpp:192
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
Conjugate gradient method.
Definition solvers.hpp:627
A coefficient that is constant across space and time.
Jacobi-type diagonal smoother of a sparse matrix.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
real_t Det() const
Definition densemat.cpp:496
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:319
virtual void SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_)
Definition tmop.cpp:2769
void SetMinSizeForTargets(real_t min_size_)
Definition tmop.hpp:1961
virtual void SetParDiscreteTargetSize(const ParGridFunction &tspec_)
Definition tmop.cpp:2749
void SetAdaptivityEvaluator(AdaptivityEvaluator *ae)
Definition tmop.hpp:1919
virtual void SetParDiscreteTargetOrientation(const ParGridFunction &tspec_)
Definition tmop.cpp:2779
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
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:132
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
int GetAttribute() const
Return element's attribute.
Definition element.hpp:58
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3906
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:876
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:314
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:268
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
A general function coefficient.
const DenseMatrix & GetGeomToPerfGeomJac(int GeomType) const
Definition geom.hpp:102
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:193
void ProjectGridFunction(const GridFunction &src)
Project the src GridFunction to this GridFunction, both of which must be on the same mesh.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:291
Parallel smoothers in hypre.
Definition hypre.hpp:1077
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
Definition hypre.cpp:3660
@ l1Jacobi
l1-scaled Jacobi
Definition hypre.hpp:1137
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
Container class for integration rules.
Definition intrules.hpp:430
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
void SetAbsTol(real_t atol)
Definition solvers.hpp:239
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
MINRES method.
Definition solvers.hpp:742
void SetPreconditioner(Solver &pr) override
This should be called before SetOperator.
Definition solvers.hpp:754
Mesh data type.
Definition mesh.hpp:67
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:309
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:7206
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1705
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1462
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:111
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:361
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition mesh.cpp:7200
real_t GetElementVolume(int i)
Definition mesh.cpp:125
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1393
long long GetGlobalNE() const
Return the total (global) number of elements.
Definition mesh.hpp:1419
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:11781
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:12125
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1569
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
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:2172
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:422
void SetPositiveDiagonal(bool pos_diag=true)
Replace diagonal entries with their absolute values.
Definition solvers.hpp:458
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.
Abstract parallel finite element space.
Definition pfespace.hpp:31
void GetElementDofs(int i, Array< int > &dofs, DofTransformation &doftrans) const override
The same as GetElementDofs(), but with a user-provided DofTransformation object.
Definition pfespace.cpp:593
Class for parallel grid function.
Definition pgridfunc.hpp:50
void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void SaveAsOne(const char *fname, int precision=16) const
Class for parallel meshes.
Definition pmesh.hpp:35
void SetNodalFESpace(FiniteElementSpace *nfes) override
Definition pmesh.cpp:2057
void PrintAsOne(std::ostream &out=mfem::out, const std::string &comments="") const
Write the mesh to the stream 'out' on Process 0 in a form suitable for visualization.
Definition pmesh.cpp:5131
Parallel non-linear operator on the true dofs.
Base class for solvers.
Definition operator.hpp:855
void ParEnableNormalization(const ParGridFunction &x)
Definition tmop.cpp:6274
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:6117
void AddTMOPIntegrator(TMOP_Integrator *ti)
Adds a new TMOP_Integrator to the combination.
Definition tmop.hpp:2632
void AddGridFunctionForUpdate(GridFunction *gf)
Definition tmop_amr.hpp:252
void AddFESpaceForUpdate(FiniteElementSpace *fes)
Definition tmop_amr.hpp:253
void SetPreconditioner(Solver &pr) override
This should be called before SetOperator.
void EnsurePositiveDeterminantBound(Mesh &mesh, int ref_factor, int max_recursion_depth=0)
Ensure a positive lower bound for the Jacobian determinant in tensor-product elements during line-sea...
void SetIntegrationRules(IntegrationRules &irules, int order)
Prescribe a set of integration rules; relevant for mixed meshes.
void SetMinDetPtr(real_t *md_ptr)
2D barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:1273
2D barrier Size+Skew (VQ) metric.
Definition tmop.hpp:1313
2D barrier Shape+Orientation (OS) metric (polyconvex).
Definition tmop.hpp:1335
2D barrier Shape+Size (VS) metric (polyconvex).
Definition tmop.hpp:1355
A TMOP integrator class based on any given TMOP_QualityMetric and TargetConstructor.
Definition tmop.hpp:1995
void SetExactActionFlag(bool flag_)
Flag to control if exact action of Integration is effected.
Definition tmop.hpp:2594
void SetCoefficient(Coefficient &w1)
Sets a scaling Coefficient for the quality metric term of the integrator.
Definition tmop.hpp:2372
void EnableFiniteDifferences(const GridFunction &x)
Enables FD-based approximation and computes dx.
Definition tmop.cpp:5910
void SetIntegrationRules(IntegrationRules &irules, int order)
Prescribe a set of integration rules; relevant for mixed meshes.
Definition tmop.hpp:2341
void IntegrateOverTarget(bool integ_over_target_)
Definition tmop.hpp:2357
2D non-barrier metric without a type.
Definition tmop.hpp:290
2D barrier Shape+Size (VS) metric (not polyconvex).
Definition tmop.hpp:425
2D barrier Shape+Size (VS) metric (not polyconvex).
Definition tmop.hpp:443
2D non-barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:461
2D Shifted barrier form of shape metric (mu_2).
Definition tmop.hpp:492
2D barrier shape (S) metric (not polyconvex).
Definition tmop.hpp:587
2D barrier Shape+Orientation (OS) metric (polyconvex).
Definition tmop.hpp:675
2D compound barrier Shape+Size (VS) metric (balanced).
Definition tmop.hpp:692
2D compound barrier Shape+Size (VS) metric (balanced).
Definition tmop.hpp:713
2D barrier Shape+Size+Orientation (VOS) metric (polyconvex).
Definition tmop.hpp:734
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:794
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:815
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:836
3D barrier Shape (S) metric, well-posed (polyconvex & invex).
Definition tmop.hpp:857
3D Shape (S) metric, untangling version of 303.
Definition tmop.hpp:899
3D Size (V) metric.
Definition tmop.hpp:920
3D Size (V) metric.
Definition tmop.hpp:938
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:980
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:1001
3D barrier Shape+Size (VS) metric, well-posed (invex).
Definition tmop.hpp:1022
3D compound barrier Shape+Size (VS) metric (polyconvex, balanced).
Definition tmop.hpp:1043
3D compound barrier Shape+Size (VS) metric (polyconvex).
Definition tmop.hpp:1064
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:1085
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:1105
3D compound barrier Shape+Size (VS) metric (polyconvex, balanced).
Definition tmop.hpp:1127
3D barrier Shape+Size (VS) metric, well-posed (polyconvex).
Definition tmop.hpp:1168
3D non-barrier Shape (S) metric.
Definition tmop.hpp:1211
Abstract class for local mesh quality metrics in the target-matrix optimization paradigm (TMOP) by P....
Definition tmop.hpp:28
Base class representing target-matrix construction algorithms for mesh optimization via the target-ma...
Definition tmop.hpp:1586
void SetVolumeScale(real_t vol_scale)
Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1.
Definition tmop.hpp:1676
void SetNodes(const GridFunction &n)
Set the nodes to be used in the target-matrix construction.
Definition tmop.hpp:1670
TargetType
Target-matrix construction algorithms supported by this class.
Definition tmop.hpp:1590
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
void Randomize(int seed=0)
Set random values in the vector.
Definition vector.cpp:955
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int dim
Definition ex24.cpp:53
@ disc
Definition ex25.cpp:151
int main()
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 adapt_lim_fun2(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 VisualizeMesh(socketstream &sock, const char *vishost, int visport, Mesh &mesh, const char *title, int x, int y, int w, int h, const char *keys)
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)
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_p(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, ParMesh &pmesh, char *title, int position)
float real_t
Definition config.hpp:46
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
STL namespace.
Settings for the output behavior of the IterativeSolver.
Definition solvers.hpp:103
Helper struct to convert a C++ type to an MPI type.