MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
mesh-fitting.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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#include "mesh-optimizer.hpp"
14
15using namespace std;
16using namespace mfem;
17using namespace common;
18
19// Used for exact surface alignment
21{
22 const int dim = x.Size();
23 if (dim == 2)
24 {
25 const real_t xc = x(0) - 0.5, yc = x(1) - 0.5;
26 const real_t r = sqrt(xc*xc + yc*yc);
27 return r-0.25;
28 }
29 else
30 {
31 const real_t xc = x(0) - 0.5, yc = x(1) - 0.5, zc = x(2) - 0.5;
32 const real_t r = sqrt(xc*xc + yc*yc + zc*zc);
33 return r-0.3;
34 }
35}
36
38{
39 const int dim = x.Size();
40 if (dim == 2)
41 {
42 const real_t xc = x(0) - 0.5, yc = x(1) - 0.5;
43 return std::pow(xc, 4.0) + std::pow(yc, 4.0) - std::pow(0.24, 4.0);
44 }
45 else
46 {
47 const real_t xc = x(0) - 0.5, yc = x(1) - 0.5, zc = x(2) - 0.5;
48 return std::pow(xc, 4.0) + std::pow(yc, 4.0) +
49 std::pow(zc, 4.0) - std::pow(0.24, 4.0);
50 }
51}
52
53real_t in_circle(const Vector &x, const Vector &x_center, real_t radius)
54{
55 Vector x_current = x;
56 x_current -= x_center;
57 real_t dist = x_current.Norml2();
58 if (dist < radius)
59 {
60 return 1.0;
61 }
62 else if (dist == radius)
63 {
64 return 0.0;
65 }
66
67 return -1.0;
68}
69
71{
72 real_t phi_t = x(1) + (a-b)*x(0)/l - a;
73 return (phi_t <= 0.0) ? 1.0 : -1.0;
74}
75
77{
78 real_t phi_p1 = (x(0)-h-t/2) - k*x(1)*x(1);
79 real_t phi_p2 = (x(0)-h+t/2) - k*x(1)*x(1);
80 return (phi_p1 <= 0.0 && phi_p2 >= 0.0) ? 1.0 : -1.0;
81}
82
84{
85 real_t dx = std::abs(x(0) - xc);
86 real_t dy = std::abs(x(1) - yc);
87 return (dx <= w/2 && dy <= h/2) ? 1.0 : -1.0;
88}
89
90// Fischer-Tropsch like geometry
92{
93 // Circle
94 Vector x_circle1(2);
95 x_circle1(0) = 0.0;
96 x_circle1(1) = 0.0;
97 real_t in_circle1_val = in_circle(x, x_circle1, 0.2);
98
99 real_t r1 = 0.2;
100 real_t r2 = 1.0;
101 real_t in_trapezium_val = in_trapezium(x, 0.05, 0.1, r2-r1);
102
103 real_t return_val = max(in_circle1_val, in_trapezium_val);
104
105 real_t h = 0.4;
106 real_t k = 2;
107 real_t t = 0.15;
108 real_t in_parabola_val = in_parabola(x, h, k, t);
109 return_val = max(return_val, in_parabola_val);
110
111 real_t in_rectangle_val = in_rectangle(x, 0.99, 0.0, 0.12, 0.35);
112 return_val = max(return_val, in_rectangle_val);
113
114 real_t in_rectangle_val2 = in_rectangle(x, 0.99, 0.5, 0.12, 0.28);
115 return_val = max(return_val, in_rectangle_val2);
116 return return_val;
117}
118
119real_t in_cube(const Vector &x, real_t xc, real_t yc, real_t zc, real_t lx,
120 real_t ly, real_t lz)
121{
122 real_t dx = std::abs(x(0) - xc);
123 real_t dy = std::abs(x(1) - yc);
124 real_t dz = std::abs(x(2) - zc);
125 return (dx <= lx/2 && dy <= ly/2 && dz <= lz/2) ? 1.0 : -1.0;
126}
127
128real_t in_pipe(const Vector &x, int pipedir, Vector x_pipe_center,
129 real_t radius, real_t minv, real_t maxv)
130{
131 Vector x_pipe_copy = x_pipe_center;
132 x_pipe_copy -= x;
133 x_pipe_copy(pipedir-1) = 0.0;
134 real_t dist = x_pipe_copy.Norml2();
135 real_t xv = x(pipedir-1);
136 if (dist < radius && xv > minv && xv < maxv)
137 {
138 return 1.0;
139 }
140 else if (dist == radius || (xv == minv && dist < radius) || (xv == maxv &&
141 dist < radius))
142 {
143 return 0.0;
144 }
145
146 return -1.0;
147}
148
150{
151 return r1 + r2 - std::pow(r1*r1 + r2*r2, 0.5);
152}
153
155{
156 return r1 + r2 + std::pow(r1*r1 + r2*r2, 0.5);
157}
158
160{
161 return r_intersect(r1, -r2);
162}
163
165{
166 Vector xcc(3);
167 xcc = 0.5;
168 real_t cube_x = 0.25*2;
169 real_t cube_y = 0.25*2;
170 real_t cube_z = 0.25*2;
171
172 real_t in_cube_val = in_cube(x, xcc(0), xcc(1), xcc(2), cube_x, cube_y, cube_z);
173
174 Vector x_circle_c(3);
175 x_circle_c = 0.5;
176
177 real_t sphere_radius = 0.30;
178 real_t in_sphere_val = in_circle(x, x_circle_c, sphere_radius);
179 real_t in_return_val = std::min(in_cube_val, in_sphere_val);
180
181 int pipedir = 1;
182 Vector x_pipe_center(3);
183 x_pipe_center = 0.5;
184 real_t xmin = 0.5-sphere_radius;
185 real_t xmax = 0.5+sphere_radius;
186 real_t pipe_radius = 0.075;
187 real_t in_pipe_x = in_pipe(x, pipedir, x_pipe_center, pipe_radius, xmin, xmax);
188
189 in_return_val = std::min(in_return_val, -1*in_pipe_x);
190
191 pipedir = 2;
192 in_pipe_x = in_pipe(x, pipedir, x_pipe_center, pipe_radius, xmin, xmax);
193 in_return_val = std::min(in_return_val, -1*in_pipe_x);
194
195 pipedir = 3;
196 in_pipe_x = in_pipe(x, pipedir, x_pipe_center, pipe_radius, xmin, xmax);
197 in_return_val = std::min(in_return_val, -1*in_pipe_x);
198
199 return in_return_val;
200}
201
202#ifdef MFEM_USE_MPI
204{
205 const int dim = pmesh->Dimension();
206 for (int i = 0; i < pmesh->GetNBE(); i++)
207 {
208 mfem::Array<int> dofs;
209 pmesh->GetNodalFESpace()->GetBdrElementDofs(i, dofs);
210 mfem::Vector bdr_xy_data;
211 mfem::Vector dof_xyz(dim);
212 mfem::Vector dof_xyz_compare;
213 mfem::Array<int> xyz_check(dim);
214 for (int j = 0; j < dofs.Size(); j++)
215 {
216 for (int d = 0; d < dim; d++)
217 {
218 dof_xyz(d) = x(pmesh->GetNodalFESpace()->DofToVDof(dofs[j], d));
219 }
220 if (j == 0)
221 {
222 dof_xyz_compare = dof_xyz;
223 xyz_check = 1;
224 }
225 else
226 {
227 for (int d = 0; d < dim; d++)
228 {
229 if (std::abs(dof_xyz(d)-dof_xyz_compare(d)) < 1.e-10)
230 {
231 xyz_check[d] += 1;
232 }
233 }
234 }
235 }
236 if (dim == 2)
237 {
238 if (xyz_check[0] == dofs.Size())
239 {
240 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 1);
241 }
242 else if (xyz_check[1] == dofs.Size())
243 {
244 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 2);
245 }
246 else
247 {
248 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 4);
249 }
250 }
251 else if (dim == 3)
252 {
253 if (xyz_check[0] == dofs.Size())
254 {
255 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 1);
256 }
257 else if (xyz_check[1] == dofs.Size())
258 {
259 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 2);
260 }
261 else if (xyz_check[2] == dofs.Size())
262 {
263 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 3);
264 }
265 else
266 {
267 pmesh->GetNodalFESpace()->GetMesh()->SetBdrAttribute(i, 4);
268 }
269 }
270 }
271}
272
274 int attr_to_switch)
275{
277 // Switch attribute if all but 1 of the faces of an element will be marked?
278 Array<int> element_attr(pmesh->GetNE());
279 element_attr = 0;
280 for (int e = 0; e < pmesh->GetNE(); e++)
281 {
282 Array<int> faces, ori;
283 if (pmesh->Dimension() == 2)
284 {
285 pmesh->GetElementEdges(e, faces, ori);
286 }
287 else
288 {
289 pmesh->GetElementFaces(e, faces, ori);
290 }
291 int inf1, inf2;
292 int elem1, elem2;
293 int diff_attr_count = 0;
294 int attr1;
295 int attr2;
296 attr1 = mat(e);
297 bool bdr_element = false;
298 element_attr[e] = attr1;
299 int target_attr = -1;
300 for (int f = 0; f < faces.Size(); f++)
301 {
302 pmesh->GetFaceElements(faces[f], &elem1, &elem2);
303 if (elem2 >= 0)
304 {
305 attr2 = elem1 == e ? (int)(mat(elem2)) : (int)(mat(elem1));
306 if (attr1 != attr2 && attr1 == attr_to_switch)
307 {
308 diff_attr_count += 1;
309 target_attr = attr2;
310 }
311 }
312 else
313 {
314 pmesh->GetFaceInfos(faces[f], &inf1, &inf2);
315 if (inf2 >= 0)
316 {
317 Vector dof_vals;
318 Array<int> dofs;
319 mat.GetElementDofValues(pmesh->GetNE() + (-1-elem2), dof_vals);
320 attr2 = (int)(dof_vals(0));
321 if (attr1 != attr2 && attr1 == attr_to_switch)
322 {
323 diff_attr_count += 1;
324 target_attr = attr2;
325 }
326 }
327 else
328 {
329 bdr_element = true;
330 }
331 }
332 }
333
334 if (diff_attr_count == faces.Size()-1 && !bdr_element)
335 {
336 element_attr[e] = target_attr;
337 }
338 }
339 for (int e = 0; e < pmesh->GetNE(); e++)
340 {
341 mat(e) = element_attr[e];
342 pmesh->SetAttribute(e, element_attr[e]+1);
343 }
345 pmesh->SetAttributes();
346}
347
349 FunctionCoefficient &ls_coeff,
350 int amr_iter,
351 ParGridFunction &distance_s,
352 const int quad_order = 5,
353 Array<ParGridFunction *> *pgf_to_update = NULL)
354{
355 mfem::H1_FECollection h1fec(distance_s.ParFESpace()->FEColl()->GetOrder(),
356 pmesh.Dimension());
357 mfem::ParFiniteElementSpace h1fespace(&pmesh, &h1fec);
358 mfem::ParGridFunction x(&h1fespace);
359
360 mfem::L2_FECollection l2fec(0, pmesh.Dimension());
361 mfem::ParFiniteElementSpace l2fespace(&pmesh, &l2fec);
362 mfem::ParGridFunction el_to_refine(&l2fespace);
363
364 mfem::H1_FECollection lhfec(1, pmesh.Dimension());
365 mfem::ParFiniteElementSpace lhfespace(&pmesh, &lhfec);
366 mfem::ParGridFunction lhx(&lhfespace);
367
368 x.ProjectCoefficient(ls_coeff);
370
372 for (int iter = 0; iter < amr_iter; iter++)
373 {
374 el_to_refine = 0.0;
375 for (int e = 0; e < pmesh.GetNE(); e++)
376 {
377 Array<int> dofs;
378 Vector x_vals;
379 DenseMatrix x_grad;
380 h1fespace.GetElementDofs(e, dofs);
381 const IntegrationRule &ir = irRules.Get(pmesh.GetElementGeometry(e),
382 quad_order);
383 x.GetValues(e, ir, x_vals);
384 real_t min_val = x_vals.Min();
385 real_t max_val = x_vals.Max();
386 // If the zero level set cuts the elements, mark it for refinement
387 if (min_val < 0 && max_val >= 0)
388 {
389 el_to_refine(e) = 1.0;
390 }
391 }
392
393 // Refine an element if its neighbor will be refined
394 for (int inner_iter = 0; inner_iter < 2; inner_iter++)
395 {
396 el_to_refine.ExchangeFaceNbrData();
397 GridFunctionCoefficient field_in_dg(&el_to_refine);
399 for (int e = 0; e < pmesh.GetNE(); e++)
400 {
401 Array<int> dofs;
402 Vector x_vals;
403 lhfespace.GetElementDofs(e, dofs);
404 const IntegrationRule &ir =
405 irRules.Get(pmesh.GetElementGeometry(e), quad_order);
406 lhx.GetValues(e, ir, x_vals);
407 real_t max_val = x_vals.Max();
408 if (max_val > 0)
409 {
410 el_to_refine(e) = 1.0;
411 }
412 }
413 }
414
415 // Make the list of elements to be refined
416 Array<int> el_to_refine_list;
417 for (int e = 0; e < el_to_refine.Size(); e++)
418 {
419 if (el_to_refine(e) > 0.0)
420 {
421 el_to_refine_list.Append(e);
422 }
423 }
424
425 int loc_count = el_to_refine_list.Size();
426 int glob_count = loc_count;
427 MPI_Allreduce(&loc_count, &glob_count, 1, MPI_INT, MPI_SUM,
428 pmesh.GetComm());
429 MPI_Barrier(pmesh.GetComm());
430 if (glob_count > 0)
431 {
432 pmesh.GeneralRefinement(el_to_refine_list, 1);
433 }
434
435 // Update
436 h1fespace.Update();
437 x.Update();
438 x.ProjectCoefficient(ls_coeff);
439
440 l2fespace.Update();
441 el_to_refine.Update();
442
443 lhfespace.Update();
444 lhx.Update();
445
446 distance_s.ParFESpace()->Update();
447 distance_s.Update();
448
449 if (pgf_to_update != NULL)
450 {
451 for (int i = 0; i < pgf_to_update->Size(); i++)
452 {
453 (*pgf_to_update)[i]->ParFESpace()->Update();
454 (*pgf_to_update)[i]->Update();
455 }
456 }
457 }
458}
459
461 FunctionCoefficient &ls_coeff,
462 ParGridFunction &distance_s,
463 const int nDiffuse = 2,
464 const int pLapOrder = 5,
465 const int pLapNewton = 50)
466{
467 mfem::H1_FECollection h1fec(distance_s.ParFESpace()->FEColl()->GetOrder(),
468 pmesh.Dimension());
469 mfem::ParFiniteElementSpace h1fespace(&pmesh, &h1fec);
470 mfem::ParGridFunction x(&h1fespace);
471
472 x.ProjectCoefficient(ls_coeff);
474
475 //Now determine distance
476 const real_t dx = AvgElementSize(pmesh);
477 PLapDistanceSolver dist_solver(pLapOrder, pLapNewton);
478
479 ParFiniteElementSpace pfes_s(*distance_s.ParFESpace());
480
481 // Smooth-out Gibbs oscillations from the input level set. The smoothing
482 // parameter here is specified to be mesh dependent with length scale dx.
483 ParGridFunction filt_gf(&pfes_s);
484 PDEFilter filter(pmesh, 1.0 * dx);
485 filter.Filter(ls_coeff, filt_gf);
486 GridFunctionCoefficient ls_filt_coeff(&filt_gf);
487
488 dist_solver.ComputeScalarDistance(ls_filt_coeff, distance_s);
489 distance_s.SetTrueVector();
490 distance_s.SetFromTrueVector();
491
492 DiffuseField(distance_s, nDiffuse);
493 distance_s.SetTrueVector();
494 distance_s.SetFromTrueVector();
495}
496#endif
int Size() const
Return the logical size of the array.
Definition array.hpp:147
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:830
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition fe_coll.hpp:240
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:878
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:679
DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element 'bel'. The returned indices are offsets in...
Definition fespace.cpp:3617
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:294
A general function coefficient.
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim=1) const
Definition gridfunc.cpp:518
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:147
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:153
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
Container class for integration rules.
Definition intrules.hpp:422
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:346
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1463
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:10883
Geometry::Type GetElementGeometry(int i) const
Definition mesh.hpp:1434
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:6479
void SetAttribute(int i, int attr)
Set the attribute of element i.
Definition mesh.cpp:7629
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition mesh.cpp:1457
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition mesh.cpp:7514
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1285
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition mesh.cpp:7267
void SetBdrAttribute(int i, int attr)
Set the attribute of boundary element i.
Definition mesh.hpp:1398
Abstract parallel finite element space.
Definition pfespace.hpp:29
void GetElementDofs(int i, Array< int > &dofs, DofTransformation &doftrans) const override
The same as GetElementDofs(), but with a user-allocated DofTransformation object. doftrans must be al...
Definition pfespace.cpp:561
void Update(bool want_transform=true) override
Class for parallel grid function.
Definition pgridfunc.hpp:50
void ProjectDiscCoefficient(VectorCoefficient &coeff) override
Project a discontinuous vector coefficient as a grid function on a continuous finite element space....
ParFiniteElementSpace * ParFESpace() const
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:91
void GetElementDofValues(int el, Vector &dof_vals) const override
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:402
void SetAttributes() override
Determine the sets of unique attribute values in domain and boundary elements.
Definition pmesh.cpp:1588
Vector data type.
Definition vector.hpp:82
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:931
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1164
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1123
void Filter(ParGridFunction &func, ParGridFunction &ffield)
void ComputeScalarDistance(Coefficient &func, ParGridFunction &fdist)
const real_t radius
Definition distance.cpp:107
int dim
Definition ex24.cpp:53
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t in_trapezium(const Vector &x, real_t a, real_t b, real_t l)
real_t reactor(const Vector &x)
real_t in_pipe(const Vector &x, int pipedir, Vector x_pipe_center, real_t radius, real_t minv, real_t maxv)
real_t in_cube(const Vector &x, real_t xc, real_t yc, real_t zc, real_t lx, real_t ly, real_t lz)
real_t in_circle(const Vector &x, const Vector &x_center, real_t radius)
real_t in_rectangle(const Vector &x, real_t xc, real_t yc, real_t w, real_t h)
real_t r_intersect(real_t r1, real_t r2)
real_t csg_cubecylsph(const Vector &x)
real_t r_remove(real_t r1, real_t r2)
void ModifyBoundaryAttributesForNodeMovement(ParMesh *pmesh, ParGridFunction &x)
void ModifyAttributeForMarkingDOFS(ParMesh *pmesh, ParGridFunction &mat, int attr_to_switch)
real_t squircle_level_set(const Vector &x)
real_t in_parabola(const Vector &x, real_t h, real_t k, real_t t)
void OptimizeMeshWithAMRAroundZeroLevelSet(ParMesh &pmesh, FunctionCoefficient &ls_coeff, int amr_iter, ParGridFunction &distance_s, const int quad_order=5, Array< ParGridFunction * > *pgf_to_update=NULL)
void ComputeScalarDistanceFromLevelSet(ParMesh &pmesh, FunctionCoefficient &ls_coeff, ParGridFunction &distance_s, const int nDiffuse=2, const int pLapOrder=5, const int pLapNewton=50)
real_t circle_level_set(const Vector &x)
real_t r_union(real_t r1, real_t r2)
real_t AvgElementSize(ParMesh &pmesh)
void DiffuseField(ParGridFunction &field, int smooth_steps)
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30