omega_h
Reliable mesh adaptation
Omega_h_shape.hpp
1 #ifndef OMEGA_H_SHAPE_HPP
2 #define OMEGA_H_SHAPE_HPP
3 
4 #include <Omega_h_adj.hpp>
5 #include <Omega_h_affine.hpp>
6 #include <Omega_h_mesh.hpp>
7 #include <Omega_h_metric.hpp>
8 #include <Omega_h_qr.hpp>
9 #include <Omega_h_simplex.hpp>
10 #include "Omega_h_macros.h"
11 
12 namespace Omega_h {
13 
14 template <Int sdim, Int edim>
15 OMEGA_H_INLINE Matrix<sdim, edim> simplex_basis(Few<Vector<sdim>, edim + 1> const & p) {
16  Matrix<sdim, edim> b;
17  for (Int i = 0; i < edim; ++i) b[i] = p[i + 1] - p[0];
18  return b;
19 }
20 
21 template <Int dim>
22 struct Sphere {
23  Vector<dim> c;
24  Real r;
25 };
26 
27 template <Int dim>
28 struct Plane {
30  Real d;
31 };
32 
33 template <Int dim>
34 OMEGA_H_INLINE Real distance(Plane<dim> plane, Vector<dim> point) {
35  return (plane.n * point) - plane.d;
36 }
37 
38 template <Int dim>
39 OMEGA_H_INLINE Plane<dim> normalize(Plane<dim> p) {
40  auto l = norm(p.n);
41  return {p.n / l, p.d / l};
42 }
43 
45 template <Int dim>
46 OMEGA_H_INLINE Vector<dim + 1> form_barycentric(Vector<dim> const & c) {
47  Vector<dim + 1> xi;
48  xi[0] = 1.0;
49  for (Int i = 1; i < dim+1; ++i) {
50  xi[i] = c[i-1];
51  xi[0] -= c[i-1];
52  }
53  return xi;
54 }
55 
57 template <Int sdim, Int edim>
58 OMEGA_H_INLINE Vector<edim +1 > barycentric_from_global(Vector<sdim> const & global_coordinate, Few<Vector<sdim>, edim + 1> const & node_coordinates) {
59  // does normal inversion when sdim=edim
60  const auto inverse_basis = pseudo_invert(simplex_basis<sdim,edim>(node_coordinates));
61  const auto lambda = inverse_basis*(global_coordinate-node_coordinates[0]);
62  return form_barycentric(lambda);
63 }
64 
65 template <Int n>
66 OMEGA_H_INLINE bool is_barycentric_inside(Vector<n> xi, Real fuzz=0) {
67  return (0.0-fuzz) <= reduce(xi, minimum<Real>()) &&
68  reduce(xi, maximum<Real>()) <= (1.0+fuzz);
69 }
70 
71 template <Int sdim>
72 OMEGA_H_INLINE Real edge_length_from_basis(Few<Vector<sdim>, 1> b) {
73  return norm(b[0]);
74 }
75 
76 template <Int sdim>
77 OMEGA_H_INLINE Real simplex_size_from_basis(Few<Vector<sdim>, 1> b) {
78  return edge_length_from_basis(b);
79 }
80 
81 OMEGA_H_INLINE Real triangle_area_from_basis(Few<Vector<2>, 2> b) {
82  return cross(b[0], b[1]) / 2.0;
83 }
84 
85 OMEGA_H_INLINE Real triangle_area_from_basis(Few<Vector<3>, 2> b) {
86  return norm(cross(b[0], b[1])) / 2.0;
87 }
88 
89 template <Int sdim>
90 OMEGA_H_INLINE Real simplex_size_from_basis(Few<Vector<sdim>, 2> b) {
91  return triangle_area_from_basis(b);
92 }
93 
94 OMEGA_H_INLINE Real tet_volume_from_basis(Few<Vector<3>, 3> b) {
95  return (cross(b[0], b[1]) * b[2]) / 6.0;
96 }
97 
98 OMEGA_H_INLINE Real simplex_size_from_basis(Few<Vector<3>, 3> b) {
99  return tet_volume_from_basis(b);
100 }
101 
102 /* Loseille, Adrien, and Rainald Lohner.
103  * "On 3D anisotropic local remeshing for surface, volume and boundary layers."
104  * Proceedings of the 18th International Meshing Roundtable.
105  * Springer Berlin Heidelberg, 2009. 611-630.
106  *
107  * Loseille's edge length integral assumes an interpolation $h(t) =
108  * h_0^{1-t}h_1^t$,
109  * which is consistent with the Log-Euclidean metric interpolation we now use.
110  */
111 
112 OMEGA_H_INLINE Real anisotropic_edge_length(Real l_a, Real l_b) {
113  if (std::abs(l_a - l_b) > 1e-3) {
114  return (l_a - l_b) / (std::log(l_a / l_b));
115  }
116  return (l_a + l_b) / 2.;
117 }
118 
119 template <Int space_dim, Int metric_dim>
120 OMEGA_H_INLINE Real metric_edge_length(
121  Few<Vector<space_dim>, 2> p, Few<Matrix<metric_dim, metric_dim>, 2> ms) {
122  auto v = p[1] - p[0];
123  auto l_a = metric_length(ms[0], v);
124  auto l_b = metric_length(ms[1], v);
125  return anisotropic_edge_length(l_a, l_b);
126 }
127 
128 template <Int space_dim, Int metric_dim>
129 OMEGA_H_DEVICE Real metric_edge_length(
130  Few<LO, 2> v, Reals coords, Reals metrics) {
131  auto p = gather_vectors<2, space_dim>(coords, v);
132  auto ms = gather_symms<2, metric_dim>(metrics, v);
133  return metric_edge_length<space_dim, metric_dim>(p, ms);
134 }
135 
136 template <Int space_dim>
138  Reals coords;
139  RealEdgeLengths(Mesh const* mesh) : coords(mesh->coords()) {}
140  OMEGA_H_DEVICE Real measure(Few<LO, 2> v) const {
141  auto p = gather_vectors<2, space_dim>(coords, v);
142  return norm(p[1] - p[0]);
143  }
144 };
145 
146 template <Int space_dim, Int metric_dim>
148  Reals coords;
149  Reals metrics;
150  MetricEdgeLengths(Mesh const* mesh, Reals metrics_in)
151  : coords(mesh->coords()), metrics(metrics_in) {}
152  MetricEdgeLengths(Mesh const* mesh)
153  : MetricEdgeLengths(mesh, mesh->get_array<Real>(VERT, "metric")) {}
154  OMEGA_H_DEVICE Real measure(Few<LO, 2> v) const {
155  return metric_edge_length<space_dim, metric_dim>(v, coords, metrics);
156  }
157 };
158 
159 Reals measure_edges_real(Mesh* mesh, LOs a2e);
160 Reals measure_edges_metric(Mesh* mesh, LOs a2e, Reals metrics);
161 Reals measure_edges_metric(Mesh* mesh, LOs a2e);
162 Reals measure_edges_real(Mesh* mesh);
163 Reals measure_edges_metric(Mesh* mesh);
164 Reals measure_edges_metric(Mesh* mesh, Reals metrics);
165 
166 template <Int sdim, Int edim>
167 OMEGA_H_INLINE Real real_simplex_size(Few<Vector<sdim>, edim + 1> p) {
168  auto b = simplex_basis<sdim, edim>(p);
169  return simplex_size_from_basis(b);
170 }
171 
173  Reals coords;
174  RealSimplexSizes(Reals coords_in) : coords(coords_in) {}
175  template <Int sdim, Int edim>
176  OMEGA_H_DEVICE Real measure(Few<LO, edim + 1> v) const {
177  auto p = gather_vectors<edim + 1, sdim>(coords, v);
178  return real_simplex_size<sdim, edim>(p);
179  }
180 };
181 
182 Reals measure_ents_real(Mesh* mesh, Int ent_dim, LOs a2e, Reals coords);
183 Reals measure_elements_real(Mesh* mesh, LOs a2e);
184 Reals measure_elements_real(Mesh* mesh);
185 
186 OMEGA_H_INLINE Few<Vector<1>, 1> element_edge_vectors(
187  Few<Vector<1>, 2>, Few<Vector<1>, 1> b) {
188  return b;
189 }
190 
191 OMEGA_H_INLINE Few<Vector<2>, 3> element_edge_vectors(
192  Few<Vector<2>, 3> p, Few<Vector<2>, 2> b) {
193  Few<Vector<2>, 3> ev;
194  ev[0] = b[0];
195  ev[1] = p[2] - p[1];
196  ev[2] = -b[1];
197  return ev;
198 }
199 
200 OMEGA_H_INLINE Few<Vector<3>, 6> element_edge_vectors(
201  Few<Vector<3>, 4> p, Few<Vector<3>, 3> b) {
202  Few<Vector<3>, 6> ev;
203  ev[0] = b[0];
204  ev[1] = p[2] - p[1];
205  ev[2] = -b[1];
206  ev[3] = b[2];
207  ev[4] = p[3] - p[1];
208  ev[5] = p[3] - p[2];
209  return ev;
210 }
211 
212 template <Int space_dim, Int metric_dim>
213 OMEGA_H_INLINE Real squared_metric_length(
214  Vector<space_dim> v, Matrix<metric_dim, metric_dim> m) {
215  return metric_product(m, v);
216 }
217 
218 template <typename EdgeVectors, typename Metric>
219 OMEGA_H_INLINE Real mean_squared_metric_length(
220  EdgeVectors edge_vectors, Metric metric) {
221  auto const nedges = edge_vectors.size();
222  Real msl = 0;
223  for (Int i = 0; i < nedges; ++i) {
224  msl += squared_metric_length(edge_vectors[i], metric);
225  }
226  return msl / nedges;
227 }
228 
229 template <typename EdgeVectors>
230 OMEGA_H_INLINE Real mean_squared_real_length(EdgeVectors edge_vectors) {
231  return mean_squared_metric_length(edge_vectors, matrix_1x1(1.0));
232 }
233 
234 OMEGA_H_INLINE Matrix<1, 1> element_implied_metric(Few<Vector<1>, 2> p) {
235  auto h = p[1][0] - p[0][0];
236  auto l = metric_eigenvalue_from_length(h);
237  return matrix_1x1(l);
238 }
239 
240 OMEGA_H_INLINE Matrix<2, 2> element_implied_metric(Few<Vector<2>, 3> p) {
241  auto b = simplex_basis<2, 2>(p);
242  auto ev = element_edge_vectors(p, b);
243  Matrix<3, 3> a;
244  Vector<3> rhs;
245  for (Int i = 0; i < 3; ++i) {
246  /* ax^2 + by^2 + 2cxy = 1 */
247  a[0][i] = square(ev[i][0]);
248  a[1][i] = square(ev[i][1]);
249  a[2][i] = 2 * ev[i][0] * ev[i][1];
250  rhs[i] = 1.0;
251  }
252  auto x = invert(a) * rhs;
253  return vector2symm(x);
254 }
255 
256 OMEGA_H_INLINE Matrix<3, 3> element_implied_metric(Few<Vector<3>, 4> p) {
257  auto b = simplex_basis<3, 3>(p);
258  auto ev = element_edge_vectors(p, b);
259  Matrix<6, 6> a;
260  Vector<6> rhs;
261  for (Int i = 0; i < 6; ++i) {
262  /* ax^2 + by^2 + cz^2 + 2dxy + 2eyz + 2fxz = 1 */
263  a[0][i] = square(ev[i][0]);
264  a[1][i] = square(ev[i][1]);
265  a[2][i] = square(ev[i][2]);
266  a[3][i] = 2 * ev[i][0] * ev[i][1];
267  a[4][i] = 2 * ev[i][1] * ev[i][2];
268  a[5][i] = 2 * ev[i][0] * ev[i][2];
269  rhs[i] = 1.0;
270  }
271  auto x = solve_using_qr(a, rhs);
272  return vector2symm(x);
273 }
274 
275 template <Int dim>
276 OMEGA_H_INLINE Vector<dim> get_triangle_normal(
277  Vector<dim> a, Vector<dim> b, Vector<dim> c) {
278  return cross(b - a, c - a);
279 }
280 
281 OMEGA_H_INLINE Vector<1> get_side_vector(Few<Vector<1>, 2>, Int ivert) {
282  return vector_1((ivert == 1) ? 1.0 : -1.0);
283 }
284 
285 OMEGA_H_INLINE Vector<2> get_side_vector(Few<Vector<2>, 2> p) {
286  return -perp(p[1] - p[0]);
287 }
288 
289 OMEGA_H_INLINE Vector<2> get_side_vector(Few<Vector<2>, 3> p, Int iedge) {
290  Few<Vector<2>, 2> sp;
291  sp[0] = p[simplex_down_template(2, 1, iedge, 0)];
292  sp[1] = p[simplex_down_template(2, 1, iedge, 1)];
293  return get_side_vector(sp);
294 }
295 
296 OMEGA_H_INLINE Vector<3> get_side_vector(Few<Vector<3>, 3> p) {
297  return get_triangle_normal<3>(p[0], p[1], p[2]);
298 }
299 
300 OMEGA_H_INLINE Vector<3> get_side_vector(Few<Vector<3>, 4> p, Int iface) {
301  Few<Vector<3>, 3> sp;
302  sp[0] = p[simplex_down_template(3, 2, iface, 0)];
303  sp[1] = p[simplex_down_template(3, 2, iface, 1)];
304  sp[2] = p[simplex_down_template(3, 2, iface, 2)];
305  return get_side_vector(sp);
306 }
307 
308 template <Int dim>
309 OMEGA_H_INLINE Plane<dim> get_side_plane(
310  Few<Vector<dim>, dim + 1> p, Int iside) {
311  auto n = get_side_vector(p, iside);
312  auto o = p[simplex_down_template(dim, dim - 1, iside, 0)];
313  return {n, n * o};
314 }
315 
316 template <Int dim>
317 OMEGA_H_INLINE Sphere<dim> get_inball(Few<Vector<dim>, dim + 1> p) {
318  constexpr auto nsides = dim + 1;
319  Few<Plane<dim>, dim + 1> planes;
320  for (Int iside = 0; iside < nsides; ++iside) {
321  planes[iside] = normalize(get_side_plane(p, iside));
322  }
323  Matrix<dim, dim> a;
324  for (Int i = 0; i < dim; ++i) {
325  a[i] = planes[i + 1].n - planes[0].n;
326  }
327  Vector<dim> b;
328  for (Int i = 0; i < dim; ++i) {
329  b[i] = planes[i + 1].d - planes[0].d;
330  }
331  a = transpose(a);
332  auto const c = invert(a) * b;
333  auto const r = -distance(planes[0], c);
334  return {c, r};
335 }
336 
337 template <Int dim>
338 OMEGA_H_INLINE Vector<dim> get_size_gradient(
339  Few<Vector<dim>, dim + 1> p, Int ivert) {
340  auto iside = simplex_opposite_template(dim, VERT, ivert);
341  auto n = -get_side_vector(p, iside);
342  return n / Real(factorial(dim));
343 }
344 
345 template <Int dim>
346 OMEGA_H_INLINE Matrix<dim, dim + 1> get_size_gradients(
347  Few<Vector<dim>, dim + 1> p) {
348  Matrix<dim, dim + 1> sgrads;
349  for (Int i = 0; i < dim + 1; ++i) sgrads[i] = get_size_gradient(p, i);
350  return sgrads;
351 }
352 
353 /* This code is copied from the tricircumcenter3d() function
354  * by Shewchuk:
355  * http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html
356  * To: compgeom-discuss@research.bell-labs.com
357  * Subject: Re: circumsphere
358  * Date: Wed, 1 Apr 98 0:34:28 EST
359  * From: Jonathan R Shewchuk <jrs+@cs.cmu.edu>
360  *
361  * given the basis vectors of a triangle in 3D,
362  * this function returns the vector from the first vertex
363  * to the triangle's circumcenter
364  */
365 
366 OMEGA_H_INLINE Vector<3> get_circumcenter_vector(Few<Vector<3>, 2> basis) {
367  auto ba = basis[0];
368  auto ca = basis[1];
369  auto balength = norm_squared(ba);
370  auto calength = norm_squared(ca);
371  auto crossbc = cross(ba, ca);
372  auto factor = 0.5 / norm_squared(crossbc);
373  auto xcirca = ((balength * ca[1] - calength * ba[1]) * crossbc[2] -
374  (balength * ca[2] - calength * ba[2]) * crossbc[1]) *
375  factor;
376  auto ycirca = ((balength * ca[2] - calength * ba[2]) * crossbc[0] -
377  (balength * ca[0] - calength * ba[0]) * crossbc[2]) *
378  factor;
379  auto zcirca = ((balength * ca[0] - calength * ba[0]) * crossbc[1] -
380  (balength * ca[1] - calength * ba[1]) * crossbc[0]) *
381  factor;
382  return vector_3(xcirca, ycirca, zcirca);
383 }
384 
385 /* This paper (and a few others):
386  *
387  * Loseille, Adrien, Victorien Menier, and Frederic Alauzet.
388  * "Parallel Generation of Large-size Adapted Meshes."
389  * Procedia Engineering 124 (2015): 57-69.
390  *
391  * Mentions using $\sqrt{\det(M)}$ to compute volume in metric space.
392  *
393  * The call to power() allows us to pass in a 1x1 isotropic metric,
394  * and have its "determinant" raised to the right power before taking
395  * the square root, and even accepting its existing value in the case
396  * of space being 2D.
397  */
398 
399 template <Int space_dim, Int metric_dim>
400 OMEGA_H_INLINE Real metric_size(
401  Real real_size, Matrix<metric_dim, metric_dim> metric) {
402  return real_size * power<space_dim, 2 * metric_dim>(determinant(metric));
403 }
404 
405 /* The measure of an equilateral simplex */
406 OMEGA_H_INLINE constexpr Real equilateral_simplex_size(Int dim) {
407  return (
408  dim == 3 ? 0.1178511301977579 : (dim == 2 ? 0.4330127018922193 : 1.0));
409 }
410 
411 template <Int dim>
412 OMEGA_H_INLINE Affine<dim> simplex_affine(Few<Vector<dim>, dim + 1> p) {
413  Affine<dim> a;
414  a.r = simplex_basis<dim, dim>(p);
415  a.t = p[0];
416  return a;
417 }
418 
419 template <Int dim>
420 Real max_simplex_edge_length(Few<Vector<dim>, dim + 1> p) {
421  auto b = simplex_basis<dim, dim>(p);
422  auto ev = element_edge_vectors(p, b);
423  Real mel = norm(ev[0]);
424  for (Int i = 1; i < ev.size; ++i) mel = max2(mel, norm(ev[1]));
425  return mel;
426 }
427 
428 } // end namespace Omega_h
429 
430 #endif
Definition: Omega_h_few.hpp:61
Definition: Omega_h_mesh.hpp:35
Definition: amr_mpi_test.cpp:6
OMEGA_H_INLINE Vector< edim+1 > barycentric_from_global(Vector< sdim > const &global_coordinate, Few< Vector< sdim >, edim+1 > const &node_coordinates)
Compute the barycentric coordinates from a position in global coordinates and the element nodal coord...
Definition: Omega_h_shape.hpp:58
OMEGA_H_INLINE Vector< dim+1 > form_barycentric(Vector< dim > const &c)
Constructs full barycentric representation (xi_0,xi_1,...) from xi_1, xi_2, ...
Definition: Omega_h_shape.hpp:46
constexpr OMEGA_H_INLINE Int simplex_down_template(Int elem_dim, Int bdry_dim, Int which_bdry, Int which_vert)
Relates bounding simplex vertices to the parent simplex's vertices.
Definition: Omega_h_simplex.hpp:23
Definition: Omega_h_shape.hpp:147
Definition: Omega_h_shape.hpp:28
Real d
Definition: Omega_h_shape.hpp:30
Vector< dim > n
Definition: Omega_h_shape.hpp:29
Definition: Omega_h_shape.hpp:137
Definition: Omega_h_shape.hpp:172
Definition: Omega_h_shape.hpp:22